< prev index next >

src/hotspot/os/windows/os_perf_windows.cpp

Print this page
rev 50222 : 8203321: assert(current_query_index < process_query_set->size) failed: invariant
Reviewed-by:


 101 
 102 typedef struct {
 103   UpdateQueryS query;
 104   HCOUNTER     counter;
 105   bool         initialized;
 106 } CounterQueryS, *CounterQueryP;
 107 
 108 typedef struct {
 109   UpdateQueryS query;
 110   HCOUNTER*    counters;
 111   int          noOfCounters;
 112   bool         initialized;
 113 } MultiCounterQueryS, *MultiCounterQueryP;
 114 
 115 typedef struct {
 116   MultiCounterQueryP queries;
 117   int                size;
 118   bool               initialized;
 119 } MultiCounterQuerySetS, *MultiCounterQuerySetP;
 120 





 121 static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
 122   if (counter != NULL && *counter != NULL) {
 123     PdhDll::PdhRemoveCounter(*counter);
 124     *counter = NULL;
 125   }
 126   if (query != NULL && *query != NULL) {
 127     PdhDll::PdhCloseQuery(*query);
 128     *query = NULL;
 129   }
 130 }
 131 
 132 static CounterQueryP create_counter_query() {
 133   CounterQueryP const query = NEW_C_HEAP_ARRAY(CounterQueryS, 1, mtInternal);
 134   memset(query, 0, sizeof(CounterQueryS));
 135   return query;
 136 }
 137 
 138 static void destroy_counter_query(CounterQueryP query) {
 139   assert(query != NULL, "invariant");
 140   pdh_cleanup(&query->query.query, &query->counter);
 141   FREE_C_HEAP_ARRAY(CounterQueryS, query);
 142 }
 143 
 144 static MultiCounterQueryP create_multi_counter_query() {
 145   MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);
 146   memset(query, 0, sizeof(MultiCounterQueryS));
 147   return query;
 148 }
 149 
 150 static void destroy_counter_query(MultiCounterQueryP counter_query) {
 151   if (counter_query != NULL) {
 152     for (int i = 0; i < counter_query->noOfCounters; ++i) {
 153       pdh_cleanup(NULL, &counter_query->counters[i]);
 154     }
 155     FREE_C_HEAP_ARRAY(char, counter_query->counters);
 156     pdh_cleanup(&counter_query->query.query, NULL);
 157     FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query);
 158   }
 159 }
 160 
 161 static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
 162   for (int i = 0; i < counter_query_set->size; i++) {
 163     for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
 164       pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
 165     }
 166     FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters);
 167     pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
 168   }
 169   FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries);




 170   FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
 171 }
 172 





 173 static int open_query(HQUERY* query) {
 174   return PdhDll::PdhOpenQuery(NULL, 0, query);
 175 }
 176 
 177 template <typename QueryP>
 178 static int open_query(QueryP query) {
 179   return open_query(&query->query);
 180 }
 181 
 182 static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) {
 183   assert(query != NULL, "invariant");
 184   assert(!query->initialized, "invariant");
 185   assert(0 == query->noOfCounters, "invariant");
 186   assert(query->counters == NULL, "invariant");
 187   query->counters = (HCOUNTER*)NEW_C_HEAP_ARRAY(char, nofCounters * sizeof(HCOUNTER), mtInternal);
 188   if (query->counters == NULL) {
 189     return OS_ERR;
 190   }
 191   memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));
 192   query->noOfCounters = (int)nofCounters;
 193   return OS_OK;
 194 }
 195 
 196 static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {
 197   assert(query_set != NULL, "invariant");
 198   assert(!query_set->initialized, "invariant");
 199   for (int i = 0; i < query_set->size; ++i) {
 200     if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) {
 201       return OS_ERR;
 202     }
 203   }
 204   return OS_OK;
 205 }
 206 





 207 static void deallocate_counters(MultiCounterQueryP query) {
 208   if (query->counters != NULL) {
 209     FREE_C_HEAP_ARRAY(char, query->counters);
 210     query->counters = NULL;
 211     query->noOfCounters = 0;
 212   }
 213 }
 214 
 215 static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 216   assert(query != NULL, "invariant");
 217   assert(counter != NULL, "invariant");
 218   assert(path != NULL, "invariant");
 219   if (query->query == NULL) {
 220     if (open_query(query) != ERROR_SUCCESS) {
 221       return OS_ERR;
 222     }
 223   }
 224   assert(query->query != NULL, "invariant");
 225   PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);
 226   if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {


 245 
 246 template <typename QueryP>
 247 static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 248   assert(counter_query != NULL, "invariant");
 249   assert(counter != NULL, "invariant");
 250   assert(path != NULL, "invariant");
 251   return add_counter(&counter_query->query, counter, path, first_sample_on_init);
 252 }
 253 
 254 static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {
 255   if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {
 256     // performance counter might be disabled in the registry
 257     return OS_ERR;
 258   }
 259   counter_query->initialized = true;
 260   return OS_OK;
 261 }
 262 
 263 static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
 264   assert(query != NULL, "invariant");
 265   assert(query != NULL, "invariant");
 266   assert(slot_index < query->noOfCounters, "invariant");
 267   assert(query->counters[slot_index] == NULL, "invariant");
 268   const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
 269   if (OS_OK == ret) {
 270     if (slot_index + 1 == query->noOfCounters) {
 271       query->initialized = true;
 272     }
 273   }
 274   return ret;
 275 }
 276 
 277 static int collect_query_data(UpdateQueryP update_query) {
 278   assert(update_query != NULL, "invariant");
 279   const s8 now = os::javaTimeMillis();
 280   if (now - update_query->lastUpdate > min_update_interval_millis) {
 281     if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {
 282       return OS_ERR;
 283     }
 284     update_query->lastUpdate = now;
 285   }


 309 * The really bad part is that this list is reset as soon as a process exits:
 310 * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
 311 *
 312 * The PDH api requires a process identifier to be submitted when registering
 313 * a query, but as soon as the list resets, the query is invalidated (since the name changed).
 314 *
 315 * Solution:
 316 * The #number identifier for a Process query can only decrease after process creation.
 317 *
 318 * We therefore create an array of counter queries for all process object instances
 319 * up to and including ourselves:
 320 *
 321 * Ex. we come in as third process instance (java#2), we then create and register
 322 * queries for the following Process object instances:
 323 * java#0, java#1, java#2
 324 *
 325 * current_query_index_for_process() keeps track of the current "correct" query
 326 * (in order to keep this index valid when the list resets from underneath,
 327 * ensure to call current_query_index_for_process() before every query involving
 328 * Process object instance data).


 329 */
 330 static int current_query_index_for_process() {
 331   assert(process_image_name != NULL, "invariant");
 332   assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
 333   HQUERY tmpQuery = NULL;
 334   if (open_query(&tmpQuery) != ERROR_SUCCESS) {
 335     return 0;
 336   }
 337   char counter[512];
 338   HCOUNTER handle_counter = NULL;
 339   // iterate over all instance indexes and try to find our own pid
 340   for (int index = 0; index < max_intx; index++) {
 341     jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);
 342     assert(strlen(counter) < sizeof(counter), "invariant");
 343     if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
 344       pdh_cleanup(&tmpQuery, &handle_counter);
 345       return 0;
 346     }
 347     const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
 348     if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
 349       pdh_cleanup(&tmpQuery, &handle_counter);
 350       return 0;
 351     } else {
 352       PDH_FMT_COUNTERVALUE counter_value;
 353       formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
 354       pdh_cleanup(NULL, &handle_counter);
 355       if ((LONG)os::current_process_id() == counter_value.longValue) {
 356         pdh_cleanup(&tmpQuery, NULL);
 357         return index;
 358       }
 359     }
 360   }
 361   pdh_cleanup(&tmpQuery, NULL);
 362   return 0;
 363 }
 364 
 365 static MultiCounterQuerySetP create_process_counter_query() {
 366   MultiCounterQuerySetP const query = NEW_C_HEAP_ARRAY(MultiCounterQuerySetS, 1, mtInternal);
 367   memset(query, 0, sizeof(MultiCounterQuerySetS));
 368   const int current_process_idx = current_query_index_for_process();
 369   query->queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
 370   memset(query->queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
 371   query->size = current_process_idx + 1;
 372   return query;
 373 }
 374 
 375 static MultiCounterQueryP current_process_counter_query(MultiCounterQuerySetP process_query_set) {
 376   assert(process_query_set != NULL, "invariant");
 377   const int current_query_index = current_query_index_for_process();
 378   assert(current_query_index < process_query_set->size, "invariant");
 379   return &process_query_set->queries[current_query_index];












 380 }
 381 
 382 static void clear_multi_counter(MultiCounterQueryP query) {
 383   for (int i = 0; i < query->noOfCounters; ++i) {
 384     pdh_cleanup(NULL, &query->counters[i]);
 385   }
 386   pdh_cleanup(&query->query.query, NULL);

 387 }
 388 
 389 static int collect_process_query_data(MultiCounterQuerySetP counter_query_set) {





 390   const int current_process_idx = current_query_index_for_process();
 391   while (current_process_idx < counter_query_set->size - 1) {
 392     const int new_size = --counter_query_set->size;
 393     clear_multi_counter(&counter_query_set->queries[new_size]);
 394   }
 395   return collect_query_data(&counter_query_set->queries[current_process_idx]);
















 396 }
 397 
 398 static int query_process_counter(MultiCounterQuerySetP process_query_set, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
 399   MultiCounterQueryP const current_query = current_process_counter_query(process_query_set);





 400   assert(current_query != NULL, "invariant");
 401   assert(slot_index < current_query->noOfCounters, "invariant");
 402   assert(current_query->counters[slot_index] != NULL, "invariant");
 403   return formatted_counter_value(current_query->counters[slot_index], format, value);
 404 }
 405 
 406 /*
 407  * Construct a fully qualified PDH path
 408  *
 409  * @param objectName   a PDH Object string representation(required)
 410  * @param counterName  a PDH Counter string representation(required)
 411  * @param imageName    a process image name string, ex. "java" (opt)
 412  * @param instance     an instance string, ex. "0", "1", ... (opt)
 413  * @return             the fully qualified PDH path.
 414  *
 415  * Caller will need a ResourceMark.
 416  *
 417  * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)
 418  */
 419 static const char* make_fully_qualified_counter_path(const char* object_name,


 793   cpu_query->initialized = true;
 794   // Query once to initialize the counters which require at least two samples
 795   // (like the % CPU usage) to calculate correctly.
 796   collect_query_data(cpu_query);
 797   return OS_OK;
 798 }
 799 
 800 static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
 801   assert(cpu_query != NULL, "invariant");
 802   assert(!cpu_query->initialized, "invariant");
 803   const int logical_cpu_count = number_of_logical_cpus();
 804   assert(logical_cpu_count >= os::processor_count(), "invariant");
 805   // we also add another counter for instance "_Total"
 806   if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) {
 807     return OS_ERR;
 808   }
 809   assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");
 810   return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
 811 }
 812 
 813 static int initialize_process_counter(MultiCounterQuerySetP query_set, int slot_index, DWORD pdh_counter_index) {
 814   char* localized_process_object;
 815   if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
 816     return OS_ERR;
 817   }
 818   assert(localized_process_object != NULL, "invariant");
 819   char* localized_counter_name;
 820   if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) {
 821     return OS_ERR;
 822   }
 823   assert(localized_counter_name != NULL, "invariant");
 824   for (int i = 0; i < query_set->size; ++i) {
 825     char instanceIndexBuffer[32];
 826     const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
 827                                                                  localized_counter_name,
 828                                                                  process_image_name,
 829                                                                  itoa(i, instanceIndexBuffer, 10));
 830     if (counter_path == NULL) {
 831       return OS_ERR;
 832     }
 833     MultiCounterQueryP const query = &query_set->queries[i];
 834     if (add_process_counter(query, slot_index, counter_path, true)) {
 835       return OS_ERR;
 836     }
 837   }
 838   return OS_OK;
 839 }
 840 
 841 static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
 842   assert(is_valid_pdh_index(pdh_object_idx), "invariant");
 843   assert(is_valid_pdh_index(pdh_counter_idx), "invariant");
 844   CounterQueryP const query = create_counter_query();
 845   const char* object = pdh_localized_artifact(pdh_object_idx);
 846   assert(object != NULL, "invariant");
 847   const char* counter = pdh_localized_artifact(pdh_counter_idx);
 848   assert(counter != NULL, "invariant");
 849   const char* full_counter_path = make_fully_qualified_counter_path(object, counter);
 850   assert(full_counter_path != NULL, "invariant");
 851   add_counter(query, full_counter_path, true);
 852   return query;
 853 }


 900     pdh_initialized = true;
 901   }
 902   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 903   return ret == OS_OK;
 904 }
 905 
 906 static void pdh_release() {
 907   while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
 908   const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);
 909   if (1 == prev_ref_count) {
 910     deallocate();
 911     pdh_initialized = false;
 912   }
 913   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 914 }
 915 
 916 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
 917   friend class CPUPerformanceInterface;
 918  private:
 919   CounterQueryP _context_switches;
 920   MultiCounterQuerySetP _process_cpu_load;
 921   MultiCounterQueryP _machine_cpu_load;
 922 
 923   int cpu_load(int which_logical_cpu, double* cpu_load);
 924   int context_switch_rate(double* rate);
 925   int cpu_load_total_process(double* cpu_load);
 926   int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad);
 927   CPUPerformance();
 928   ~CPUPerformance();
 929   bool initialize();
 930 };
 931 
 932 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
 933   friend class SystemProcessInterface;
 934  private:
 935   class ProcessIterator : public CHeapObj<mtInternal> {
 936     friend class SystemProcessInterface::SystemProcesses;
 937    private:
 938     HANDLE         _hProcessSnap;
 939     PROCESSENTRY32 _pe32;
 940     BOOL           _valid;


 952 
 953   ProcessIterator* _iterator;
 954   SystemProcesses();
 955   ~SystemProcesses();
 956   bool initialize();
 957 
 958   // information about system processes
 959   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
 960 };
 961 
 962 CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
 963 
 964 bool CPUPerformanceInterface::CPUPerformance::initialize() {
 965   if (!pdh_acquire()) {
 966     return false;
 967   }
 968   _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
 969   if (_context_switches == NULL) {
 970     return false;
 971   }
 972   _process_cpu_load = create_process_counter_query();
 973   if (_process_cpu_load == NULL) {
 974     return false;
 975   }
 976   if (allocate_counters(_process_cpu_load, 2) != OS_OK) {
 977     return false;
 978   }
 979   if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
 980     return false;
 981   }
 982   if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
 983     return false;
 984   }
 985   _process_cpu_load->initialized = true;
 986 
 987   _machine_cpu_load = create_multi_counter_query();
 988   if (_machine_cpu_load == NULL) {
 989     return false;
 990   }
 991   if (initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
 992     return false;
 993   }
 994   return true;
 995 }
 996 
 997 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
 998   if (_context_switches != NULL) {
 999     destroy_counter_query(_context_switches);
1000     _context_switches = NULL;
1001   }
1002   if (_process_cpu_load != NULL) {
1003     destroy_counter_query(_process_cpu_load);
1004     _process_cpu_load = NULL;
1005   }


