1 /* 2 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "iphlp_interface.hpp" 27 #include "logging/log.hpp" 28 #include "memory/allocation.inline.hpp" 29 #include "memory/resourceArea.hpp" 30 #include "pdh_interface.hpp" 31 #include "runtime/os_perf.hpp" 32 #include "runtime/os.hpp" 33 #include "utilities/globalDefinitions.hpp" 34 #include "utilities/macros.hpp" 35 #include CPU_HEADER(vm_version_ext) 36 #include <math.h> 37 #include <psapi.h> 38 #include <TlHelp32.h> 39 40 /* 41 * Windows provides a vast plethora of performance objects and counters, 42 * consumption of which is assisted using the Performance Data Helper (PDH) interface. 43 * We import a selected few api entry points from PDH, see pdh_interface.hpp. 44 * 45 * The code located in this file is to a large extent an abstraction over much of the 46 * plumbing needed to start consuming an object and/or counter of choice. 47 * 48 */ 49 50 /* 51 * How to use: 52 * 1. Create query 53 * 2. Add counters to the query 54 * 3. Collect the performance data using the query 55 * 4. Display the performance data using the counters associated with the query 56 * 5. Destroy query (counter destruction implied) 57 */ 58 59 /* 60 * Every PDH artifact, like processor, process, thread, memory, and so forth are 61 * identified with an index that is always the same irrespective 62 * of the localized version of the operating system or service pack installed. 63 * INFO: Using PDH APIs Correctly in a Localized Language (Q287159) 64 * http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159 65 * 66 * To find the correct index for an object or counter, inspect the registry key / value: 67 * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter] 68 * 69 * some common PDH indexes 70 */ 71 static const DWORD PDH_PROCESSOR_IDX = 238; 72 static const DWORD PDH_PROCESSOR_TIME_IDX = 6; 73 static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144; 74 static const DWORD PDH_PROCESS_IDX = 230; 75 static const DWORD PDH_ID_PROCESS_IDX = 784; 76 static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146; 77 static const DWORD PDH_SYSTEM_IDX = 2; 78 79 /* useful pdh fmt's */ 80 static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s"; 81 static const size_t OBJECT_COUNTER_FMT_LEN = 2; 82 static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s"; 83 static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4; 84 static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s"; 85 static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5; 86 87 static const char* process_image_name = NULL; // for example, "java" but could have another image name 88 static char* pdh_IDProcess_counter_fmt = NULL; // "\Process(java#%d)\ID Process" */ 89 90 // Need to limit how often we update a query to minimize the heisenberg effect. 91 // (PDH behaves erratically if the counters are queried too often, especially counters that 92 // store and use values from two consecutive updates, like cpu load.) 93 static const int min_update_interval_millis = 500; 94 95 /* 96 * Structs for PDH queries. 97 */ 98 typedef struct { 99 HQUERY query; 100 s8 lastUpdate; // Last time query was updated (current millis). 101 } UpdateQueryS, *UpdateQueryP; 102 103 104 typedef struct { 105 UpdateQueryS query; 106 HCOUNTER counter; 107 bool initialized; 108 } CounterQueryS, *CounterQueryP; 109 110 typedef struct { 111 UpdateQueryS query; 112 HCOUNTER* counters; 113 int noOfCounters; 114 bool initialized; 115 } MultiCounterQueryS, *MultiCounterQueryP; 116 117 typedef struct { 118 MultiCounterQueryP queries; 119 int size; 120 bool initialized; 121 } MultiCounterQuerySetS, *MultiCounterQuerySetP; 122 123 typedef struct { 124 MultiCounterQuerySetS set; 125 int process_index; 126 } ProcessQueryS, *ProcessQueryP; 127 128 static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) { 129 if (counter != NULL && *counter != NULL) { 130 PdhDll::PdhRemoveCounter(*counter); 131 *counter = NULL; 132 } 133 if (query != NULL && *query != NULL) { 134 PdhDll::PdhCloseQuery(*query); 135 *query = NULL; 136 } 137 } 138 139 static CounterQueryP create_counter_query() { 140 CounterQueryP const query = NEW_C_HEAP_ARRAY(CounterQueryS, 1, mtInternal); 141 memset(query, 0, sizeof(CounterQueryS)); 142 return query; 143 } 144 145 static void destroy_counter_query(CounterQueryP query) { 146 assert(query != NULL, "invariant"); 147 pdh_cleanup(&query->query.query, &query->counter); 148 FREE_C_HEAP_ARRAY(CounterQueryS, query); 149 } 150 151 static MultiCounterQueryP create_multi_counter_query() { 152 MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal); 153 memset(query, 0, sizeof(MultiCounterQueryS)); 154 return query; 155 } 156 157 static void destroy_counter_query(MultiCounterQueryP counter_query) { 158 if (counter_query != NULL) { 159 for (int i = 0; i < counter_query->noOfCounters; ++i) { 160 pdh_cleanup(NULL, &counter_query->counters[i]); 161 } 162 FREE_C_HEAP_ARRAY(char, counter_query->counters); 163 pdh_cleanup(&counter_query->query.query, NULL); 164 FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query); 165 } 166 } 167 168 static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) { 169 for (int i = 0; i < counter_query_set->size; i++) { 170 for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) { 171 pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]); 172 } 173 FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters); 174 pdh_cleanup(&counter_query_set->queries[i].query.query, NULL); 175 } 176 FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries); 177 } 178 179 static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) { 180 destroy_multi_counter_query(counter_query_set); 181 FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set); 182 } 183 184 static void destroy_counter_query(ProcessQueryP process_query) { 185 destroy_multi_counter_query(&process_query->set); 186 FREE_C_HEAP_ARRAY(ProcessQueryS, process_query); 187 } 188 189 static int open_query(HQUERY* query) { 190 return PdhDll::PdhOpenQuery(NULL, 0, query); 191 } 192 193 template <typename QueryP> 194 static int open_query(QueryP query) { 195 return open_query(&query->query); 196 } 197 198 static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) { 199 assert(query != NULL, "invariant"); 200 assert(!query->initialized, "invariant"); 201 assert(0 == query->noOfCounters, "invariant"); 202 assert(query->counters == NULL, "invariant"); 203 query->counters = (HCOUNTER*)NEW_C_HEAP_ARRAY(char, nofCounters * sizeof(HCOUNTER), mtInternal); 204 if (query->counters == NULL) { 205 return OS_ERR; 206 } 207 memset(query->counters, 0, nofCounters * sizeof(HCOUNTER)); 208 query->noOfCounters = (int)nofCounters; 209 return OS_OK; 210 } 211 212 static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) { 213 assert(query_set != NULL, "invariant"); 214 assert(!query_set->initialized, "invariant"); 215 for (int i = 0; i < query_set->size; ++i) { 216 if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) { 217 return OS_ERR; 218 } 219 } 220 return OS_OK; 221 } 222 223 static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) { 224 assert(process_query != NULL, "invariant"); 225 return allocate_counters(&process_query->set, nofCounters); 226 } 227 228 static void deallocate_counters(MultiCounterQueryP query) { 229 if (query->counters != NULL) { 230 FREE_C_HEAP_ARRAY(char, query->counters); 231 query->counters = NULL; 232 query->noOfCounters = 0; 233 } 234 } 235 236 static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) { 237 assert(query != NULL, "invariant"); 238 assert(counter != NULL, "invariant"); 239 assert(path != NULL, "invariant"); 240 if (query->query == NULL) { 241 if (open_query(query) != ERROR_SUCCESS) { 242 return OS_ERR; 243 } 244 } 245 assert(query->query != NULL, "invariant"); 246 PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter); 247 if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) { 248 return OS_ERR; 249 } 250 /* 251 * According to the MSDN documentation, rate counters must be read twice: 252 * 253 * "Obtaining the value of rate counters such as Page faults/sec requires that 254 * PdhCollectQueryData be called twice, with a specific time interval between 255 * the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to 256 * implement the waiting period between the two calls to PdhCollectQueryData." 257 * 258 * Take the first sample here already to allow for the next "real" sample 259 * to succeed. 260 */ 261 if (first_sample_on_init) { 262 PdhDll::PdhCollectQueryData(query->query); 263 } 264 return OS_OK; 265 } 266 267 template <typename QueryP> 268 static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) { 269 assert(counter_query != NULL, "invariant"); 270 assert(counter != NULL, "invariant"); 271 assert(path != NULL, "invariant"); 272 return add_counter(&counter_query->query, counter, path, first_sample_on_init); 273 } 274 275 static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) { 276 if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) { 277 // performance counter might be disabled in the registry 278 return OS_ERR; 279 } 280 counter_query->initialized = true; 281 return OS_OK; 282 } 283 284 static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) { 285 assert(query != NULL, "invariant"); 286 assert(slot_index < query->noOfCounters, "invariant"); 287 assert(query->counters[slot_index] == NULL, "invariant"); 288 const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init); 289 if (OS_OK == ret) { 290 if (slot_index + 1 == query->noOfCounters) { 291 query->initialized = true; 292 } 293 } 294 return ret; 295 } 296 297 static int collect_query_data(UpdateQueryP update_query) { 298 assert(update_query != NULL, "invariant"); 299 const s8 now = os::javaTimeMillis(); 300 if (now - update_query->lastUpdate > min_update_interval_millis) { 301 if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) { 302 return OS_ERR; 303 } 304 update_query->lastUpdate = now; 305 } 306 return OS_OK; 307 } 308 309 template <typename Query> 310 static int collect_query_data(Query* counter_query) { 311 assert(counter_query != NULL, "invariant"); 312 return collect_query_data(&counter_query->query); 313 } 314 315 static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) { 316 assert(value != NULL, "invariant"); 317 if (PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS) { 318 return OS_ERR; 319 } 320 return OS_OK; 321 } 322 323 /* 324 * Working against the Process object and it's related counters is inherently problematic 325 * when using the PDH API: 326 * 327 * Using PDH, a process is not primarily identified by the process id, 328 * but with a sequential number, for example \Process(java#0), \Process(java#1), ... 329 * The really bad part is that this list is reset as soon as a process exits: 330 * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc. 331 * 332 * The PDH api requires a process identifier to be submitted when registering 333 * a query, but as soon as the list resets, the query is invalidated (since the name changed). 334 * 335 * Solution: 336 * The #number identifier for a Process query can only decrease after process creation. 337 * 338 * We therefore create an array of counter queries for all process object instances 339 * up to and including ourselves: 340 * 341 * Ex. we come in as third process instance (java#2), we then create and register 342 * queries for the following Process object instances: 343 * java#0, java#1, java#2 344 * 345 * current_query_index_for_process() keeps track of the current "correct" query 346 * (in order to keep this index valid when the list resets from underneath, 347 * ensure to call current_query_index_for_process() before every query involving 348 * Process object instance data). 349 * 350 * if unable to query, returns OS_ERR(-1) 351 */ 352 static int current_query_index_for_process() { 353 assert(process_image_name != NULL, "invariant"); 354 assert(pdh_IDProcess_counter_fmt != NULL, "invariant"); 355 HQUERY tmpQuery = NULL; 356 if (open_query(&tmpQuery) != ERROR_SUCCESS) { 357 return OS_ERR; 358 } 359 char counter[512]; 360 HCOUNTER handle_counter = NULL; 361 // iterate over all instance indexes and try to find our own pid 362 for (int index = 0; index < max_intx; index++) { 363 jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index); 364 assert(strlen(counter) < sizeof(counter), "invariant"); 365 if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) { 366 pdh_cleanup(&tmpQuery, &handle_counter); 367 return OS_ERR; 368 } 369 const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery); 370 if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) { 371 pdh_cleanup(&tmpQuery, &handle_counter); 372 return OS_ERR; 373 } else { 374 PDH_FMT_COUNTERVALUE counter_value; 375 formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value); 376 pdh_cleanup(NULL, &handle_counter); 377 if ((LONG)os::current_process_id() == counter_value.longValue) { 378 pdh_cleanup(&tmpQuery, NULL); 379 return index; 380 } 381 } 382 } 383 pdh_cleanup(&tmpQuery, NULL); 384 return OS_ERR; 385 } 386 387 static ProcessQueryP create_process_query() { 388 const int current_process_idx = current_query_index_for_process(); 389 if (OS_ERR == current_process_idx) { 390 return NULL; 391 } 392 ProcessQueryP const process_query = NEW_C_HEAP_ARRAY(ProcessQueryS, 1, mtInternal); 393 memset(process_query, 0, sizeof(ProcessQueryS)); 394 process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal); 395 memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1)); 396 process_query->process_index = current_process_idx; 397 process_query->set.size = current_process_idx + 1; 398 assert(process_query->set.size > process_query->process_index, "invariant"); 399 return process_query; 400 } 401 402 static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) { 403 assert(process_query != NULL, "invariant"); 404 assert(process_query->process_index < process_query->set.size, "invariant"); 405 return &process_query->set.queries[process_query->process_index]; 406 } 407 408 static void clear_multi_counter(MultiCounterQueryP query) { 409 for (int i = 0; i < query->noOfCounters; ++i) { 410 pdh_cleanup(NULL, &query->counters[i]); 411 } 412 pdh_cleanup(&query->query.query, NULL); 413 query->initialized = false; 414 } 415 416 static int ensure_valid_process_query_index(ProcessQueryP process_query) { 417 assert(process_query != NULL, "invariant"); 418 const int previous_process_idx = process_query->process_index; 419 if (previous_process_idx == 0) { 420 return previous_process_idx; 421 } 422 const int current_process_idx = current_query_index_for_process(); 423 if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx || 424 current_process_idx >= process_query->set.size) { 425 return previous_process_idx; 426 } 427 428 assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!"); 429 while (current_process_idx < process_query->set.size - 1) { 430 const int new_size = --process_query->set.size; 431 clear_multi_counter(&process_query->set.queries[new_size]); 432 } 433 assert(current_process_idx < process_query->set.size, "invariant"); 434 process_query->process_index = current_process_idx; 435 return current_process_idx; 436 } 437 438 static MultiCounterQueryP current_process_query(ProcessQueryP process_query) { 439 assert(process_query != NULL, "invariant"); 440 const int current_process_idx = ensure_valid_process_query_index(process_query); 441 assert(current_process_idx == process_query->process_index, "invariant"); 442 assert(current_process_idx < process_query->set.size, "invariant"); 443 return &process_query->set.queries[current_process_idx]; 444 } 445 446 static int collect_process_query_data(ProcessQueryP process_query) { 447 assert(process_query != NULL, "invariant"); 448 return collect_query_data(current_process_query(process_query)); 449 } 450 451 static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) { 452 MultiCounterQueryP const current_query = current_process_counter_query(process_query); 453 assert(current_query != NULL, "invariant"); 454 assert(slot_index < current_query->noOfCounters, "invariant"); 455 assert(current_query->counters[slot_index] != NULL, "invariant"); 456 return formatted_counter_value(current_query->counters[slot_index], format, value); 457 } 458 459 /* 460 * Construct a fully qualified PDH path 461 * 462 * @param objectName a PDH Object string representation(required) 463 * @param counterName a PDH Counter string representation(required) 464 * @param imageName a process image name string, ex. "java" (opt) 465 * @param instance an instance string, ex. "0", "1", ... (opt) 466 * @return the fully qualified PDH path. 467 * 468 * Caller will need a ResourceMark. 469 * 470 * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead) 471 */ 472 static const char* make_fully_qualified_counter_path(const char* object_name, 473 const char* counter_name, 474 const char* image_name = NULL, 475 const char* instance = NULL) { 476 assert(object_name != NULL, "invariant"); 477 assert(counter_name != NULL, "invariant"); 478 size_t full_counter_path_len = strlen(object_name) + strlen(counter_name); 479 480 char* full_counter_path; 481 size_t jio_snprintf_result = 0; 482 if (image_name) { 483 /* 484 * For paths using the "Process" Object. 485 * 486 * Examples: 487 * form: "\object_name(image_name#instance)\counter_name" 488 * actual: "\Process(java#2)\ID Process" 489 */ 490 full_counter_path_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN; 491 full_counter_path_len += strlen(image_name); 492 /* 493 * image_name must be passed together with an associated 494 * instance "number" ("0", "1", "2", ...). 495 * This is required in order to create valid "Process" Object paths. 496 * 497 * Examples: "\Process(java#0)", \Process(java#1"), ... 498 */ 499 assert(instance != NULL, "invariant"); 500 full_counter_path_len += strlen(instance); 501 full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1); 502 if (full_counter_path == NULL) { 503 return NULL; 504 } 505 jio_snprintf_result = jio_snprintf(full_counter_path, 506 full_counter_path_len + 1, 507 PROCESS_OBJECT_INSTANCE_COUNTER_FMT, 508 object_name, 509 image_name, 510 instance, 511 counter_name); 512 } else { 513 if (instance) { 514 /* 515 * For paths where the Object has multiple instances. 516 * 517 * Examples: 518 * form: "\object_name(instance)\counter_name" 519 * actual: "\Processor(0)\% Privileged Time" 520 */ 521 full_counter_path_len += strlen(instance); 522 full_counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; 523 } else { 524 /* 525 * For "normal" paths. 526 * 527 * Examples: 528 * form: "\object_name\counter_name" 529 * actual: "\Memory\Available Mbytes" 530 */ 531 full_counter_path_len += OBJECT_COUNTER_FMT_LEN; 532 } 533 full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1); 534 if (full_counter_path == NULL) { 535 return NULL; 536 } 537 if (instance) { 538 jio_snprintf_result = jio_snprintf(full_counter_path, 539 full_counter_path_len + 1, 540 OBJECT_WITH_INSTANCES_COUNTER_FMT, 541 object_name, 542 instance, 543 counter_name); 544 } else { 545 jio_snprintf_result = jio_snprintf(full_counter_path, 546 full_counter_path_len + 1, 547 OBJECT_COUNTER_FMT, 548 object_name, 549 counter_name); 550 } 551 } 552 assert(full_counter_path_len == jio_snprintf_result, "invariant"); 553 return full_counter_path; 554 } 555 556 static void log_invalid_pdh_index(DWORD index) { 557 log_warning(os)("Unable to resolve PDH index: (%ld)", index); 558 log_warning(os)("Please check the registry if this performance object/counter is disabled"); 559 } 560 561 static bool is_valid_pdh_index(DWORD index) { 562 DWORD dummy = 0; 563 if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) { 564 log_invalid_pdh_index(index); 565 return false; 566 } 567 return true; 568 } 569 570 /* 571 * Maps an index to a resource area allocated string for the localized PDH artifact. 572 * 573 * Caller will need a ResourceMark. 574 * 575 * @param index the counter index as specified in the registry 576 * @param ppBuffer pointer to a char* 577 * @return OS_OK if successful, OS_ERR on failure. 578 */ 579 static OSReturn lookup_name_by_index(DWORD index, char** p_string) { 580 assert(p_string != NULL, "invariant"); 581 if (!is_valid_pdh_index(index)) { 582 return OS_ERR; 583 } 584 // determine size needed 585 DWORD size = 0; 586 PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size); 587 assert(status == PDH_MORE_DATA, "invariant"); 588 *p_string = NEW_RESOURCE_ARRAY_RETURN_NULL(char, size); 589 if (*p_string== NULL) { 590 return OS_ERR; 591 } 592 if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) { 593 return OS_ERR; 594 } 595 if (0 == size || *p_string == NULL) { 596 return OS_ERR; 597 } 598 // windows vista does not null-terminate the string (although the docs says it will) 599 (*p_string)[size - 1] = '\0'; 600 return OS_OK; 601 } 602 603 static const char* copy_string_to_c_heap(const char* string) { 604 assert(string != NULL, "invariant"); 605 const size_t len = strlen(string); 606 char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); 607 if (NULL == cheap_allocated_string) { 608 return NULL; 609 } 610 strncpy(cheap_allocated_string, string, len + 1); 611 return cheap_allocated_string; 612 } 613 614 /* 615 * Maps an index to a resource area allocated string for the localized PDH artifact. 616 * 617 * Caller will need a ResourceMark. 618 * 619 * @param index the counter index as specified in the registry 620 * @return localized pdh artifact string if successful, NULL on failure. 621 */ 622 static const char* pdh_localized_artifact(DWORD pdh_artifact_index) { 623 char* pdh_localized_artifact_string = NULL; 624 // get localized name from pdh artifact index 625 if (lookup_name_by_index(pdh_artifact_index, &pdh_localized_artifact_string) != OS_OK) { 626 return NULL; 627 } 628 return pdh_localized_artifact_string; 629 } 630 631 /* 632 * Returns the PDH string identifying the current process image name. 633 * Use this prefix when getting counters from the PDH process object 634 * representing your process. 635 * Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process 636 * image description. 637 * 638 * Caller needs ResourceMark. 639 * 640 * @return the process image description. NULL if the call failed. 641 */ 642 static const char* pdh_process_image_name() { 643 char* module_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, MAX_PATH); 644 if (NULL == module_name) { 645 return NULL; 646 } 647 // Find our module name and use it to extract the image name used by PDH 648 DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH); 649 if (getmfn_return >= MAX_PATH || 0 == getmfn_return) { 650 return NULL; 651 } 652 if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) { 653 return NULL; 654 } 655 char* process_image_name = strrchr(module_name, '\\'); //drop path 656 process_image_name++; //skip slash 657 char* dot_pos = strrchr(process_image_name, '.'); //drop .exe 658 dot_pos[0] = '\0'; 659 return process_image_name; 660 } 661 662 static void deallocate_pdh_constants() { 663 if (process_image_name != NULL) { 664 FREE_C_HEAP_ARRAY(char, process_image_name); 665 process_image_name = NULL; 666 } 667 if (pdh_IDProcess_counter_fmt != NULL) { 668 FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt); 669 pdh_IDProcess_counter_fmt = NULL; 670 } 671 } 672 673 static int allocate_pdh_constants() { 674 assert(process_image_name == NULL, "invariant"); 675 const char* pdh_image_name = pdh_process_image_name(); 676 if (pdh_image_name == NULL) { 677 return OS_ERR; 678 } 679 process_image_name = copy_string_to_c_heap(pdh_image_name); 680 681 const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX); 682 if (pdh_localized_process_object == NULL) { 683 return OS_ERR; 684 } 685 686 const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX); 687 if (pdh_localized_IDProcess_counter == NULL) { 688 return OS_ERR; 689 } 690 691 size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name); 692 pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object); 693 pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter); 694 pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN; 695 pdh_IDProcess_counter_fmt_len += 2; // "%d" 696 697 assert(pdh_IDProcess_counter_fmt == NULL, "invariant"); 698 pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal); 699 if (pdh_IDProcess_counter_fmt == NULL) { 700 return OS_ERR; 701 } 702 703 /* "\Process(java#%d)\ID Process" */ 704 const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt, 705 pdh_IDProcess_counter_fmt_len + 1, 706 PROCESS_OBJECT_INSTANCE_COUNTER_FMT, 707 pdh_localized_process_object, 708 process_image_name, 709 "%d", 710 pdh_localized_IDProcess_counter); 711 712 assert(pdh_IDProcess_counter_fmt != NULL, "invariant"); 713 assert(len == pdh_IDProcess_counter_fmt_len, "invariant"); 714 return OS_OK; 715 } 716 717 /* 718 * Enuerate the Processor PDH object and returns a buffer containing the enumerated instances. 719 * Caller needs ResourceMark; 720 * 721 * @return buffer if successful, NULL on failure. 722 */ 723 static const char* enumerate_cpu_instances() { 724 char* processor; //'Processor' == PDH_PROCESSOR_IDX 725 if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { 726 return NULL; 727 } 728 DWORD c_size = 0; 729 DWORD i_size = 0; 730 // enumerate all processors. 731 PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved 732 NULL, // local machine 733 processor, // object to enumerate 734 NULL, 735 &c_size, 736 NULL, // instance buffer is NULL and 737 &i_size, // pass 0 length in order to get the required size 738 PERF_DETAIL_WIZARD, // counter detail level 739 0); 740 if (PdhDll::PdhStatusFail((pdhStat))) { 741 return NULL; 742 } 743 char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size); 744 if (instances == NULL) { 745 return NULL; 746 } 747 c_size = 0; 748 pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved 749 NULL, // local machine 750 processor, // object to enumerate 751 NULL, 752 &c_size, 753 instances, // now instance buffer is allocated to be filled in 754 &i_size, // and the required size is known 755 PERF_DETAIL_WIZARD, // counter detail level 756 0); 757 if (PdhDll::PdhStatusFail((pdhStat))) { 758 return NULL; 759 } 760 return instances; 761 } 762 763 static int count_logical_cpus(const char* instances) { 764 assert(instances != NULL, "invariant"); 765 // count logical instances. 766 DWORD count; 767 char* tmp; 768 for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++); 769 // PDH reports an instance for each logical processor plus an instance for the total (_Total) 770 assert(count == os::processor_count() + 1, "invalid enumeration!"); 771 return count - 1; 772 } 773 774 static int number_of_logical_cpus() { 775 static int numberOfCPUS = 0; 776 if (numberOfCPUS == 0) { 777 const char* instances = enumerate_cpu_instances(); 778 if (instances == NULL) { 779 return OS_ERR; 780 } 781 numberOfCPUS = count_logical_cpus(instances); 782 } 783 return numberOfCPUS; 784 } 785 786 static double cpu_factor() { 787 static DWORD numCpus = 0; 788 static double cpuFactor = .0; 789 if (numCpus == 0) { 790 numCpus = number_of_logical_cpus(); 791 assert(os::processor_count() <= (int)numCpus, "invariant"); 792 cpuFactor = numCpus * 100; 793 } 794 return cpuFactor; 795 } 796 797 static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) { 798 log_warning(os)("Unable to register PDH query for \"%s\"", full_counter_name); 799 log_warning(os)("Please check the registry if this performance object/counter is disabled"); 800 } 801 802 static int initialize_cpu_query_counters(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) { 803 assert(cpu_query != NULL, "invariant"); 804 assert(cpu_query->counters != NULL, "invariant"); 805 char* processor; //'Processor' == PDH_PROCESSOR_IDX 806 if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { 807 return OS_ERR; 808 } 809 char* counter_name = NULL; 810 if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) { 811 return OS_ERR; 812 } 813 if (cpu_query->query.query == NULL) { 814 if (open_query(cpu_query)) { 815 return OS_ERR; 816 } 817 } 818 assert(cpu_query->query.query != NULL, "invariant"); 819 size_t counter_len = strlen(processor); 820 counter_len += strlen(counter_name); 821 counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s" 822 823 DWORD index; 824 char* tmp; 825 const char* instances = enumerate_cpu_instances(); 826 for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) { 827 const size_t tmp_len = strlen(tmp); 828 char* counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, counter_len + tmp_len + 1); 829 if (counter_path == NULL) { 830 return OS_ERR; 831 } 832 const size_t jio_snprintf_result = jio_snprintf(counter_path, 833 counter_len + tmp_len + 1, 834 OBJECT_WITH_INSTANCES_COUNTER_FMT, 835 processor, 836 tmp, // instance "0", "1", .."_Total" 837 counter_name); 838 assert(counter_len + tmp_len == jio_snprintf_result, "invariant"); 839 if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) { 840 // performance counter is disabled in registry and not accessible via PerfLib 841 log_error_message_on_no_PDH_artifact(counter_path); 842 // return OS_OK to have the system continue to run without the missing counter 843 return OS_OK; 844 } 845 } 846 cpu_query->initialized = true; 847 // Query once to initialize the counters which require at least two samples 848 // (like the % CPU usage) to calculate correctly. 849 collect_query_data(cpu_query); 850 return OS_OK; 851 } 852 853 static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) { 854 assert(cpu_query != NULL, "invariant"); 855 assert(!cpu_query->initialized, "invariant"); 856 const int logical_cpu_count = number_of_logical_cpus(); 857 assert(logical_cpu_count >= os::processor_count(), "invariant"); 858 // we also add another counter for instance "_Total" 859 if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) { 860 return OS_ERR; 861 } 862 assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant"); 863 return initialize_cpu_query_counters(cpu_query, pdh_counter_idx); 864 } 865 866 static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) { 867 char* localized_process_object; 868 if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) { 869 return OS_ERR; 870 } 871 assert(localized_process_object != NULL, "invariant"); 872 char* localized_counter_name; 873 if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) { 874 return OS_ERR; 875 } 876 assert(localized_counter_name != NULL, "invariant"); 877 for (int i = 0; i < process_query->set.size; ++i) { 878 char instanceIndexBuffer[32]; 879 const char* counter_path = make_fully_qualified_counter_path(localized_process_object, 880 localized_counter_name, 881 process_image_name, 882 itoa(i, instanceIndexBuffer, 10)); 883 if (counter_path == NULL) { 884 return OS_ERR; 885 } 886 MultiCounterQueryP const query = &process_query->set.queries[i]; 887 if (add_process_counter(query, slot_index, counter_path, true)) { 888 return OS_ERR; 889 } 890 } 891 return OS_OK; 892 } 893 894 static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) { 895 if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) { 896 return NULL; 897 } 898 CounterQueryP const query = create_counter_query(); 899 const char* object = pdh_localized_artifact(pdh_object_idx); 900 assert(object != NULL, "invariant"); 901 const char* counter = pdh_localized_artifact(pdh_counter_idx); 902 assert(counter != NULL, "invariant"); 903 const char* full_counter_path = make_fully_qualified_counter_path(object, counter); 904 assert(full_counter_path != NULL, "invariant"); 905 add_counter(query, full_counter_path, true); 906 return query; 907 } 908 909 static void deallocate() { 910 deallocate_pdh_constants(); 911 PdhDll::PdhDetach(); 912 } 913 914 static LONG critical_section = 0; 915 static LONG reference_count = 0; 916 static bool pdh_initialized = false; 917 918 static void on_initialization_failure() { 919 // still holder of critical section 920 deallocate(); 921 InterlockedExchangeAdd(&reference_count, -1); 922 } 923 924 static OSReturn initialize() { 925 ResourceMark rm; 926 if (!PdhDll::PdhAttach()) { 927 return OS_ERR; 928 } 929 if (allocate_pdh_constants() != OS_OK) { 930 on_initialization_failure(); 931 return OS_ERR; 932 } 933 return OS_OK; 934 } 935 936 /* 937 * Helper to initialize the PDH library, function pointers, constants and counters. 938 * 939 * Reference counting allows for unloading of pdh.dll granted all sessions use the pair: 940 * 941 * pdh_acquire(); 942 * pdh_release(); 943 * 944 * @return OS_OK if successful, OS_ERR on failure. 945 */ 946 static bool pdh_acquire() { 947 while (InterlockedCompareExchange(&critical_section, 1, 0) == 1); 948 InterlockedExchangeAdd(&reference_count, 1); 949 if (pdh_initialized) { 950 return true; 951 } 952 const OSReturn ret = initialize(); 953 if (OS_OK == ret) { 954 pdh_initialized = true; 955 } 956 while (InterlockedCompareExchange(&critical_section, 0, 1) == 0); 957 return ret == OS_OK; 958 } 959 960 static void pdh_release() { 961 while (InterlockedCompareExchange(&critical_section, 1, 0) == 1); 962 const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1); 963 if (1 == prev_ref_count) { 964 deallocate(); 965 pdh_initialized = false; 966 } 967 while (InterlockedCompareExchange(&critical_section, 0, 1) == 0); 968 } 969 970 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> { 971 friend class CPUPerformanceInterface; 972 private: 973 CounterQueryP _context_switches; 974 ProcessQueryP _process_cpu_load; 975 MultiCounterQueryP _machine_cpu_load; 976 977 int cpu_load(int which_logical_cpu, double* cpu_load); 978 int context_switch_rate(double* rate); 979 int cpu_load_total_process(double* cpu_load); 980 int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad); 981 CPUPerformance(); 982 ~CPUPerformance(); 983 bool initialize(); 984 }; 985 986 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> { 987 friend class SystemProcessInterface; 988 private: 989 class ProcessIterator : public CHeapObj<mtInternal> { 990 friend class SystemProcessInterface::SystemProcesses; 991 private: 992 HANDLE _hProcessSnap; 993 PROCESSENTRY32 _pe32; 994 BOOL _valid; 995 char _exePath[MAX_PATH]; 996 ProcessIterator(); 997 ~ProcessIterator(); 998 bool initialize(); 999 1000 int current(SystemProcess* const process_info); 1001 int next_process(); 1002 bool is_valid() const { return _valid != FALSE; } 1003 char* allocate_string(const char* str) const; 1004 int snapshot(); 1005 }; 1006 1007 ProcessIterator* _iterator; 1008 SystemProcesses(); 1009 ~SystemProcesses(); 1010 bool initialize(); 1011 1012 // information about system processes 1013 int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; 1014 }; 1015 1016 CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {} 1017 1018 bool CPUPerformanceInterface::CPUPerformance::initialize() { 1019 if (!pdh_acquire()) { 1020 return true; 1021 } 1022 _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX); 1023 _process_cpu_load = create_process_query(); 1024 if (_process_cpu_load == NULL) { 1025 return true; 1026 } 1027 if (allocate_counters(_process_cpu_load, 2) != OS_OK) { 1028 return true; 1029 } 1030 if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) { 1031 return true; 1032 } 1033 if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) { 1034 return true; 1035 } 1036 _process_cpu_load->set.initialized = true; 1037 _machine_cpu_load = create_multi_counter_query(); 1038 if (_machine_cpu_load == NULL) { 1039 return true; 1040 } 1041 initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX); 1042 return true; 1043 } 1044 1045 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { 1046 if (_context_switches != NULL) { 1047 destroy_counter_query(_context_switches); 1048 _context_switches = NULL; 1049 } 1050 if (_process_cpu_load != NULL) { 1051 destroy_counter_query(_process_cpu_load); 1052 _process_cpu_load = NULL; 1053 } 1054 if (_machine_cpu_load != NULL) { 1055 destroy_counter_query(_machine_cpu_load); 1056 _machine_cpu_load = NULL; 1057 } 1058 pdh_release(); 1059 } 1060 1061 CPUPerformanceInterface::CPUPerformanceInterface() { 1062 _impl = NULL; 1063 } 1064 1065 bool CPUPerformanceInterface::initialize() { 1066 _impl = new CPUPerformanceInterface::CPUPerformance(); 1067 return _impl != NULL && _impl->initialize(); 1068 } 1069 1070 CPUPerformanceInterface::~CPUPerformanceInterface() { 1071 if (_impl != NULL) { 1072 delete _impl; 1073 } 1074 } 1075 1076 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { 1077 return _impl->cpu_load(which_logical_cpu, cpu_load); 1078 } 1079 1080 int CPUPerformanceInterface::context_switch_rate(double* rate) const { 1081 return _impl->context_switch_rate(rate); 1082 } 1083 1084 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { 1085 return _impl->cpu_load_total_process(cpu_load); 1086 } 1087 1088 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, 1089 double* pjvmKernelLoad, 1090 double* psystemTotalLoad) const { 1091 return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); 1092 } 1093 1094 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { 1095 *cpu_load = .0; 1096 if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) { 1097 return OS_ERR; 1098 } 1099 assert(_machine_cpu_load != NULL, "invariant"); 1100 assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant"); 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 *cpu_load = .0; 1115 if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) { 1116 return OS_ERR; 1117 } 1118 assert(_process_cpu_load != NULL, "invariant"); 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 1143 if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) { 1144 return OS_ERR; 1145 } 1146 assert(_process_cpu_load != NULL, "invariant"); 1147 if (collect_process_query_data(_process_cpu_load)) { 1148 return OS_ERR; 1149 } 1150 double process_load = .0; 1151 PDH_FMT_COUNTERVALUE counter_value; 1152 // Read PDH_PROCESSOR_TIME_IDX 1153 if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) { 1154 return OS_ERR; 1155 } 1156 process_load = counter_value.doubleValue / cpu_factor(); 1157 process_load = MIN2<double>(1, process_load); 1158 process_load = MAX2<double>(0, process_load); 1159 // Read PDH_PRIV_PROCESSOR_TIME_IDX 1160 if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) { 1161 return OS_ERR; 1162 } 1163 double kernel_load = counter_value.doubleValue / cpu_factor(); 1164 kernel_load = MIN2<double>(1, kernel_load); 1165 kernel_load = MAX2<double>(0, kernel_load); 1166 *pjvmKernelLoad = kernel_load; 1167 1168 double user_load = process_load - kernel_load; 1169 user_load = MIN2<double>(1, user_load); 1170 user_load = MAX2<double>(0, user_load); 1171 *pjvmUserLoad = user_load; 1172 1173 if (collect_query_data(_machine_cpu_load)) { 1174 return OS_ERR; 1175 } 1176 if (formatted_counter_value(_machine_cpu_load->counters[_machine_cpu_load->noOfCounters - 1], PDH_FMT_DOUBLE, &counter_value) != OS_OK) { 1177 return OS_ERR; 1178 } 1179 double machine_load = counter_value.doubleValue / 100; 1180 assert(machine_load >= 0, "machine_load is negative!"); 1181 // clamp at user+system and 1.0 1182 if (*pjvmKernelLoad + *pjvmUserLoad > machine_load) { 1183 machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0); 1184 } 1185 *psystemTotalLoad = machine_load; 1186 return OS_OK; 1187 } 1188 1189 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { 1190 assert(rate != NULL, "invariant"); 1191 *rate = .0; 1192 if (_context_switches == NULL || !_context_switches->initialized) { 1193 return OS_ERR; 1194 } 1195 assert(_context_switches != NULL, "invariant"); 1196 if (collect_query_data(_context_switches) != OS_OK) { 1197 return OS_ERR; 1198 } 1199 PDH_FMT_COUNTERVALUE counter_value; 1200 if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) { 1201 return OS_ERR; 1202 } 1203 *rate = counter_value.doubleValue; 1204 return OS_OK; 1205 } 1206 1207 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { 1208 _hProcessSnap = INVALID_HANDLE_VALUE; 1209 _valid = FALSE; 1210 _pe32.dwSize = sizeof(PROCESSENTRY32); 1211 } 1212 1213 bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { 1214 return true; 1215 } 1216 1217 int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() { 1218 // take snapshot of all process in the system 1219 _hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 1220 if (_hProcessSnap == INVALID_HANDLE_VALUE) { 1221 return OS_ERR; 1222 } 1223 // step to first process 1224 _valid = Process32First(_hProcessSnap, &_pe32); 1225 return is_valid() ? OS_OK : OS_ERR; 1226 } 1227 1228 SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { 1229 if (_hProcessSnap != INVALID_HANDLE_VALUE) { 1230 CloseHandle(_hProcessSnap); 1231 } 1232 } 1233 1234 int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { 1235 assert(is_valid(), "no current process to be fetched!"); 1236 assert(process_info != NULL, "process_info is NULL!"); 1237 char* exePath = NULL; 1238 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID); 1239 if (hProcess != NULL) { 1240 HMODULE hMod; 1241 DWORD cbNeeded; 1242 if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) { 1243 if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) { 1244 exePath = _exePath; 1245 } 1246 } 1247 CloseHandle (hProcess); 1248 } 1249 process_info->set_pid((int)_pe32.th32ProcessID); 1250 process_info->set_name(allocate_string(_pe32.szExeFile)); 1251 process_info->set_path(allocate_string(exePath)); 1252 return OS_OK; 1253 } 1254 1255 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { 1256 if (str != NULL) { 1257 return os::strdup_check_oom(str, mtInternal); 1258 } 1259 return NULL; 1260 } 1261 1262 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { 1263 _valid = Process32Next(_hProcessSnap, &_pe32); 1264 return OS_OK; 1265 } 1266 1267 SystemProcessInterface::SystemProcesses::SystemProcesses() { 1268 _iterator = NULL; 1269 } 1270 1271 bool SystemProcessInterface::SystemProcesses::initialize() { 1272 _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); 1273 return _iterator != NULL && _iterator->initialize(); 1274 } 1275 1276 SystemProcessInterface::SystemProcesses::~SystemProcesses() { 1277 if (_iterator != NULL) { 1278 delete _iterator; 1279 _iterator = NULL; 1280 } 1281 } 1282 1283 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, 1284 int* no_of_sys_processes) const { 1285 assert(system_processes != NULL, "system_processes pointer is NULL!"); 1286 assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!"); 1287 assert(_iterator != NULL, "iterator is NULL!"); 1288 1289 // initialize pointers 1290 *no_of_sys_processes = 0; 1291 *system_processes = NULL; 1292 1293 // take process snapshot 1294 if (_iterator->snapshot() != OS_OK) { 1295 return OS_ERR; 1296 } 1297 1298 while (_iterator->is_valid()) { 1299 SystemProcess* tmp = new SystemProcess(); 1300 _iterator->current(tmp); 1301 1302 //if already existing head 1303 if (*system_processes != NULL) { 1304 //move "first to second" 1305 tmp->set_next(*system_processes); 1306 } 1307 // new head 1308 *system_processes = tmp; 1309 // increment 1310 (*no_of_sys_processes)++; 1311 // step forward 1312 _iterator->next_process(); 1313 } 1314 return OS_OK; 1315 } 1316 1317 int SystemProcessInterface::system_processes(SystemProcess** system_procs, 1318 int* no_of_sys_processes) const { 1319 return _impl->system_processes(system_procs, no_of_sys_processes); 1320 } 1321 1322 SystemProcessInterface::SystemProcessInterface() { 1323 _impl = NULL; 1324 } 1325 1326 bool SystemProcessInterface::initialize() { 1327 _impl = new SystemProcessInterface::SystemProcesses(); 1328 return _impl != NULL && _impl->initialize(); 1329 } 1330 1331 SystemProcessInterface::~SystemProcessInterface() { 1332 if (_impl != NULL) { 1333 delete _impl; 1334 } 1335 } 1336 1337 CPUInformationInterface::CPUInformationInterface() { 1338 _cpu_info = NULL; 1339 } 1340 1341 bool CPUInformationInterface::initialize() { 1342 _cpu_info = new CPUInformation(); 1343 if (NULL == _cpu_info) { 1344 return false; 1345 } 1346 _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); 1347 _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); 1348 _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); 1349 _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); 1350 _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); 1351 return true; 1352 } 1353 1354 CPUInformationInterface::~CPUInformationInterface() { 1355 if (_cpu_info != NULL) { 1356 const char* cpu_name = _cpu_info->cpu_name(); 1357 if (cpu_name != NULL) { 1358 FREE_C_HEAP_ARRAY(char, cpu_name); 1359 _cpu_info->set_cpu_name(NULL); 1360 } 1361 const char* cpu_desc = _cpu_info->cpu_description(); 1362 if (cpu_desc != NULL) { 1363 FREE_C_HEAP_ARRAY(char, cpu_desc); 1364 _cpu_info->set_cpu_description(NULL); 1365 } 1366 delete _cpu_info; 1367 _cpu_info = NULL; 1368 } 1369 } 1370 1371 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { 1372 if (NULL == _cpu_info) { 1373 return OS_ERR; 1374 } 1375 cpu_info = *_cpu_info; // shallow copy assignment 1376 return OS_OK; 1377 } 1378 1379 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> { 1380 friend class NetworkPerformanceInterface; 1381 private: 1382 bool _iphlp_attached; 1383 1384 NetworkPerformance(); 1385 NONCOPYABLE(NetworkPerformance); 1386 bool initialize(); 1387 ~NetworkPerformance(); 1388 int network_utilization(NetworkInterface** network_interfaces) const; 1389 }; 1390 1391 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() 1392 : _iphlp_attached(false) { 1393 } 1394 1395 bool NetworkPerformanceInterface::NetworkPerformance::initialize() { 1396 _iphlp_attached = IphlpDll::IphlpAttach(); 1397 return _iphlp_attached; 1398 } 1399 1400 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { 1401 if (_iphlp_attached) { 1402 IphlpDll::IphlpDetach(); 1403 } 1404 } 1405 1406 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { 1407 MIB_IF_TABLE2* table; 1408 1409 if (IphlpDll::GetIfTable2(&table) != NO_ERROR) { 1410 return OS_ERR; 1411 } 1412 1413 NetworkInterface* ret = NULL; 1414 for (ULONG i = 0; i < table->NumEntries; ++i) { 1415 if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) { 1416 continue; 1417 } 1418 1419 char buf[256]; 1420 if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) { 1421 continue; 1422 } 1423 1424 NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret); 1425 ret = cur; 1426 } 1427 1428 IphlpDll::FreeMibTable(table); 1429 *network_interfaces = ret; 1430 1431 return OS_OK; 1432 } 1433 1434 NetworkPerformanceInterface::NetworkPerformanceInterface() { 1435 _impl = NULL; 1436 } 1437 1438 NetworkPerformanceInterface::~NetworkPerformanceInterface() { 1439 if (_impl != NULL) { 1440 delete _impl; 1441 } 1442 } 1443 1444 bool NetworkPerformanceInterface::initialize() { 1445 _impl = new NetworkPerformanceInterface::NetworkPerformance(); 1446 return _impl != NULL && _impl->initialize(); 1447 } 1448 1449 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { 1450 return _impl->network_utilization(network_interfaces); 1451 }