jdk/src/windows/native/com/sun/management/OperatingSystem_md.c
changeset 22596 62542b8be764
parent 22595 aaa6b141196c
parent 21741 8cd632761233
child 22597 7515a991bb37
equal deleted inserted replaced
22595:aaa6b141196c 22596:62542b8be764
     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 }