1047   assert(_machine_cpu_load != NULL, "invariant");
1048   assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
1049   *cpu_load = .0;
1050   if (!_machine_cpu_load->initialized) {
1051     return OS_ERR;
1052   }
1053   if (collect_query_data(_machine_cpu_load)) {
1054     return OS_ERR;
1055   }
1056   // -1 is total (all cpus)
1057   const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;
1058   PDH_FMT_COUNTERVALUE counter_value;
1059   formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);
1060   *cpu_load = counter_value.doubleValue / 100;
1061   return OS_OK;
1062 }
1063 
1064 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
1065   assert(_process_cpu_load != NULL, "invariant");
1066   *cpu_load = .0;
1067   if (!_process_cpu_load->initialized) {
1068     return OS_ERR;
1069   }
1070   if (collect_process_query_data(_process_cpu_load)) {
1071     return OS_ERR;
1072   }
1073   PDH_FMT_COUNTERVALUE counter_value;
1074   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1075     return OS_ERR;
1076   }
1077   double process_load = counter_value.doubleValue / cpu_factor();
1078   process_load = MIN2<double>(1, process_load);
1079   process_load = MAX2<double>(0, process_load);
1080   *cpu_load = process_load;
1081   return OS_OK;
1082 }
1083 
1084 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad,
1085                                                                double* pjvmKernelLoad,
1086                                                                double* psystemTotalLoad) {
1087   assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");
1088   assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");
1089   assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");
1090   *pjvmUserLoad = .0;
1091   *pjvmKernelLoad = .0;
1092   *psystemTotalLoad = .0;
1093   if (!_process_cpu_load->initialized) {
1094     return OS_ERR;
1095   }
1096   if (collect_process_query_data(_process_cpu_load)) {
1097     return OS_ERR;
1098   }
1099   double process_load = .0;
1100   PDH_FMT_COUNTERVALUE counter_value;
1101   // Read  PDH_PROCESSOR_TIME_IDX
1102   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1103     return OS_ERR;
1104   }
1105   process_load = counter_value.doubleValue / cpu_factor();
1106   process_load = MIN2<double>(1, process_load);
1107   process_load = MAX2<double>(0, process_load);
1108   // Read PDH_PRIV_PROCESSOR_TIME_IDX
1109   if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1110     return OS_ERR;
1111   }
1112   double kernel_load = counter_value.doubleValue / cpu_factor();
1113   kernel_load = MIN2<double>(1, kernel_load);




 101 
 102 typedef struct {
 103   UpdateQueryS query;
 104   HCOUNTER     counter;
 105   bool         initialized;
 106 } CounterQueryS, *CounterQueryP;
 107 
 108 typedef struct {
 109   UpdateQueryS query;
 110   HCOUNTER*    counters;
 111   int          noOfCounters;
 112   bool         initialized;
 113 } MultiCounterQueryS, *MultiCounterQueryP;
 114 
 115 typedef struct {
 116   MultiCounterQueryP queries;
 117   int                size;
 118   bool               initialized;
 119 } MultiCounterQuerySetS, *MultiCounterQuerySetP;
 120 
 121 typedef struct {
 122   MultiCounterQuerySetS set;
 123   int                   process_index;
 124 } ProcessQueryS, *ProcessQueryP;
 125 
 126 static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
 127   if (counter != NULL && *counter != NULL) {
 128     PdhDll::PdhRemoveCounter(*counter);
 129     *counter = NULL;
 130   }
 131   if (query != NULL && *query != NULL) {
 132     PdhDll::PdhCloseQuery(*query);
 133     *query = NULL;
 134   }
 135 }
 136 
 137 static CounterQueryP create_counter_query() {
 138   CounterQueryP const query = NEW_C_HEAP_ARRAY(CounterQueryS, 1, mtInternal);
 139   memset(query, 0, sizeof(CounterQueryS));
 140   return query;
 141 }
 142 
 143 static void destroy_counter_query(CounterQueryP query) {
 144   assert(query != NULL, "invariant");
 145   pdh_cleanup(&query->query.query, &query->counter);
 146   FREE_C_HEAP_ARRAY(CounterQueryS, query);
 147 }
 148 
 149 static MultiCounterQueryP create_multi_counter_query() {
 150   MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);
 151   memset(query, 0, sizeof(MultiCounterQueryS));
 152   return query;
 153 }
 154 
 155 static void destroy_counter_query(MultiCounterQueryP counter_query) {
 156   if (counter_query != NULL) {
 157     for (int i = 0; i < counter_query->noOfCounters; ++i) {
 158       pdh_cleanup(NULL, &counter_query->counters[i]);
 159     }
 160     FREE_C_HEAP_ARRAY(char, counter_query->counters);
 161     pdh_cleanup(&counter_query->query.query, NULL);
 162     FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query);
 163   }
 164 }
 165 
 166 static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) {
 167   for (int i = 0; i < counter_query_set->size; i++) {
 168     for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
 169       pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
 170     }
 171     FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters);
 172     pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
 173   }
 174   FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries);
 175 }
 176 
 177 static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
 178   destroy_multi_counter_query(counter_query_set);
 179   FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
 180 }
 181 
 182 static void destroy_counter_query(ProcessQueryP process_query) {
 183   destroy_multi_counter_query(&process_query->set);
 184   FREE_C_HEAP_ARRAY(ProcessQueryS, process_query);
 185 }
 186 
 187 static int open_query(HQUERY* query) {
 188   return PdhDll::PdhOpenQuery(NULL, 0, query);
 189 }
 190 
 191 template <typename QueryP>
 192 static int open_query(QueryP query) {
 193   return open_query(&query->query);
 194 }
 195 
 196 static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) {
 197   assert(query != NULL, "invariant");
 198   assert(!query->initialized, "invariant");
 199   assert(0 == query->noOfCounters, "invariant");
 200   assert(query->counters == NULL, "invariant");
 201   query->counters = (HCOUNTER*)NEW_C_HEAP_ARRAY(char, nofCounters * sizeof(HCOUNTER), mtInternal);
 202   if (query->counters == NULL) {
 203     return OS_ERR;
 204   }
 205   memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));
 206   query->noOfCounters = (int)nofCounters;
 207   return OS_OK;
 208 }
 209 
 210 static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {
 211   assert(query_set != NULL, "invariant");
 212   assert(!query_set->initialized, "invariant");
 213   for (int i = 0; i < query_set->size; ++i) {
 214     if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) {
 215       return OS_ERR;
 216     }
 217   }
 218   return OS_OK;
 219 }
 220 
 221 static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) {
 222   assert(process_query != NULL, "invariant");
 223   return allocate_counters(&process_query->set, nofCounters);
 224 }
 225 
 226 static void deallocate_counters(MultiCounterQueryP query) {
 227   if (query->counters != NULL) {
 228     FREE_C_HEAP_ARRAY(char, query->counters);
 229     query->counters = NULL;
 230     query->noOfCounters = 0;
 231   }
 232 }
 233 
 234 static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 235   assert(query != NULL, "invariant");
 236   assert(counter != NULL, "invariant");
 237   assert(path != NULL, "invariant");
 238   if (query->query == NULL) {
 239     if (open_query(query) != ERROR_SUCCESS) {
 240       return OS_ERR;
 241     }
 242   }
 243   assert(query->query != NULL, "invariant");
 244   PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);
 245   if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {


 264 
 265 template <typename QueryP>
 266 static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 267   assert(counter_query != NULL, "invariant");
 268   assert(counter != NULL, "invariant");
 269   assert(path != NULL, "invariant");
 270   return add_counter(&counter_query->query, counter, path, first_sample_on_init);
 271 }
 272 
 273 static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {
 274   if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {
 275     // performance counter might be disabled in the registry
 276     return OS_ERR;
 277   }
 278   counter_query->initialized = true;
 279   return OS_OK;
 280 }
 281 
 282 static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
 283   assert(query != NULL, "invariant");

 284   assert(slot_index < query->noOfCounters, "invariant");
 285   assert(query->counters[slot_index] == NULL, "invariant");
 286   const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
 287   if (OS_OK == ret) {
 288     if (slot_index + 1 == query->noOfCounters) {
 289       query->initialized = true;
 290     }
 291   }
 292   return ret;
 293 }
 294 
 295 static int collect_query_data(UpdateQueryP update_query) {
 296   assert(update_query != NULL, "invariant");
 297   const s8 now = os::javaTimeMillis();
 298   if (now - update_query->lastUpdate > min_update_interval_millis) {
 299     if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {
 300       return OS_ERR;
 301     }
 302     update_query->lastUpdate = now;
 303   }


 327 * The really bad part is that this list is reset as soon as a process exits:
 328 * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
 329 *
 330 * The PDH api requires a process identifier to be submitted when registering
 331 * a query, but as soon as the list resets, the query is invalidated (since the name changed).
 332 *
 333 * Solution:
 334 * The #number identifier for a Process query can only decrease after process creation.
 335 *
 336 * We therefore create an array of counter queries for all process object instances
 337 * up to and including ourselves:
 338 *
 339 * Ex. we come in as third process instance (java#2), we then create and register
 340 * queries for the following Process object instances:
 341 * java#0, java#1, java#2
 342 *
 343 * current_query_index_for_process() keeps track of the current "correct" query
 344 * (in order to keep this index valid when the list resets from underneath,
 345 * ensure to call current_query_index_for_process() before every query involving
 346 * Process object instance data).
 347 *
 348 * if unable to query, returns OS_ERR(-1)
 349 */
 350 static int current_query_index_for_process() {
 351   assert(process_image_name != NULL, "invariant");
 352   assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
 353   HQUERY tmpQuery = NULL;
 354   if (open_query(&tmpQuery) != ERROR_SUCCESS) {
 355     return OS_ERR;
 356   }
 357   char counter[512];
 358   HCOUNTER handle_counter = NULL;
 359   // iterate over all instance indexes and try to find our own pid
 360   for (int index = 0; index < max_intx; index++) {
 361     jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);
 362     assert(strlen(counter) < sizeof(counter), "invariant");
 363     if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
 364       pdh_cleanup(&tmpQuery, &handle_counter);
 365       return OS_ERR;
 366     }
 367     const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
 368     if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
 369       pdh_cleanup(&tmpQuery, &handle_counter);
 370       return OS_ERR;
 371     } else {
 372       PDH_FMT_COUNTERVALUE counter_value;
 373       formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
 374       pdh_cleanup(NULL, &handle_counter);
 375       if ((LONG)os::current_process_id() == counter_value.longValue) {
 376         pdh_cleanup(&tmpQuery, NULL);
 377         return index;
 378       }
 379     }
 380   }
 381   pdh_cleanup(&tmpQuery, NULL);
 382   return OS_ERR;










 383 }
 384 
 385 static ProcessQueryP create_process_query() {
 386   ProcessQueryP const process_query = NEW_C_HEAP_ARRAY(ProcessQueryS, 1, mtInternal);
 387   memset(process_query, 0, sizeof(ProcessQueryS));
 388   const int process_index = current_query_index_for_process();
 389   const int current_process_idx = (OS_ERR == process_index) ? 0 : process_index;
 390   process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
 391   memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
 392   process_query->process_index = current_process_idx;
 393   process_query->set.size = current_process_idx + 1;
 394   assert(process_query->set.size > process_query->process_index, "invariant");
 395   return process_query;
 396 }
 397 
 398 static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) {
 399   assert(process_query != NULL, "invariant");
 400   assert(process_query->process_index < process_query->set.size, "invariant");
 401   return &process_query->set.queries[process_query->process_index];
 402 }
 403 
 404 static void clear_multi_counter(MultiCounterQueryP query) {
 405   for (int i = 0; i < query->noOfCounters; ++i) {
 406     pdh_cleanup(NULL, &query->counters[i]);
 407   }
 408   pdh_cleanup(&query->query.query, NULL);
 409   query->initialized = false;
 410 }
 411 
 412 static int ensure_valid_process_query_index(ProcessQueryP process_query) {
 413   assert(process_query != NULL, "invariant");
 414   const int previous_process_idx = process_query->process_index;
 415   if (previous_process_idx == 0) {
 416     return previous_process_idx;
 417   }
 418   const int current_process_idx = current_query_index_for_process();
 419   if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx ||
 420     current_process_idx >= process_query->set.size) {
 421     return previous_process_idx;
 422   }
 423 
 424   assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!");
 425   while (current_process_idx < process_query->set.size - 1) {
 426     const int new_size = --process_query->set.size;
 427     clear_multi_counter(&process_query->set.queries[new_size]);
 428   }
 429   assert(current_process_idx < process_query->set.size, "invariant");
 430   process_query->process_index = current_process_idx;
 431   return current_process_idx;
 432 }
 433 
 434 static MultiCounterQueryP current_process_query(ProcessQueryP process_query) {
 435   assert(process_query != NULL, "invariant");
 436   const int current_process_idx = ensure_valid_process_query_index(process_query);
 437   assert(current_process_idx == process_query->process_index, "invariant");
 438   assert(current_process_idx < process_query->set.size, "invariant");
 439   return &process_query->set.queries[current_process_idx];
 440 }
 441 
 442 static int collect_process_query_data(ProcessQueryP process_query) {
 443   assert(process_query != NULL, "invariant");
 444   return collect_query_data(current_process_query(process_query));
 445 }
 446 
 447 static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
 448   MultiCounterQueryP const current_query = current_process_counter_query(process_query);
 449   assert(current_query != NULL, "invariant");
 450   assert(slot_index < current_query->noOfCounters, "invariant");
 451   assert(current_query->counters[slot_index] != NULL, "invariant");
 452   return formatted_counter_value(current_query->counters[slot_index], format, value);
 453 }
 454 
 455 /*
 456  * Construct a fully qualified PDH path
 457  *
 458  * @param objectName   a PDH Object string representation(required)
 459  * @param counterName  a PDH Counter string representation(required)
 460  * @param imageName    a process image name string, ex. "java" (opt)
 461  * @param instance     an instance string, ex. "0", "1", ... (opt)
 462  * @return             the fully qualified PDH path.
 463  *
 464  * Caller will need a ResourceMark.
 465  *
 466  * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)
 467  */
 468 static const char* make_fully_qualified_counter_path(const char* object_name,


 842   cpu_query->initialized = true;
 843   // Query once to initialize the counters which require at least two samples
 844   // (like the % CPU usage) to calculate correctly.
 845   collect_query_data(cpu_query);
 846   return OS_OK;
 847 }
 848 
 849 static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
 850   assert(cpu_query != NULL, "invariant");
 851   assert(!cpu_query->initialized, "invariant");
 852   const int logical_cpu_count = number_of_logical_cpus();
 853   assert(logical_cpu_count >= os::processor_count(), "invariant");
 854   // we also add another counter for instance "_Total"
 855   if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) {
 856     return OS_ERR;
 857   }
 858   assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");
 859   return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
 860 }
 861 
 862 static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) {
 863   char* localized_process_object;
 864   if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
 865     return OS_ERR;
 866   }
 867   assert(localized_process_object != NULL, "invariant");
 868   char* localized_counter_name;
 869   if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) {
 870     return OS_ERR;
 871   }
 872   assert(localized_counter_name != NULL, "invariant");
 873   for (int i = 0; i < process_query->set.size; ++i) {
 874     char instanceIndexBuffer[32];
 875     const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
 876                                                                  localized_counter_name,
 877                                                                  process_image_name,
 878                                                                  itoa(i, instanceIndexBuffer, 10));
 879     if (counter_path == NULL) {
 880       return OS_ERR;
 881     }
 882     MultiCounterQueryP const query = &process_query->set.queries[i];
 883     if (add_process_counter(query, slot_index, counter_path, true)) {
 884       return OS_ERR;
 885     }
 886   }
 887   return OS_OK;
 888 }
 889 
 890 static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
 891   assert(is_valid_pdh_index(pdh_object_idx), "invariant");
 892   assert(is_valid_pdh_index(pdh_counter_idx), "invariant");
 893   CounterQueryP const query = create_counter_query();
 894   const char* object = pdh_localized_artifact(pdh_object_idx);
 895   assert(object != NULL, "invariant");
 896   const char* counter = pdh_localized_artifact(pdh_counter_idx);
 897   assert(counter != NULL, "invariant");
 898   const char* full_counter_path = make_fully_qualified_counter_path(object, counter);
 899   assert(full_counter_path != NULL, "invariant");
 900   add_counter(query, full_counter_path, true);
 901   return query;
 902 }


 949     pdh_initialized = true;
 950   }
 951   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 952   return ret == OS_OK;
 953 }
 954 
 955 static void pdh_release() {
 956   while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
 957   const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);
 958   if (1 == prev_ref_count) {
 959     deallocate();
 960     pdh_initialized = false;
 961   }
 962   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 963 }
 964 
 965 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
 966   friend class CPUPerformanceInterface;
 967  private:
 968   CounterQueryP _context_switches;
 969   ProcessQueryP _process_cpu_load;
 970   MultiCounterQueryP _machine_cpu_load;
 971 
 972   int cpu_load(int which_logical_cpu, double* cpu_load);
 973   int context_switch_rate(double* rate);
 974   int cpu_load_total_process(double* cpu_load);
 975   int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad);
 976   CPUPerformance();
 977   ~CPUPerformance();
 978   bool initialize();
 979 };
 980 
 981 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
 982   friend class SystemProcessInterface;
 983  private:
 984   class ProcessIterator : public CHeapObj<mtInternal> {
 985     friend class SystemProcessInterface::SystemProcesses;
 986    private:
 987     HANDLE         _hProcessSnap;
 988     PROCESSENTRY32 _pe32;
 989     BOOL           _valid;


1001 
1002   ProcessIterator* _iterator;
1003   SystemProcesses();
1004   ~SystemProcesses();
1005   bool initialize();
1006 
1007   // information about system processes
1008   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
1009 };
1010 
1011 CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
1012 
1013 bool CPUPerformanceInterface::CPUPerformance::initialize() {
1014   if (!pdh_acquire()) {
1015     return false;
1016   }
1017   _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
1018   if (_context_switches == NULL) {
1019     return false;
1020   }
1021   _process_cpu_load = create_process_query();
1022   if (_process_cpu_load == NULL) {
1023     return false;
1024   }
1025   if (allocate_counters(_process_cpu_load, 2) != OS_OK) {
1026     return false;
1027   }
1028   if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
1029     return false;
1030   }
1031   if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
1032     return false;
1033   }
1034   _process_cpu_load->set.initialized = true;
1035 
1036   _machine_cpu_load = create_multi_counter_query();
1037   if (_machine_cpu_load == NULL) {
1038     return false;
1039   }
1040   if (initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
1041     return false;
1042   }
1043   return true;
1044 }
1045 
1046 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
1047   if (_context_switches != NULL) {
1048     destroy_counter_query(_context_switches);
1049     _context_switches = NULL;
1050   }
1051   if (_process_cpu_load != NULL) {
1052     destroy_counter_query(_process_cpu_load);
1053     _process_cpu_load = NULL;
1054   }


