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 }