1 /*
   2  * Copyright (c) 2003, 2013, 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 "sun_management_OperatingSystemImpl.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 static void set_low(jlong* value, jint low) {
  57     *value &= (jlong)0xffffffff << 32;
  58     *value |= (jlong)(julong)(juint)low;
  59 }
  60 
  61 static void set_high(jlong* value, jint high) {
  62     *value &= (jlong)(julong)(juint)0xffffffff;
  63     *value |= (jlong)high       << 32;
  64 }
  65 
  66 static jlong jlong_from(jint h, jint l) {
  67     jlong result = 0; // initialization to avoid warning
  68     set_high(&result, h);
  69     set_low(&result,  l);
  70     return result;
  71 }
  72 
  73 static HANDLE main_process;
  74 
  75 static void perfInit(void);
  76 
  77 JNIEXPORT void JNICALL
  78 Java_sun_management_OperatingSystemImpl_initialize
  79   (JNIEnv *env, jclass cls)
  80 {
  81     main_process = GetCurrentProcess();
  82     perfInit();
  83 }
  84 
  85 JNIEXPORT jlong JNICALL
  86 Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize0
  87   (JNIEnv *env, jobject mbean)
  88 {
  89     PROCESS_MEMORY_COUNTERS pmc;
  90     if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) {
  91         return (jlong)-1L;
  92     } else {
  93         return (jlong) pmc.PagefileUsage;
  94     }
  95 }
  96 
  97 JNIEXPORT jlong JNICALL
  98 Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize
  99   (JNIEnv *env, jobject mbean)
 100 {
 101     MEMORYSTATUSEX ms;
 102     ms.dwLength = sizeof(ms);
 103     GlobalMemoryStatusEx(&ms);
 104     return (jlong) ms.ullTotalPageFile;
 105 }
 106 
 107 JNIEXPORT jlong JNICALL
 108 Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize
 109   (JNIEnv *env, jobject mbean)
 110 {
 111     MEMORYSTATUSEX ms;
 112     ms.dwLength = sizeof(ms);
 113     GlobalMemoryStatusEx(&ms);
 114     return (jlong) ms.ullAvailPageFile;
 115 }
 116 
 117 JNIEXPORT jlong JNICALL
 118 Java_sun_management_OperatingSystemImpl_getProcessCpuTime
 119   (JNIEnv *env, jobject mbean)
 120 {
 121 
 122     FILETIME process_creation_time, process_exit_time,
 123              process_user_time, process_kernel_time;
 124 
 125     // Using static variables declared above
 126     // Units are 100-ns intervals.  Convert to ns.
 127     GetProcessTimes(main_process, &process_creation_time,
 128                     &process_exit_time,
 129                     &process_kernel_time, &process_user_time);
 130     return (jlong_from(process_user_time.dwHighDateTime,
 131                         process_user_time.dwLowDateTime) +
 132             jlong_from(process_kernel_time.dwHighDateTime,
 133                         process_kernel_time.dwLowDateTime)) * 100;
 134 }
 135 
 136 JNIEXPORT jlong JNICALL
 137 Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize
 138   (JNIEnv *env, jobject mbean)
 139 {
 140     MEMORYSTATUSEX ms;
 141     ms.dwLength = sizeof(ms);
 142     GlobalMemoryStatusEx(&ms);
 143     return (jlong) ms.ullAvailPhys;
 144 }
 145 
 146 JNIEXPORT jlong JNICALL
 147 Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize
 148   (JNIEnv *env, jobject mbean)
 149 {
 150     MEMORYSTATUSEX ms;
 151     ms.dwLength = sizeof(ms);
 152     GlobalMemoryStatusEx(&ms);
 153     return (jlong) ms.ullTotalPhys;
 154 }
 155 
 156 /* Performance Data Helper API (PDH) support */
 157 
 158 typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(
 159                            HQUERY      hQuery,
 160                            LPCSTR      szFullCounterPath,
 161                            DWORD       dwUserData,
 162                            HCOUNTER    *phCounter
 163                            );
 164 typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(
 165                            LPCWSTR     szDataSource,
 166                            DWORD       dwUserData,
 167                            HQUERY      *phQuery
 168                            );
 169 typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(
 170                            HQUERY      hQuery
 171                            );
 172 
 173 typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(
 174                            LPCTSTR     szDataSource,
 175                            LPCTSTR     szMachineName,
 176                            LPCTSTR     szObjectName,
 177                            LPTSTR      mszCounterList,
 178                            LPDWORD     pcchCounterListLength,
 179                            LPTSTR      mszInstanceList,
 180                            LPDWORD     pcchInstanceListLength,
 181                            DWORD       dwDetailLevel,
 182                            DWORD       dwFlags
 183                            );
 184 typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(
 185                            HCOUNTER   hCounter
 186                            );
 187 typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(
 188                            LPCSTR     szMachineName,
 189                            DWORD      dwNameIndex,
 190                            LPSTR      szNameBuffer,
 191                            LPDWORD    pcchNameBufferSize
 192                            );
 193 typedef DWORD (WINAPI *PdhCloseQueryFunc)(
 194                       HQUERY      hQuery
 195                       );
 196 
 197 typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(
 198                       HCOUNTER                hCounter,
 199                       DWORD                   dwFormat,
 200                       LPDWORD                 lpdwType,
 201                       PPDH_FMT_COUNTERVALUE   pValue
 202                       );
 203 
 204 static PdhAddCounterFunc PdhAddCounter_i;
 205 static PdhOpenQueryFunc PdhOpenQuery_i;
 206 static PdhCloseQueryFunc PdhCloseQuery_i;
 207 static PdhCollectQueryDataFunc PdhCollectQueryData_i;
 208 static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;
 209 static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;
 210 static PdhRemoveCounterFunc PdhRemoveCounter_i;
 211 static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;
 212 
 213 /*
 214  * Struct for PDH queries.
 215  */
 216 typedef struct {
 217     HQUERY      query;
 218     uint64_t    lastUpdate; // Last time query was updated (ticks)
 219 } UpdateQueryS, *UpdateQueryP;
 220 
 221 // Min time between query updates (ticks)
 222 static const int MIN_UPDATE_INTERVAL = 500;
 223 
 224 /*
 225  * Struct for a PDH query with multiple counters.
 226  */
 227 typedef struct {
 228     UpdateQueryS  query;
 229     HCOUNTER*     counters;
 230     int           noOfCounters;
 231 } MultipleCounterQueryS, *MultipleCounterQueryP;
 232 
 233 /*
 234  * Struct for a PDH query with a single counter.
 235  */
 236 typedef struct {
 237     UpdateQueryS  query;
 238     HCOUNTER      counter;
 239 } SingleCounterQueryS, *SingleCounterQueryP;
 240 
 241 
 242 typedef struct {
 243     CRITICAL_SECTION cs;
 244     DWORD owningThread;
 245     DWORD recursionCount;
 246 } PdhCriticalSectionS, *PdhCriticalSectionP;
 247 
 248 static PdhCriticalSectionS initializationLock;
 249 
 250 static void InitializePdhCriticalSection(PdhCriticalSectionP criticalSection) {
 251     assert(criticalSection);
 252 
 253     InitializeCriticalSection(&criticalSection->cs);
 254     criticalSection->owningThread = 0;
 255     criticalSection->recursionCount = 0;
 256 }
 257 
 258 static void EnterPdhCriticalSection(PdhCriticalSectionP criticalSection) {
 259     assert(criticalSection);
 260 
 261     EnterCriticalSection(&criticalSection->cs);
 262     criticalSection->recursionCount++;
 263     if (!criticalSection->owningThread) {
 264         criticalSection->owningThread = GetCurrentThreadId();
 265     }
 266 }
 267 
 268 static void LeavePdhCriticalSection(PdhCriticalSectionP criticalSection) {
 269     assert(criticalSection);
 270     assert(GetCurrentThreadId() == criticalSection->owningThread);
 271     assert(criticalSection->recursionCount >= 1);
 272 
 273     criticalSection->recursionCount--;
 274     if (!criticalSection->recursionCount) {
 275         criticalSection->owningThread = 0;
 276     }
 277     LeaveCriticalSection(&criticalSection->cs);
 278 }
 279 
 280 /*
 281  * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
 282  *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
 283  * The index value for the base system counters and objects like processor,
 284  * process, thread, memory, and so forth are always the same irrespective
 285  * of the localized version of the operating system or service pack installed.
 286  * To find the correct index for an object or counter, inspect the registry key/value:
 287  * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
 288  */
 289 static const DWORD PDH_PROCESSOR_IDX = 238;
 290 static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
 291 static const DWORD PDH_PROCESS_IDX = 230;
 292 static const DWORD PDH_ID_PROCESS_IDX = 784;
 293 
 294 /* useful pdh fmt's */
 295 static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
 296 static const size_t OBJECT_COUNTER_FMT_LEN = 2;
 297 static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
 298 static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
 299 static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
 300 static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
 301 
 302 static const char* pdhProcessImageName = NULL; /* "java" */
 303 static char* pdhIDProcessCounterFmt = NULL;    /* "\Process(java#%d)\ID Process" */
 304 
 305 static int numberOfJavaProcessesAtInitialization = 0;
 306 
 307 /*
 308  * Currently used CPU queries/counters and variables
 309  */
 310 static SingleCounterQueryP processTotalCPULoad = NULL;
 311 static MultipleCounterQueryP multiCounterCPULoad = NULL;
 312 static double cpuFactor = .0;
 313 static DWORD  numCpus = 0;
 314 
 315 /*
 316  * Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.
 317  * Let's just ignore it, since we make sure we have enough buffer anyway.
 318  */
 319 static int
 320 pdhFail(PDH_STATUS pdhStat) {
 321     return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
 322 }
 323 
 324 static const char*
 325 allocateAndCopy(const char* const originalString) {
 326     size_t len;
 327     char* allocatedString;
 328 
 329     assert(originalString);
 330 
 331     len = strlen(originalString);
 332 
 333     allocatedString = malloc(len + 1);
 334 
 335     if (!allocatedString) {
 336         return NULL;
 337     }
 338 
 339     strncpy(allocatedString, originalString, len);
 340     allocatedString[len] = '\0';
 341 
 342     return allocatedString;
 343 }
 344 
 345 /*
 346  * Allocates memory into the supplied pointer and
 347  * fills it with the localized PDH artifact description, if indexed correctly.
 348  * Caller owns the memory from the point of returning from this function.
 349  *
 350  * @param index    the PDH counter index as specified in the registry
 351  * @param ppBuffer pointer to a char*.
 352  * @return         0 if successful, negative on failure.
 353  */
 354 static int
 355 lookupNameByIndex(DWORD index, char** ppBuffer) {
 356     DWORD size;
 357 
 358     assert(ppBuffer);
 359 
 360     /* determine size needed */
 361     if (PdhLookupPerfNameByIndex_i(NULL, index, NULL, &size) != PDH_MORE_DATA) {
 362       /* invalid index? */
 363       return -1;
 364     }
 365 
 366     *ppBuffer = malloc((size_t)size);
 367 
 368     if (!*ppBuffer) {
 369         return -1;
 370     }
 371 
 372     if (PdhLookupPerfNameByIndex_i(NULL, index, *ppBuffer, &size) != ERROR_SUCCESS) {
 373         free(*ppBuffer);
 374         *ppBuffer = NULL;
 375         return -1;
 376     }
 377 
 378     /* windows vista does not null-terminate the string
 379      * (although the docs says it will) */
 380     (*ppBuffer)[size - 1] = '\0';
 381 
 382     return 0;
 383 }
 384 
 385 /*
 386 * Construct a fully qualified PDH path
 387 *
 388 * @param objectName   a PDH Object string representation (required)
 389 * @param counterName  a PDH Counter string representation (required)
 390 * @param imageName    a process image name string, ex. "java" (opt)
 391 * @param instance     an instance string, ex. "0", "1", ... (opt)
 392 * @return             the fully qualified PDH path.
 393 *
 394 * Caller will own the returned malloc:ed string
 395 */
 396 static const char*
 397 makeFullCounterPath(const char* const objectName,
 398                     const char* const counterName,
 399                     const char* const imageName,
 400                     const char* const instance) {
 401 
 402     size_t fullCounterPathLen;
 403     char* fullCounterPath;
 404 
 405     assert(objectName);
 406     assert(counterName);
 407 
 408     fullCounterPathLen = strlen(objectName);
 409     fullCounterPathLen += strlen(counterName);
 410 
 411     if (imageName) {
 412         /*
 413          * For paths using the "Process" Object.
 414          *
 415          * Examples:
 416          * abstract: "\Process(imageName#instance)\Counter"
 417          * actual:   "\Process(java#2)\ID Process"
 418          */
 419         fullCounterPathLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
 420         fullCounterPathLen += strlen(imageName);
 421 
 422         /*
 423          * imageName must be passed together with an associated
 424          * instance "number" ("0", "1", "2", ...).
 425          * This is required in order to create valid "Process" Object paths.
 426          *
 427          * Examples: "\Process(java#0)", \Process(java#1"), ...
 428          */
 429         assert(instance);
 430 
 431         fullCounterPathLen += strlen(instance);
 432 
 433         fullCounterPath = malloc(fullCounterPathLen + 1);
 434 
 435         if (!fullCounterPath) {
 436             return NULL;
 437         }
 438 
 439         _snprintf(fullCounterPath,
 440                   fullCounterPathLen,
 441                   PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
 442                   objectName,
 443                   imageName,
 444                   instance,
 445                   counterName);
 446     } else {
 447         if (instance) {
 448             /*
 449              * For paths where the Object has multiple instances.
 450              *
 451              * Examples:
 452              * abstract: "\Object(instance)\Counter"
 453              * actual:   "\Processor(0)\% Privileged Time"
 454              */
 455             fullCounterPathLen += strlen(instance);
 456             fullCounterPathLen += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
 457         } else {
 458             /*
 459              * For "normal" paths.
 460              *
 461              * Examples:
 462              * abstract: "\Object\Counter"
 463              * actual:   "\Memory\Available Mbytes"
 464              */
 465             fullCounterPathLen += OBJECT_COUNTER_FMT_LEN;
 466         }
 467 
 468         fullCounterPath = malloc(fullCounterPathLen + 1);
 469 
 470         if (!fullCounterPath) {
 471             return NULL;
 472         }
 473 
 474         if (instance) {
 475             _snprintf(fullCounterPath,
 476                       fullCounterPathLen,
 477                       OBJECT_WITH_INSTANCES_COUNTER_FMT,
 478                       objectName,
 479                       instance,
 480                       counterName);
 481         } else {
 482             _snprintf(fullCounterPath,
 483                       fullCounterPathLen,
 484                       OBJECT_COUNTER_FMT,
 485                       objectName,
 486                       counterName);
 487         }
 488     }
 489 
 490     fullCounterPath[fullCounterPathLen] = '\0';
 491 
 492     return fullCounterPath;
 493 }
 494 
 495 /*
 496  * Resolves an index for a PDH artifact to
 497  * a localized, malloc:ed string representation.
 498  * Caller will own the returned malloc:ed string.
 499  *
 500  * @param pdhArtifactIndex  PDH index
 501  * @return                  malloc:ed string representation
 502  *                          of the requested pdh artifact (localized).
 503  *                          NULL on failure.
 504  */
 505 static const char*
 506 getPdhLocalizedArtifact(DWORD pdhArtifactIndex) {
 507     char* pdhLocalizedArtifactString;
 508 
 509     if (lookupNameByIndex(pdhArtifactIndex,
 510                           &pdhLocalizedArtifactString) != 0) {
 511         return NULL;
 512     }
 513 
 514     return pdhLocalizedArtifactString;
 515 }
 516 
 517 static void
 518 pdhCleanup(HQUERY* const query, HCOUNTER* const counter) {
 519     if (counter && *counter) {
 520         PdhRemoveCounter_i(*counter);
 521         *counter = NULL;
 522     }
 523     if (query && *query) {
 524         PdhCloseQuery_i(*query);
 525         *query = NULL;
 526     }
 527 }
 528 
 529 static void
 530 destroySingleCounter(SingleCounterQueryP counterQuery) {
 531     if (counterQuery) {
 532         pdhCleanup(&counterQuery->query.query, &counterQuery->counter);
 533     }
 534 }
 535 
 536 static void
 537 destroyMultiCounter(MultipleCounterQueryP multiCounterQuery) {
 538     int i;
 539     if (multiCounterQuery) {
 540         if (multiCounterQuery->counters) {
 541             for (i = 0; i < multiCounterQuery->noOfCounters; i++) {
 542                 pdhCleanup(NULL, &multiCounterQuery->counters[i]);
 543             }
 544             free(multiCounterQuery->counters);
 545             multiCounterQuery->counters = NULL;
 546         }
 547         pdhCleanup(&multiCounterQuery->query.query, NULL);
 548     }
 549 }
 550 
 551 static int
 552 openQuery(HQUERY* const query) {
 553     assert(query);
 554 
 555     if (PdhOpenQuery_i(NULL, 0, query) != ERROR_SUCCESS) {
 556         return -1;
 557     }
 558 
 559     return 0;
 560 }
 561 
 562 static int
 563 addCounter(HQUERY query,
 564            const char* const fullCounterPath,
 565            HCOUNTER* const counter) {
 566 
 567     assert(fullCounterPath);
 568     assert(counter);
 569 
 570     if (PdhAddCounter_i(query,
 571                         fullCounterPath,
 572                         0,
 573                         counter) != ERROR_SUCCESS) {
 574         return -1;
 575     }
 576 
 577     return 0;
 578 }
 579 
 580 /*
 581  * Sets up the supplied SingleCounterQuery to listen for the specified counter.
 582  *
 583  * @param counterQuery       the counter query to set up.
 584  * @param fullCounterPath    the string specifying the full path to the counter.
 585  * @returns                  0 if successful, negative on failure.
 586  */
 587 static int
 588 initializeSingleCounterQuery(SingleCounterQueryP counterQuery,
 589                              const char* const fullCounterPath) {
 590     assert(counterQuery);
 591     assert(fullCounterPath);
 592 
 593     if (openQuery(&counterQuery->query.query) == 0) {
 594         if (addCounter(counterQuery->query.query,
 595                        fullCounterPath,
 596                        &counterQuery->counter) == 0) {
 597             return 0;
 598         }
 599     }
 600 
 601     return -1;
 602 }
 603 
 604 /*
 605  * Sets up a SingleCounterQuery
 606  *
 607  * param counter             the counter query to set up.
 608  * param localizedObject     string representing the PDH object to query
 609  * param localizedCounter    string representing the PDH counter to query
 610  * param processImageName    if the counter query needs the process image name ("java")
 611  * param instance            if the counter has instances, this is the instance ("\Processor(0)\")
 612                                  where 0 is the instance
 613  * param firstSampleOnInit   for counters that need two queries to yield their values,
 614                                  the first query can be issued just after initialization
 615  *
 616  * @returns                   0 if successful, negative on failure.
 617  */
 618 static int
 619 initializeSingleCounter(SingleCounterQueryP const counter,
 620                         const char* const localizedObject,
 621                         const char* const localizedCounter,
 622                         const char* const processImageName,
 623                         const char* const instance,
 624                         BOOL firstSampleOnInit) {
 625     int retValue = -1;
 626 
 627     const char* fullCounterPath = makeFullCounterPath(localizedObject,
 628                                                       localizedCounter,
 629                                                       processImageName,
 630                                                       instance);
 631 
 632     if (fullCounterPath) {
 633 
 634         assert(counter);
 635 
 636         if (initializeSingleCounterQuery(counter, fullCounterPath) == 0) {
 637             /*
 638              * According to the MSDN documentation, rate counters must be read twice:
 639              *
 640              * "Obtaining the value of rate counters such as Page faults/sec requires that
 641              *  PdhCollectQueryData be called twice, with a specific time interval between
 642              *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
 643              *  implement the waiting period between the two calls to PdhCollectQueryData."
 644              *
 645              *  Take the first sample here already to allow for the next (first) "real" sample
 646              *  to succeed.
 647              */
 648             if (firstSampleOnInit) {
 649                 PdhCollectQueryData_i(counter->query.query);
 650             }
 651 
 652             retValue = 0;
 653         }
 654         free((char*)fullCounterPath);
 655     }
 656 
 657     return retValue;
 658 }
 659 
 660 static void
 661 perfInit(void) {
 662     InitializePdhCriticalSection(&initializationLock);
 663 }
 664 
 665 static int
 666 getProcessID() {
 667     static int myPid = 0;
 668     if (0 == myPid) {
 669         myPid = _getpid();
 670     }
 671     return myPid;
 672 }
 673 
 674 /*
 675  * Working against the Process object and it's related counters is inherently problematic
 676  * when using the PDH API:
 677  *
 678  * For PDH, a process is not primarily identified by it's process id,
 679  * but with a sequential number, for example \Process(java#0), \Process(java#1), ....
 680  * The really bad part is that this list is reset as soon as one process exits:
 681  * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
 682  *
 683  * The PDH query api requires a process identifier to be submitted when registering
 684  * a query, but as soon as the list resets, the query is invalidated (since the name
 685  * changed).
 686  *
 687  * Solution:
 688  * The #number identifier for a Process query can only decrease after process creation.
 689  *
 690  * Therefore we create an array of counter queries for all process object instances
 691  * up to and including ourselves:
 692  *
 693  * Ex. we come in as third process instance (java#2), we then create and register
 694  * queries for the following Process object instances:
 695  * java#0, java#1, java#2
 696  *
 697  * currentQueryIndexForProcess() keeps track of the current "correct" query
 698  * (in order to keep this index valid when the list resets from underneath,
 699  * ensure to call getCurrentQueryIndexForProcess() before every query involving
 700  * Process object instance data).
 701  */
 702 static int
 703 currentQueryIndexForProcess(void) {
 704     HQUERY tmpQuery = NULL;
 705     HCOUNTER handleCounter = NULL;
 706     int retValue = -1;
 707 
 708     assert(pdhProcessImageName);
 709     assert(pdhIDProcessCounterFmt);
 710 
 711     if (openQuery(&tmpQuery) == 0) {
 712         int index;
 713 
 714         /* iterate over all instance indexes and try to find our own pid */
 715         for (index = 0; index < INT_MAX; ++index) {
 716             char fullIDProcessCounterPath[MAX_PATH];
 717             PDH_FMT_COUNTERVALUE counterValue;
 718             PDH_STATUS res;
 719 
 720             _snprintf(fullIDProcessCounterPath,
 721                       MAX_PATH,
 722                       pdhIDProcessCounterFmt,
 723                       index);
 724 
 725             if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) {
 726                 break;
 727             }
 728 
 729             res = PdhCollectQueryData_i(tmpQuery);
 730 
 731             if (PDH_INVALID_HANDLE == res || PDH_NO_DATA == res) {
 732                 break;
 733             }
 734 
 735             PdhGetFormattedCounterValue_i(handleCounter,
 736                                           PDH_FMT_LONG,
 737                                           NULL,
 738                                           &counterValue);
 739             /*
 740              * This check seems to be needed for Win2k SMP boxes, since
 741              * they for some reason don't return PDH_NO_DATA for non existing
 742              * counters.
 743              */
 744             if (counterValue.CStatus != PDH_CSTATUS_VALID_DATA) {
 745                 break;
 746             }
 747 
 748             if ((LONG)getProcessID() == counterValue.longValue) {
 749                 retValue = index;
 750                 break;
 751             }
 752         }
 753     }
 754 
 755     pdhCleanup(&tmpQuery, &handleCounter);
 756 
 757     return retValue;
 758 }
 759 
 760 /*
 761  * If successful, returns the #index corresponding to our PID
 762  * as resolved by the pdh query:
 763  * "\Process(java#index)\ID Process" (or localized equivalent)
 764  *
 765  * This function should be called before attempting to read
 766  * from any Process related counter(s), and the return value
 767  * is the index to be used for indexing an array of Process object query's:
 768  *
 769  * Example:
 770  * processTotalCPULoad[currentQueryIndex].query
 771  *
 772  * Returns -1 on failure.
 773  */
 774 static int
 775 getCurrentQueryIndexForProcess() {
 776     int currentQueryIndex = currentQueryIndexForProcess();
 777 
 778     assert(currentQueryIndex >= 0 &&
 779            currentQueryIndex < numberOfJavaProcessesAtInitialization);
 780 
 781     return currentQueryIndex;
 782 }
 783 
 784 /*
 785  * Returns the PDH string identifying the current process image name.
 786  * Use this name as a qualifier when getting counters from the PDH Process Object
 787  * representing your process.
 788 
 789  * Example:
 790  * "\Process(java#0)\Virtual Bytes" - where "java" is the PDH process
 791  * image name.
 792  *
 793  * Please note that the process image name is not necessarily "java",
 794  * hence the use of GetModuleFileName() to detect the process image name.
 795  *
 796  * @return   the process image name to be used when retrieving
 797  *           PDH counters from the current process. The caller will
 798              own the returned malloc:ed string. NULL if failure.
 799  */
 800 static const char*
 801 getPdhProcessImageName() {
 802     char moduleName[MAX_PATH];
 803     char* processImageName;
 804     char* dotPos;
 805 
 806     // Find our module name and use it to extract the image name used by PDH
 807     DWORD getmfnReturn = GetModuleFileName(NULL, moduleName, sizeof(moduleName));
 808 
 809     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 810         return NULL;
 811     }
 812 
 813     if (getmfnReturn >= MAX_PATH || 0 == getmfnReturn) {
 814         return NULL;
 815     }
 816 
 817     processImageName = strrchr(moduleName, '\\'); //drop path
 818     processImageName++;                           //skip slash
 819     dotPos = strrchr(processImageName, '.');      //drop .exe
 820     dotPos[0] = '\0';
 821 
 822     return allocateAndCopy(processImageName);
 823 }
 824 
 825 /*
 826  * Sets up the supplied MultipleCounterQuery to check on the processors via PDH CPU counters.
 827  * TODO: Refactor and prettify as with the the SingleCounter queries
 828  * if more MultipleCounterQueries are discovered/needed.
 829  *
 830  * @param multiCounterCPULoad  a pointer to a MultipleCounterQueryS, will be filled in with
 831  *                             the necessary info to check the PDH processor counters.
 832  * @return                     0 if successful, negative on failure.
 833  */
 834 static int
 835 initializeMultipleCounterForCPUs(MultipleCounterQueryP multiCounterCPULoad) {
 836     DWORD cSize = 0;
 837     DWORD iSize = 0;
 838     DWORD pCount;
 839     DWORD index;
 840     char* processor = NULL; //'Processor' == PDH_PROCESSOR_IDX
 841     char* time = NULL;      //'Time' == PDH_PROCESSOR_TIME_IDX
 842     char* instances = NULL;
 843     char* tmp;
 844     int   retValue = -1;
 845     PDH_STATUS pdhStat;
 846 
 847     if (lookupNameByIndex(PDH_PROCESSOR_IDX, &processor) != 0) {
 848         goto end;
 849     }
 850 
 851     if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX, &time) != 0) {
 852         goto end;
 853     }
 854 
 855     //ok, now we have enough to enumerate all processors.
 856     pdhStat = PdhEnumObjectItems_i(
 857                                    NULL, // reserved
 858                                    NULL, // local machine
 859                                    processor, // object to enumerate
 860                                    NULL, // pass in NULL buffers
 861                                    &cSize, // and 0 length to get
 862                                    NULL, // required size
 863                                    &iSize, // of the buffers in chars
 864                                    PERF_DETAIL_WIZARD, // counter detail level
 865                                    0);
 866 
 867     if (pdhFail(pdhStat)) {
 868         goto end;
 869     }
 870 
 871     instances = calloc(iSize, 1);
 872 
 873     if (!instances) {
 874         goto end;
 875     }
 876 
 877     cSize = 0;
 878 
 879     pdhStat = PdhEnumObjectItems_i(
 880                                    NULL, // reserved
 881                                    NULL, // local machine
 882                                    processor, // object to enumerate
 883                                    NULL, // pass in NULL buffers
 884                                    &cSize,
 885                                    instances, // now allocated to be filled in
 886                                    &iSize, // and size is known
 887                                    PERF_DETAIL_WIZARD, // counter detail level
 888                                    0);
 889 
 890     if (pdhFail(pdhStat)) {
 891         goto end;
 892     }
 893 
 894     // enumerate the Processor instances ("\Processor(0)", "\Processor(1)", ..., "\Processor(_Total)")
 895     for (pCount = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], pCount++);
 896 
 897     assert(pCount == numCpus+1);
 898 
 899     //ok, we now have the number of Processor instances - allocate an HCOUNTER for each
 900     multiCounterCPULoad->counters = (HCOUNTER*)malloc(pCount * sizeof(HCOUNTER));
 901 
 902     if (!multiCounterCPULoad->counters) {
 903         goto end;
 904     }
 905 
 906     multiCounterCPULoad->noOfCounters = pCount;
 907 
 908     if (openQuery(&multiCounterCPULoad->query.query) != 0) {
 909         goto end;
 910     }
 911 
 912     // fetch instance and register its corresponding HCOUNTER with the query
 913     for (index = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], ++index) {
 914         const char* const fullCounterPath = makeFullCounterPath(processor, time, NULL, tmp);
 915 
 916         if (!fullCounterPath) {
 917             goto end;
 918         }
 919 
 920         retValue = addCounter(multiCounterCPULoad->query.query,
 921                               fullCounterPath,
 922                               &multiCounterCPULoad->counters[index]);
 923 
 924         free((char*)fullCounterPath);
 925 
 926         if (retValue != 0) {
 927             goto end;
 928         }
 929     }
 930 
 931     // Query once to initialize the counters which require at least two samples
 932     // (like the % CPU usage) to calculate correctly.
 933     PdhCollectQueryData_i(multiCounterCPULoad->query.query);
 934 
 935   end:
 936     if (processor) {
 937         free(processor);
 938     }
 939 
 940     if (time) {
 941         free(time);
 942     }
 943 
 944     if (instances) {
 945         free(instances);
 946     }
 947 
 948     return retValue;
 949 }
 950 
 951 /*
 952  * Dynamically sets up function pointers to the PDH library.
 953  *
 954  * @param h  HMODULE for the PDH library
 955  * @return   0 on success, negative on failure.
 956  */
 957 static int
 958 bindPdhFunctionPointers(HMODULE h) {
 959     assert(h);
 960     assert(GetCurrentThreadId() == initializationLock.owningThread);
 961 
 962     /* The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods */
 963     PdhAddCounter_i         = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");
 964     PdhOpenQuery_i         = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");
 965     PdhCloseQuery_i         = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");
 966     PdhCollectQueryData_i     = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");
 967     PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");
 968     PdhEnumObjectItems_i         = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");
 969     PdhRemoveCounter_i         = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");
 970     PdhLookupPerfNameByIndex_i     = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");
 971 
 972     if (!PdhAddCounter_i || !PdhOpenQuery_i ||
 973         !PdhCloseQuery_i || !PdhCollectQueryData_i ||
 974         !PdhGetFormattedCounterValue_i || !PdhEnumObjectItems_i ||
 975         !PdhRemoveCounter_i || !PdhLookupPerfNameByIndex_i)
 976     {
 977         return -1;
 978     }
 979     return 0;
 980 }
 981 
 982 /*
 983  * Returns the counter value as a double for the specified query.
 984  * Will collect the query data and update the counter values as necessary.
 985  *
 986  * @param query       the query to update (if needed).
 987  * @param c           the counter to read.
 988  * @param value       where to store the formatted value.
 989  * @param format      the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)
 990  * @return            0 if no error
 991  *                    -1 if PdhCollectQueryData fails
 992  *                    -2 if PdhGetFormattedCounterValue fails
 993  */
 994 static int
 995 getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {
 996     clock_t now = clock();
 997 
 998     /*
 999      * Need to limit how often we update the query
1000      * to minimize the Heisenberg effect.
1001      * (PDH behaves erratically if the counters are
1002      * queried too often, especially counters that
1003      * store and use values from two consecutive updates,
1004      * like cpu load.)
1005      */
1006     if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {
1007         if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {
1008             return -1;
1009         }
1010         query->lastUpdate = now;
1011     }
1012 
1013     if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {
1014         return -2;
1015     }
1016 
1017     return 0;
1018 }
1019 
1020 static int
1021 allocateAndInitializePdhConstants() {
1022     const char* pdhLocalizedProcessObject = NULL;
1023     const char* pdhLocalizedIDProcessCounter = NULL;
1024     size_t pdhIDProcessCounterFmtLen;
1025     int currentQueryIndex;
1026     int retValue = -1;
1027 
1028     assert(GetCurrentThreadId() == initializationLock.owningThread);
1029 
1030     assert(!pdhProcessImageName);
1031     pdhProcessImageName = getPdhProcessImageName();
1032     if (!pdhProcessImageName) {
1033         goto end;
1034     }
1035 
1036     pdhLocalizedProcessObject = getPdhLocalizedArtifact(PDH_PROCESS_IDX);
1037     if (!pdhLocalizedProcessObject) {
1038         goto end;
1039     }
1040 
1041     pdhLocalizedIDProcessCounter = getPdhLocalizedArtifact(PDH_ID_PROCESS_IDX);
1042     if (!pdhLocalizedIDProcessCounter) {
1043         goto end;
1044     }
1045 
1046     assert(!pdhIDProcessCounterFmt);
1047 
1048     pdhIDProcessCounterFmtLen = strlen(pdhProcessImageName);
1049     pdhIDProcessCounterFmtLen += strlen(pdhLocalizedProcessObject);
1050     pdhIDProcessCounterFmtLen += strlen(pdhLocalizedIDProcessCounter);
1051     pdhIDProcessCounterFmtLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
1052     pdhIDProcessCounterFmtLen += 2; // "%d"
1053 
1054     assert(pdhIDProcessCounterFmtLen < MAX_PATH);
1055     pdhIDProcessCounterFmt = malloc(pdhIDProcessCounterFmtLen + 1);
1056     if (!pdhIDProcessCounterFmt) {
1057         goto end;
1058     }
1059 
1060     /* "\Process(java#%d)\ID Process" */
1061     _snprintf(pdhIDProcessCounterFmt,
1062               pdhIDProcessCounterFmtLen,
1063               PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
1064               pdhLocalizedProcessObject,
1065               pdhProcessImageName,
1066               "%d",
1067               pdhLocalizedIDProcessCounter);
1068 
1069     pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0';
1070 
1071     assert(0 == numberOfJavaProcessesAtInitialization);
1072     currentQueryIndex = currentQueryIndexForProcess();
1073     if (-1 == currentQueryIndex) {
1074         goto end;
1075     }
1076 
1077     numberOfJavaProcessesAtInitialization = currentQueryIndex + 1;
1078     assert(numberOfJavaProcessesAtInitialization >= 1);
1079 
1080     retValue = 0;
1081 
1082   end:
1083 
1084     if (pdhLocalizedProcessObject) {
1085         free((char*)pdhLocalizedProcessObject);
1086     }
1087 
1088     if (pdhLocalizedIDProcessCounter) {
1089         free((char*)pdhLocalizedIDProcessCounter);
1090     }
1091 
1092     return retValue;
1093 }
1094 
1095 static void
1096 deallocatePdhConstants() {
1097     assert(GetCurrentThreadId() == initializationLock.owningThread);
1098 
1099     if (pdhProcessImageName) {
1100         free((char*)pdhProcessImageName);
1101         pdhProcessImageName = NULL;
1102     }
1103 
1104     if (pdhIDProcessCounterFmt) {
1105       free(pdhIDProcessCounterFmt);
1106       pdhIDProcessCounterFmt = NULL;
1107     }
1108 
1109     numberOfJavaProcessesAtInitialization = 0;
1110 }
1111 
1112 static int
1113 initializeCPUCounters() {
1114     SYSTEM_INFO si;
1115     char* localizedProcessObject;
1116     char* localizedProcessorTimeCounter;
1117     int i;
1118     int retValue = -1;
1119 
1120     assert(GetCurrentThreadId() == initializationLock.owningThread);
1121 
1122     assert(0 == numCpus);
1123     GetSystemInfo(&si);
1124     numCpus = si.dwNumberOfProcessors;
1125     assert(numCpus >= 1);
1126 
1127     /* Initialize the denominator for the jvm load calculations */
1128     assert(.0 == cpuFactor);
1129     cpuFactor = numCpus * 100;
1130 
1131     if (lookupNameByIndex(PDH_PROCESS_IDX,
1132                           &localizedProcessObject) == 0) {
1133 
1134         if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX,
1135                               &localizedProcessorTimeCounter) == 0) {
1136 
1137             assert(processTotalCPULoad);
1138             assert(pdhProcessImageName);
1139 
1140             for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
1141                 char instanceIndexBuffer[32];
1142                 retValue = initializeSingleCounter(&processTotalCPULoad[i],
1143                                                    localizedProcessObject,
1144                                                    localizedProcessorTimeCounter,
1145                                                    pdhProcessImageName,
1146                                                    itoa(i, instanceIndexBuffer, 10),
1147                                                    TRUE);
1148                 if (retValue != 0) {
1149                     break;
1150                 }
1151             }
1152             free(localizedProcessorTimeCounter);
1153         }
1154         free(localizedProcessObject);
1155     }
1156 
1157     if (retValue != 0) {
1158         return -1;
1159     }
1160 
1161     assert(multiCounterCPULoad);
1162     return initializeMultipleCounterForCPUs(multiCounterCPULoad);
1163 }
1164 
1165 static void
1166 deallocateCPUCounters() {
1167     int i;
1168 
1169     assert(GetCurrentThreadId() == initializationLock.owningThread);
1170 
1171     if (processTotalCPULoad) {
1172         for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
1173             destroySingleCounter(&processTotalCPULoad[i]);
1174         }
1175         free(processTotalCPULoad);
1176         processTotalCPULoad = NULL;
1177     }
1178 
1179     if (multiCounterCPULoad) {
1180         destroyMultiCounter(multiCounterCPULoad);
1181         free(multiCounterCPULoad);
1182         multiCounterCPULoad = NULL;
1183     }
1184 
1185     cpuFactor = .0;
1186     numCpus = 0;
1187 }
1188 
1189 static void
1190 pdhInitErrorHandler(HMODULE h) {
1191     assert(GetCurrentThreadId() == initializationLock.owningThread);
1192 
1193     deallocatePdhConstants();
1194 
1195     if (h) {
1196         FreeLibrary(h);
1197     }
1198 }
1199 
1200 /*
1201  * Helper to initialize the PDH library, function pointers and constants.
1202  *
1203  * @return  0 if successful, negative on failure.
1204  */
1205 static int
1206 pdhInit() {
1207     static BOOL initialized = FALSE;
1208     int retValue;
1209 
1210     if (initialized) {
1211         return 0;
1212     }
1213 
1214     retValue = 0;
1215 
1216     EnterPdhCriticalSection(&initializationLock); {
1217         if (!initialized) {
1218             HMODULE h = NULL;
1219             if ((h = LoadLibrary("pdh.dll")) == NULL) {
1220                 retValue = -1;
1221             } else if (bindPdhFunctionPointers(h) < 0) {
1222                 retValue = -1;
1223             } else if (allocateAndInitializePdhConstants() < 0) {
1224                 retValue = -1;
1225             }
1226 
1227             if (0 == retValue) {
1228                 initialized = TRUE;
1229             } else {
1230                 pdhInitErrorHandler(h);
1231             }
1232         }
1233     } LeavePdhCriticalSection(&initializationLock);
1234 
1235     return retValue;
1236 }
1237 
1238 static int
1239 allocateCPUCounters() {
1240     assert(GetCurrentThreadId() == initializationLock.owningThread);
1241     assert(numberOfJavaProcessesAtInitialization >= 1);
1242     assert(!processTotalCPULoad);
1243     assert(!multiCounterCPULoad);
1244 
1245     /*
1246      * Create an array of Process object queries, for each instance
1247      * up to and including our own (java#0, java#1, java#2, ...).
1248      */
1249     processTotalCPULoad = calloc(numberOfJavaProcessesAtInitialization,
1250                                  sizeof(SingleCounterQueryS));
1251 
1252     if (!processTotalCPULoad) {
1253         return -1;
1254     }
1255 
1256     multiCounterCPULoad = calloc(1, sizeof(MultipleCounterQueryS));
1257 
1258     if (!multiCounterCPULoad) {
1259         return -1;
1260     }
1261 
1262     return 0;
1263 }
1264 
1265 static int
1266 initializePdhCPUCounters() {
1267     static BOOL initialized = FALSE;
1268     int retValue;
1269 
1270     if (initialized) {
1271         return 0;
1272     }
1273 
1274     retValue = 0;
1275 
1276     EnterPdhCriticalSection(&initializationLock); {
1277         if (!initialized) {
1278             if (pdhInit() < 0) {
1279                 retValue = -1;
1280             }  else if (allocateCPUCounters() < 0) {
1281                 retValue = -1;
1282             } else if (initializeCPUCounters() < 0) {
1283                 retValue = -1;
1284             }
1285 
1286             if (0 == retValue) {
1287                 initialized = TRUE;
1288             } else {
1289               deallocateCPUCounters();
1290             }
1291         }
1292     } LeavePdhCriticalSection(&initializationLock);
1293 
1294     return retValue;
1295 }
1296 
1297 static int
1298 perfCPUInit() {
1299     return initializePdhCPUCounters();
1300 }
1301 
1302 static double
1303 perfGetProcessCPULoad() {
1304     PDH_FMT_COUNTERVALUE cv;
1305     int currentQueryIndex;
1306 
1307     if (perfCPUInit() < 0) {
1308         // warn?
1309         return -1.0;
1310     }
1311 
1312     currentQueryIndex = getCurrentQueryIndexForProcess();
1313 
1314     if (getPerformanceData(&processTotalCPULoad[currentQueryIndex].query,
1315                            processTotalCPULoad[currentQueryIndex].counter,
1316                            &cv,
1317                            PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == 0) {
1318         double d = cv.doubleValue / cpuFactor;
1319         d = min(1, d);
1320         d = max(0, d);
1321         return d;
1322     }
1323     return -1.0;
1324 }
1325 
1326 static double
1327 perfGetCPULoad(int which) {
1328     PDH_FMT_COUNTERVALUE cv;
1329     HCOUNTER c;
1330 
1331     if (perfCPUInit() < 0) {
1332         // warn?
1333         return -1.0;
1334     }
1335 
1336     if (-1 == which) {
1337         c = multiCounterCPULoad->counters[multiCounterCPULoad->noOfCounters - 1];
1338     } else {
1339         if (which < multiCounterCPULoad->noOfCounters) {
1340             c = multiCounterCPULoad->counters[which];
1341         } else {
1342             return -1.0;
1343         }
1344     }
1345     if (getPerformanceData(&multiCounterCPULoad->query, c, &cv, PDH_FMT_DOUBLE ) == 0) {
1346         return cv.doubleValue / 100;
1347     }
1348     return -1.0;
1349 }
1350 
1351 JNIEXPORT jdouble JNICALL
1352 Java_sun_management_OperatingSystemImpl_getSystemCpuLoad
1353 (JNIEnv *env, jobject dummy)
1354 {
1355     return perfGetCPULoad(-1);
1356 }
1357 
1358 JNIEXPORT jdouble JNICALL
1359 Java_sun_management_OperatingSystemImpl_getProcessCpuLoad
1360 (JNIEnv *env, jobject dummy)
1361 {
1362     return perfGetProcessCPULoad();
1363 }