1096   assert(_machine_cpu_load != NULL, "invariant");
1097   assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
1098   *cpu_load = .0;
1099   if (!_machine_cpu_load->initialized) {
1100     return OS_ERR;
1101   }
1102   if (collect_query_data(_machine_cpu_load)) {
1103     return OS_ERR;
1104   }
1105   // -1 is total (all cpus)
1106   const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;
1107   PDH_FMT_COUNTERVALUE counter_value;
1108   formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);
1109   *cpu_load = counter_value.doubleValue / 100;
1110   return OS_OK;
1111 }
1112 
1113 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
1114   assert(_process_cpu_load != NULL, "invariant");
1115   *cpu_load = .0;
1116   if (!_process_cpu_load->set.initialized) {
1117     return OS_ERR;
1118   }
1119   if (collect_process_query_data(_process_cpu_load)) {
1120     return OS_ERR;
1121   }
1122   PDH_FMT_COUNTERVALUE counter_value;
1123   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1124     return OS_ERR;
1125   }
1126   double process_load = counter_value.doubleValue / cpu_factor();
1127   process_load = MIN2<double>(1, process_load);
1128   process_load = MAX2<double>(0, process_load);
1129   *cpu_load = process_load;
1130   return OS_OK;
1131 }
1132 
1133 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad,
1134                                                                double* pjvmKernelLoad,
1135                                                                double* psystemTotalLoad) {
1136   assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");
1137   assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");
1138   assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");
1139   *pjvmUserLoad = .0;
1140   *pjvmKernelLoad = .0;
1141   *psystemTotalLoad = .0;
1142   if (!_process_cpu_load->set.initialized) {
1143     return OS_ERR;
1144   }
1145   if (collect_process_query_data(_process_cpu_load)) {
1146     return OS_ERR;
1147   }
1148   double process_load = .0;
1149   PDH_FMT_COUNTERVALUE counter_value;
1150   // Read  PDH_PROCESSOR_TIME_IDX
1151   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1152     return OS_ERR;
1153   }
1154   process_load = counter_value.doubleValue / cpu_factor();
1155   process_load = MIN2<double>(1, process_load);
1156   process_load = MAX2<double>(0, process_load);
1157   // Read PDH_PRIV_PROCESSOR_TIME_IDX
1158   if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1159     return OS_ERR;
1160   }
1161   double kernel_load = counter_value.doubleValue / cpu_factor();
1162   kernel_load = MIN2<double>(1, kernel_load);


< prev index next >