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