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