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