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