Print this page
rev 10261 : 8056049: getProcessCpuLoad() stops working in one process when a different process exits
Reviewed-by: ctornqvi

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