1 /* 2 * Copyright (c) 2003, 2011, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jni.h" 27 #include "jni_util.h" 28 #include "jlong.h" 29 #include "jvm.h" 30 #include "management.h" 31 #include "com_sun_management_OperatingSystem.h" 32 33 #include <psapi.h> 34 #include <errno.h> 35 #include <stdlib.h> 36 37 #include <malloc.h> 38 #pragma warning (push,0) 39 #include <windows.h> 40 #pragma warning (pop) 41 #include <stdio.h> 42 #include <time.h> 43 #include <stdint.h> 44 #include <assert.h> 45 46 /* Disable warnings due to broken header files from Microsoft... */ 47 #pragma warning(push, 3) 48 #include <pdh.h> 49 #include <pdhmsg.h> 50 #include <process.h> 51 #pragma warning(pop) 52 53 typedef unsigned __int32 juint; 54 typedef unsigned __int64 julong; 55 56 typedef enum boolean_values { false=0, true=1}; 57 58 static void set_low(jlong* value, jint low) { 59 *value &= (jlong)0xffffffff << 32; 60 *value |= (jlong)(julong)(juint)low; 61 } 62 63 static void set_high(jlong* value, jint high) { 64 *value &= (jlong)(julong)(juint)0xffffffff; 65 *value |= (jlong)high << 32; 66 } 67 68 static jlong jlong_from(jint h, jint l) { 69 jlong result = 0; // initialization to avoid warning 70 set_high(&result, h); 71 set_low(&result, l); 72 return result; 73 } 74 75 static HANDLE main_process; 76 77 int perfiInit(void); 78 79 JNIEXPORT void JNICALL 80 Java_com_sun_management_OperatingSystem_initialize 81 (JNIEnv *env, jclass cls) 82 { 83 main_process = GetCurrentProcess(); 84 perfiInit(); 85 } 86 87 JNIEXPORT jlong JNICALL 88 Java_com_sun_management_OperatingSystem_getCommittedVirtualMemorySize0 89 (JNIEnv *env, jobject mbean) 90 { 91 PROCESS_MEMORY_COUNTERS pmc; 92 if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) { 93 return (jlong)-1L; 94 } else { 95 return (jlong) pmc.PagefileUsage; 96 } 97 } 98 99 JNIEXPORT jlong JNICALL 100 Java_com_sun_management_OperatingSystem_getTotalSwapSpaceSize 101 (JNIEnv *env, jobject mbean) 102 { 103 MEMORYSTATUSEX ms; 104 ms.dwLength = sizeof(ms); 105 GlobalMemoryStatusEx(&ms); 106 return (jlong) ms.ullTotalPageFile; 107 } 108 109 JNIEXPORT jlong JNICALL 110 Java_com_sun_management_OperatingSystem_getFreeSwapSpaceSize 111 (JNIEnv *env, jobject mbean) 112 { 113 MEMORYSTATUSEX ms; 114 ms.dwLength = sizeof(ms); 115 GlobalMemoryStatusEx(&ms); 116 return (jlong) ms.ullAvailPageFile; 117 } 118 119 JNIEXPORT jlong JNICALL 120 Java_com_sun_management_OperatingSystem_getProcessCpuTime 121 (JNIEnv *env, jobject mbean) 122 { 123 124 FILETIME process_creation_time, process_exit_time, 125 process_user_time, process_kernel_time; 126 127 // Using static variables declared above 128 // Units are 100-ns intervals. Convert to ns. 129 GetProcessTimes(main_process, &process_creation_time, 130 &process_exit_time, 131 &process_kernel_time, &process_user_time); 132 return (jlong_from(process_user_time.dwHighDateTime, 133 process_user_time.dwLowDateTime) + 134 jlong_from(process_kernel_time.dwHighDateTime, 135 process_kernel_time.dwLowDateTime)) * 100; 136 } 137 138 JNIEXPORT jlong JNICALL 139 Java_com_sun_management_OperatingSystem_getFreePhysicalMemorySize 140 (JNIEnv *env, jobject mbean) 141 { 142 MEMORYSTATUSEX ms; 143 ms.dwLength = sizeof(ms); 144 GlobalMemoryStatusEx(&ms); 145 return (jlong) ms.ullAvailPhys; 146 } 147 148 JNIEXPORT jlong JNICALL 149 Java_com_sun_management_OperatingSystem_getTotalPhysicalMemorySize 150 (JNIEnv *env, jobject mbean) 151 { 152 MEMORYSTATUSEX ms; 153 ms.dwLength = sizeof(ms); 154 GlobalMemoryStatusEx(&ms); 155 return (jlong) ms.ullTotalPhys; 156 } 157 158 // Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer. 159 // Let's just ignore it, since we make sure we have enough buffer anyway. 160 static int 161 pdh_fail(PDH_STATUS pdhStat) { 162 return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA; 163 } 164 165 // INFO: Using PDH APIs Correctly in a Localized Language (Q287159) 166 // http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159 167 // The index value for the base system counters and objects like processor, 168 // process, thread, memory, and so forth are always the same irrespective 169 // of the localized version of the operating system or service pack installed. 170 #define PDH_PROCESSOR_IDX ((DWORD) 238) 171 #define PDH_PROCESSOR_TIME_IDX ((DWORD) 6) 172 #define PDH_PRIV_PROCESSOR_TIME_IDX ((DWORD) 144) 173 #define PDH_PROCESS_IDX ((DWORD) 230) 174 #define PDH_ID_PROCESS_IDX ((DWORD) 784) 175 #define PDH_CONTEXT_SWITCH_RATE_IDX ((DWORD) 146) 176 #define PDH_SYSTEM_IDX ((DWORD) 2) 177 #define PDH_VIRTUAL_BYTES_IDX ((DWORD) 174) 178 179 typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)( 180 HQUERY hQuery, 181 LPCSTR szFullCounterPath, 182 DWORD dwUserData, 183 HCOUNTER *phCounter 184 ); 185 typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)( 186 LPCWSTR szDataSource, 187 DWORD dwUserData, 188 HQUERY *phQuery 189 ); 190 typedef DWORD (WINAPI *PdhCloseQueryFunc)( 191 HQUERY hQuery 192 ); 193 typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)( 194 HQUERY hQuery 195 ); 196 typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)( 197 HCOUNTER hCounter, 198 DWORD dwFormat, 199 LPDWORD lpdwType, 200 PPDH_FMT_COUNTERVALUE pValue 201 ); 202 typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)( 203 LPCTSTR szDataSource, 204 LPCTSTR szMachineName, 205 LPCTSTR szObjectName, 206 LPTSTR mszCounterList, 207 LPDWORD pcchCounterListLength, 208 LPTSTR mszInstanceList, 209 LPDWORD pcchInstanceListLength, 210 DWORD dwDetailLevel, 211 DWORD dwFlags 212 ); 213 typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)( 214 HCOUNTER hCounter 215 ); 216 typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)( 217 LPCSTR szMachineName, 218 DWORD dwNameIndex, 219 LPSTR szNameBuffer, 220 LPDWORD pcchNameBufferSize 221 ); 222 typedef PDH_STATUS (WINAPI *PdhMakeCounterPathFunc)( 223 PDH_COUNTER_PATH_ELEMENTS *pCounterPathElements, 224 LPTSTR szFullPathBuffer, 225 LPDWORD pcchBufferSize, 226 DWORD dwFlags 227 ); 228 229 static PdhAddCounterFunc PdhAddCounter_i; 230 static PdhOpenQueryFunc PdhOpenQuery_i; 231 static PdhCloseQueryFunc PdhCloseQuery_i; 232 static PdhCollectQueryDataFunc PdhCollectQueryData_i; 233 static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i; 234 static PdhEnumObjectItemsFunc PdhEnumObjectItems_i; 235 static PdhRemoveCounterFunc PdhRemoveCounter_i; 236 static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i; 237 static PdhMakeCounterPathFunc PdhMakeCounterPath_i; 238 239 static HANDLE thisProcess; 240 static double cpuFactor; 241 static DWORD num_cpus; 242 243 #define FT2JLONG(X) ((((jlong)X.dwHighDateTime) << 32) | ((jlong)X.dwLowDateTime)) 244 #define COUNTER_BUF_SIZE 256 245 // Min time between query updates. 246 #define MIN_UPDATE_INTERVAL 500 247 #define CONFIG_SUCCESSFUL 0 248 249 /** 250 * Struct for PDH queries. 251 */ 252 typedef struct { 253 HQUERY query; 254 uint64_t lastUpdate; // Last time query was updated (current millis). 255 } UpdateQueryS, *UpdateQueryP; 256 257 /** 258 * Struct for the processor load counters. 259 */ 260 typedef struct { 261 UpdateQueryS query; 262 HCOUNTER* counters; 263 int noOfCounters; 264 } MultipleCounterQueryS, *MultipleCounterQueryP; 265 266 /** 267 * Struct for the jvm process load counter. 268 */ 269 typedef struct { 270 UpdateQueryS query; 271 HCOUNTER counter; 272 } SingleCounterQueryS, *SingleCounterQueryP; 273 274 static char* getProcessPDHHeader(void); 275 276 /** 277 * Currently available counters. 278 */ 279 static SingleCounterQueryS cntCtxtSwitchRate; 280 static SingleCounterQueryS cntVirtualSize; 281 static SingleCounterQueryS cntProcLoad; 282 static SingleCounterQueryS cntProcSystemLoad; 283 static MultipleCounterQueryS multiCounterCPULoad; 284 285 static CRITICAL_SECTION processHeaderLock; 286 static CRITICAL_SECTION initializationLock; 287 288 /** 289 * Initialize the perf module at startup. 290 */ 291 int 292 perfiInit(void) 293 { 294 InitializeCriticalSection(&processHeaderLock); 295 InitializeCriticalSection(&initializationLock); 296 return 0; 297 } 298 299 /** 300 * Dynamically sets up function pointers to the PDH library. 301 * 302 * @return CONFIG_SUCCESSFUL on success, negative on failure. 303 */ 304 static int 305 get_functions(HMODULE h, char *ebuf, size_t elen) { 306 // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods 307 PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA"); 308 PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA"); 309 PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery"); 310 PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData"); 311 PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue"); 312 PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA"); 313 PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter"); 314 PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA"); 315 PdhMakeCounterPath_i = (PdhMakeCounterPathFunc)GetProcAddress(h, "PdhMakeCounterPathA"); 316 317 if (PdhAddCounter_i == NULL || PdhOpenQuery_i == NULL || 318 PdhCloseQuery_i == NULL || PdhCollectQueryData_i == NULL || 319 PdhGetFormattedCounterValue_i == NULL || PdhEnumObjectItems_i == NULL || 320 PdhRemoveCounter_i == NULL || PdhLookupPerfNameByIndex_i == NULL || PdhMakeCounterPath_i == NULL) 321 { 322 _snprintf(ebuf, elen, "Required method could not be found."); 323 return -1; 324 } 325 return CONFIG_SUCCESSFUL; 326 } 327 328 /** 329 * Returns the counter value as a double for the specified query. 330 * Will collect the query data and update the counter values as necessary. 331 * 332 * @param query the query to update (if needed). 333 * @param c the counter to read. 334 * @param value where to store the formatted value. 335 * @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc) 336 * @return CONFIG_SUCCESSFUL if no error 337 * -1 if PdhCollectQueryData fails 338 * -2 if PdhGetFormattedCounterValue fails 339 */ 340 static int 341 getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) { 342 clock_t now; 343 now = clock(); 344 345 // Need to limit how often we update the query 346 // to mimise the heisenberg effect. 347 // (PDH behaves erratically if the counters are 348 // queried too often, especially counters that 349 // store and use values from two consecutive updates, 350 // like cpu load.) 351 if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) { 352 if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) { 353 return -1; 354 } 355 query->lastUpdate = now; 356 } 357 358 if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) { 359 return -2; 360 } 361 return CONFIG_SUCCESSFUL; 362 } 363 364 /** 365 * Places the resolved counter name of the counter at the specified index in the 366 * supplied buffer. There must be enough space in the buffer to hold the counter name. 367 * 368 * @param index the counter index as specified in the registry. 369 * @param buf the buffer in which to place the counter name. 370 * @param size the size of the counter name buffer. 371 * @param ebuf the error message buffer. 372 * @param elen the length of the error buffer. 373 * @return CONFIG_SUCCESSFUL if successful, negative on failure. 374 */ 375 static int 376 find_name(DWORD index, char *buf, DWORD size) { 377 PDH_STATUS res; 378 379 if ((res = PdhLookupPerfNameByIndex_i(NULL, index, buf, &size)) != ERROR_SUCCESS) { 380 381 /* printf("Could not open counter %d: error=0x%08x", index, res); */ 382 /* if (res == PDH_CSTATUS_NO_MACHINE) { */ 383 /* printf("User probably does not have sufficient privileges to use"); */ 384 /* printf("performance counters. If you are running on Windows 2003"); */ 385 /* printf("or Windows Vista, make sure the user is in the"); */ 386 /* printf("Performance Logs user group."); */ 387 /* } */ 388 return -1; 389 } 390 391 if (size == 0) { 392 /* printf("Failed to get counter name for %d: empty string", index); */ 393 return -1; 394 } 395 396 // windows vista does not null-terminate the string (allthough the docs says it will) 397 buf[size - 1] = '\0'; 398 return CONFIG_SUCCESSFUL; 399 } 400 401 /** 402 * Sets up the supplied SingleCounterQuery to listen for the specified counter. 403 * initPDH() must have been run prior to calling this function! 404 * 405 * @param counterQuery the counter query to set up. 406 * @param counterString the string specifying the path to the counter. 407 * @param ebuf the error buffer. 408 * @param elen the length of the error buffer. 409 * @returns CONFIG_SUCCESSFUL if successful, negative on failure. 410 */ 411 static int 412 initSingleCounterQuery(SingleCounterQueryP counterQuery, char *counterString) { 413 if (PdhOpenQuery_i(NULL, 0, &counterQuery->query.query) != ERROR_SUCCESS) { 414 /* printf("Could not open query for %s", counterString); */ 415 return -1; 416 } 417 if (PdhAddCounter_i(counterQuery->query.query, counterString, 0, &counterQuery->counter) != ERROR_SUCCESS) { 418 /* printf("Could not add counter %s for query", counterString); */ 419 if (counterQuery->counter != NULL) { 420 PdhRemoveCounter_i(counterQuery->counter); 421 } 422 if (counterQuery->query.query != NULL) { 423 PdhCloseQuery_i(counterQuery->query.query); 424 } 425 memset(counterQuery, 0, sizeof(SingleCounterQueryS)); 426 return -1; 427 } 428 return CONFIG_SUCCESSFUL; 429 } 430 431 /** 432 * Sets up the supplied SingleCounterQuery to listen for the time spent 433 * by the HotSpot process. 434 * 435 * @param counterQuery the counter query to set up as a process counter. 436 * @param ebuf the error buffer. 437 * @param elen the length of the error buffer. 438 * @returns CONFIG_SUCCESSFUL if successful, negative on failure. 439 */ 440 static int 441 initProcLoadCounter(void) { 442 char time[COUNTER_BUF_SIZE]; 443 char counter[COUNTER_BUF_SIZE*2]; 444 445 if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { 446 return -1; 447 } 448 _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); 449 return initSingleCounterQuery(&cntProcLoad, counter); 450 } 451 452 static int 453 initProcSystemLoadCounter(void) { 454 char time[COUNTER_BUF_SIZE]; 455 char counter[COUNTER_BUF_SIZE*2]; 456 457 if (find_name(PDH_PRIV_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { 458 return -1; 459 } 460 _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); 461 return initSingleCounterQuery(&cntProcSystemLoad, counter); 462 } 463 464 /** 465 * Sets up the supplied MultipleCounterQuery to check on the processors. 466 * (Comment: Refactor and prettify as with the the SingleCounter queries 467 * if more MultipleCounterQueries are discovered.) 468 * 469 * initPDH() must have been run prior to calling this function. 470 * 471 * @param multiQuery a pointer to a MultipleCounterQueryS, will be filled in with 472 * the necessary info to check the PDH processor counters. 473 * @return CONFIG_SUCCESSFUL if successful, negative on failure. 474 */ 475 static int 476 initProcessorCounters(void) { 477 char processor[COUNTER_BUF_SIZE]; //'Processor' == #238 478 char time[COUNTER_BUF_SIZE]; //'Time' == 6 479 DWORD c_size, i_size; 480 HQUERY tmpQuery; 481 DWORD i, p_count; 482 BOOL error; 483 char *instances, *tmp; 484 PDH_STATUS pdhStat; 485 486 c_size = i_size = 0; 487 tmpQuery = NULL; 488 error = false; 489 490 // This __try / __except stuff is there since Windows 2000 beta (or so) sometimes triggered 491 // an access violation when the user had insufficient privileges to use the performance 492 // counters. This was previously guarded by a very ugly piece of code which disabled the 493 // global trap handling in JRockit. Don't know if this really is needed anymore, but otoh, 494 // if we keep it we don't crash on Win2k beta. /Ihse, 2005-05-30 495 __try { 496 if (find_name(PDH_PROCESSOR_IDX, processor, sizeof(processor)-1) < 0) { 497 return -1; 498 } 499 } __except (EXCEPTION_EXECUTE_HANDLER) { // We'll catch all exceptions here. 500 /* printf("User does not have sufficient privileges to use performance counters"); */ 501 return -1; 502 } 503 504 if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { 505 return -1; 506 } 507 //ok, now we have enough to enumerate all processors. 508 pdhStat = PdhEnumObjectItems_i ( 509 NULL, // reserved 510 NULL, // local machine 511 processor, // object to enumerate 512 NULL, // pass in NULL buffers 513 &c_size, // and 0 length to get 514 NULL, // required size 515 &i_size, // of the buffers in chars 516 PERF_DETAIL_WIZARD, // counter detail level 517 0); 518 if (pdh_fail(pdhStat)) { 519 /* printf("could not enumerate processors (1) error=%d", pdhStat); */ 520 return -1; 521 } 522 523 // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) 524 instances = calloc(i_size, 1); 525 if (instances == NULL) { 526 /* printf("could not allocate memory (1) %d bytes", i_size); */ 527 error = true; 528 goto end; 529 } 530 531 c_size = 0; 532 pdhStat = PdhEnumObjectItems_i ( 533 NULL, // reserved 534 NULL, // local machine 535 processor, // object to enumerate 536 NULL, // pass in NULL buffers 537 &c_size, // and 0 length to get 538 instances, // required size 539 &i_size, // of the buffers in chars 540 PERF_DETAIL_WIZARD, // counter detail level 541 0); 542 543 if (pdh_fail(pdhStat)) { 544 /* printf("could not enumerate processors (2) error=%d", pdhStat); */ 545 error = true; 546 goto end; 547 } 548 //count perf count instances. 549 for (p_count = 0, tmp = instances; *tmp != 0; tmp = &tmp[lstrlen(tmp)+1], p_count++); 550 551 //is this correct for HT? 552 assert(p_count == num_cpus+1); 553 554 //ok, have number of perf counters. 555 multiCounterCPULoad.counters = calloc(p_count, sizeof(HCOUNTER)); 556 if (multiCounterCPULoad.counters == NULL) { 557 /* printf("could not allocate memory (2) count=%d", p_count); */ 558 error = true; 559 goto end; 560 } 561 562 multiCounterCPULoad.noOfCounters = p_count; 563 564 if (PdhOpenQuery_i(NULL, 0, &multiCounterCPULoad.query.query) != ERROR_SUCCESS) { 565 /* printf("could not create query"); */ 566 error = true; 567 goto end; 568 } 569 //now, fetch the counters. 570 for (i = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[lstrlen(tmp)+1], i++) { 571 char counter[2*COUNTER_BUF_SIZE]; 572 573 _snprintf(counter, sizeof(counter)-1, "\\%s(%s)\\%s", processor, tmp, time); 574 575 if (PdhAddCounter_i(multiCounterCPULoad.query.query, counter, 0, &multiCounterCPULoad.counters[i]) != ERROR_SUCCESS) { 576 /* printf("error adding processor counter %s", counter); */ 577 error = true; 578 goto end; 579 } 580 } 581 582 free(instances); 583 instances = NULL; 584 585 // Query once to initialize the counters needing at least two queries 586 // (like the % CPU usage) to calculate correctly. 587 if (PdhCollectQueryData_i(multiCounterCPULoad.query.query) != ERROR_SUCCESS) 588 error = true; 589 590 end: 591 if (instances != NULL) { 592 free(instances); 593 } 594 if (tmpQuery != NULL) { 595 PdhCloseQuery_i(tmpQuery); 596 } 597 if (error) { 598 int i; 599 600 if (multiCounterCPULoad.counters != NULL) { 601 for (i = 0; i < multiCounterCPULoad.noOfCounters; i++) { 602 if (multiCounterCPULoad.counters[i] != NULL) { 603 PdhRemoveCounter_i(multiCounterCPULoad.counters[i]); 604 } 605 } 606 free(multiCounterCPULoad.counters[i]); 607 } 608 if (multiCounterCPULoad.query.query != NULL) { 609 PdhCloseQuery_i(multiCounterCPULoad.query.query); 610 } 611 memset(&multiCounterCPULoad, 0, sizeof(MultipleCounterQueryS)); 612 return -1; 613 } 614 return CONFIG_SUCCESSFUL; 615 } 616 617 /** 618 * Help function that initializes the PDH process header for the JRockit process. 619 * (You should probably use getProcessPDHHeader() instead!) 620 * 621 * initPDH() must have been run prior to calling this function. 622 * 623 * @param ebuf the error buffer. 624 * @param elen the length of the error buffer. 625 * 626 * @return the PDH instance description corresponding to the JVM process. 627 */ 628 static char* 629 initProcessPDHHeader(void) { 630 static char hotspotheader[2*COUNTER_BUF_SIZE]; 631 632 char counter[2*COUNTER_BUF_SIZE]; 633 char processes[COUNTER_BUF_SIZE]; //'Process' == #230 634 char pid[COUNTER_BUF_SIZE]; //'ID Process' == 784 635 char module_name[MAX_PATH]; 636 PDH_STATUS pdhStat; 637 DWORD c_size = 0, i_size = 0; 638 HQUERY tmpQuery = NULL; 639 int i, myPid = _getpid(); 640 BOOL error = false; 641 char *instances, *tmp, *instance_name, *dot_pos; 642 643 tmpQuery = NULL; 644 myPid = _getpid(); 645 error = false; 646 647 if (find_name(PDH_PROCESS_IDX, processes, sizeof(processes) - 1) < 0) { 648 return NULL; 649 } 650 651 if (find_name(PDH_ID_PROCESS_IDX, pid, sizeof(pid) - 1) < 0) { 652 return NULL; 653 } 654 //time is same. 655 656 c_size = 0; 657 i_size = 0; 658 659 pdhStat = PdhEnumObjectItems_i ( 660 NULL, // reserved 661 NULL, // local machine 662 processes, // object to enumerate 663 NULL, // pass in NULL buffers 664 &c_size, // and 0 length to get 665 NULL, // required size 666 &i_size, // of the buffers in chars 667 PERF_DETAIL_WIZARD, // counter detail level 668 0); 669 670 //ok, now we have enough to enumerate all processes 671 if (pdh_fail(pdhStat)) { 672 /* printf("Could not enumerate processes (1) error=%d", pdhStat); */ 673 return NULL; 674 } 675 676 // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) 677 if ((instances = calloc(i_size, 1)) == NULL) { 678 /* printf("Could not allocate memory %d bytes", i_size); */ 679 error = true; 680 goto end; 681 } 682 683 c_size = 0; 684 685 pdhStat = PdhEnumObjectItems_i ( 686 NULL, // reserved 687 NULL, // local machine 688 processes, // object to enumerate 689 NULL, // pass in NULL buffers 690 &c_size, // and 0 length to get 691 instances, // required size 692 &i_size, // of the buffers in chars 693 PERF_DETAIL_WIZARD, // counter detail level 694 0); 695 696 // ok, now we have enough to enumerate all processes 697 if (pdh_fail(pdhStat)) { 698 /* printf("Could not enumerate processes (2) error=%d", pdhStat); */ 699 error = true; 700 goto end; 701 } 702 703 if (PdhOpenQuery_i(NULL, 0, &tmpQuery) != ERROR_SUCCESS) { 704 /* printf("Could not create temporary query"); */ 705 error = true; 706 goto end; 707 } 708 709 // Find our module name and use it to extract the instance name used by PDH 710 if (GetModuleFileName(NULL, module_name, MAX_PATH) >= MAX_PATH-1) { 711 /* printf("Module name truncated"); */ 712 error = true; 713 goto end; 714 } 715 instance_name = strrchr(module_name, '\\'); //drop path 716 instance_name++; //skip slash 717 dot_pos = strchr(instance_name, '.'); //drop .exe 718 dot_pos[0] = '\0'; 719 720 //now, fetch the counters. 721 for (tmp = instances; *tmp != 0 && !error; tmp = &tmp[lstrlen(tmp)+1]) { 722 HCOUNTER hc = NULL; 723 BOOL done = false; 724 725 // Skip until we find our own process name 726 if (strcmp(tmp, instance_name) != 0) { 727 continue; 728 } 729 730 // iterate over all instance indexes and try to find our own pid 731 for (i = 0; !done && !error; i++){ 732 PDH_STATUS res; 733 _snprintf(counter, sizeof(counter)-1, "\\%s(%s#%d)\\%s", processes, tmp, i, pid); 734 735 if (PdhAddCounter_i(tmpQuery, counter, 0, &hc) != ERROR_SUCCESS) { 736 /* printf("Failed to create process id query"); */ 737 error = true; 738 goto end; 739 } 740 741 res = PdhCollectQueryData_i(tmpQuery); 742 743 if (res == PDH_INVALID_HANDLE) { 744 /* printf("Failed to query process id"); */ 745 res = -1; 746 done = true; 747 } else if (res == PDH_NO_DATA) { 748 done = true; 749 } else { 750 PDH_FMT_COUNTERVALUE cv; 751 752 PdhGetFormattedCounterValue_i(hc, PDH_FMT_LONG, NULL, &cv); 753 /* 754 * This check seems to be needed for Win2k SMP boxes, since 755 * they for some reason don't return PDH_NO_DATA for non existing 756 * counters. 757 */ 758 if (cv.CStatus != PDH_CSTATUS_VALID_DATA) { 759 done = true; 760 } else if (cv.longValue == myPid) { 761 _snprintf(hotspotheader, sizeof(hotspotheader)-1, "\\%s(%s#%d)\0", processes, tmp, i); 762 PdhRemoveCounter_i(hc); 763 goto end; 764 } 765 } 766 PdhRemoveCounter_i(hc); 767 } 768 } 769 end: 770 if (instances != NULL) { 771 free(instances); 772 } 773 if (tmpQuery != NULL) { 774 PdhCloseQuery_i(tmpQuery); 775 } 776 if (error) { 777 return NULL; 778 } 779 return hotspotheader; 780 } 781 782 /** 783 * Returns the PDH string prefix identifying the HotSpot process. Use this prefix when getting 784 * counters from the PDH process object representing HotSpot. 785 * 786 * Note: this call may take some time to complete. 787 * 788 * @param ebuf error buffer. 789 * @param elen error buffer length. 790 * 791 * @return the header to be used when retrieving PDH counters from the HotSpot process. 792 * Will return NULL if the call failed. 793 */ 794 static char * 795 getProcessPDHHeader(void) { 796 static char *processHeader = NULL; 797 798 EnterCriticalSection(&processHeaderLock); { 799 if (processHeader == NULL) { 800 processHeader = initProcessPDHHeader(); 801 } 802 } LeaveCriticalSection(&processHeaderLock); 803 return processHeader; 804 } 805 806 int perfInit(void); 807 808 double 809 perfGetCPULoad(int which) 810 { 811 PDH_FMT_COUNTERVALUE cv; 812 HCOUNTER c; 813 814 if (perfInit() < 0) { 815 // warn? 816 return -1.0; 817 } 818 819 if (multiCounterCPULoad.query.query == NULL) { 820 // warn? 821 return -1.0; 822 } 823 824 if (which == -1) { 825 c = multiCounterCPULoad.counters[multiCounterCPULoad.noOfCounters - 1]; 826 } else { 827 if (which < multiCounterCPULoad.noOfCounters) { 828 c = multiCounterCPULoad.counters[which]; 829 } else { 830 return -1.0; 831 } 832 } 833 if (getPerformanceData(&multiCounterCPULoad.query, c, &cv, PDH_FMT_DOUBLE ) == CONFIG_SUCCESSFUL) { 834 return cv.doubleValue / 100; 835 } 836 return -1.0; 837 } 838 839 double 840 perfGetProcessLoad(void) 841 { 842 PDH_FMT_COUNTERVALUE cv; 843 844 if (perfInit() < 0) { 845 // warn? 846 return -1.0; 847 } 848 849 if (cntProcLoad.query.query == NULL) { 850 // warn? 851 return -1.0; 852 } 853 854 if (getPerformanceData(&cntProcLoad.query, cntProcLoad.counter, &cv, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == CONFIG_SUCCESSFUL) { 855 double d = cv.doubleValue / cpuFactor; 856 d = min(1, d); 857 d = max(0, d); 858 return d; 859 } 860 return -1.0; 861 } 862 863 /** 864 * Helper to initialize the PDH library. Loads the library and sets up the functions. 865 * Note that once loaded, we will never unload the PDH library. 866 * 867 * @return CONFIG_SUCCESSFUL if successful, negative on failure. 868 */ 869 int 870 perfInit(void) { 871 static HMODULE h; 872 static BOOL running, inited; 873 874 int error; 875 876 if (running) { 877 return CONFIG_SUCCESSFUL; 878 } 879 880 error = CONFIG_SUCCESSFUL; 881 882 // this is double checked locking again, but we try to bypass the worst by 883 // implicit membar at end of lock. 884 EnterCriticalSection(&initializationLock); { 885 if (!inited) { 886 char buf[64] = ""; 887 SYSTEM_INFO si; 888 889 // CMH. But windows will not care about our affinity when giving 890 // us measurements. Need the real, raw num cpus. 891 892 GetSystemInfo(&si); 893 num_cpus = si.dwNumberOfProcessors; 894 // Initialize the denominator for the jvm load calculations 895 cpuFactor = num_cpus * 100; 896 897 /** 898 * Do this dynamically, so we don't fail to start on systems without pdh. 899 */ 900 if ((h = LoadLibrary("pdh.dll")) == NULL) { 901 /* printf("Could not load pdh.dll (%d)", GetLastError()); */ 902 error = -2; 903 } else if (get_functions(h, buf, sizeof(buf)) < 0) { 904 FreeLibrary(h); 905 h = NULL; 906 error = -2; 907 /* printf("Failed to init pdh functions: %s.\n", buf); */ 908 } else { 909 if (initProcessorCounters() != 0) { 910 /* printf("Failed to init system load counters.\n"); */ 911 } else if (initProcLoadCounter() != 0) { 912 /* printf("Failed to init process load counter.\n"); */ 913 } else if (initProcSystemLoadCounter() != 0) { 914 /* printf("Failed to init process system load counter.\n"); */ 915 } else { 916 inited = true; 917 } 918 } 919 } 920 } LeaveCriticalSection(&initializationLock); 921 922 if (inited && error == CONFIG_SUCCESSFUL) { 923 running = true; 924 } 925 926 return error; 927 } 928 929 JNIEXPORT jdouble JNICALL 930 Java_com_sun_management_OperatingSystem_getSystemCpuLoad 931 (JNIEnv *env, jobject dummy) 932 { 933 return perfGetCPULoad(-1); 934 } 935 936 JNIEXPORT jdouble JNICALL 937 Java_com_sun_management_OperatingSystem_getProcessCpuLoad 938 (JNIEnv *env, jobject dummy) 939 { 940 return perfGetProcessLoad(); 941 }