--- a/jdk/src/java.management/windows/native/libmanagement/OperatingSystemImpl.c Thu May 07 20:49:48 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1363 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jlong.h"
-#include "jvm.h"
-#include "management.h"
-#include "sun_management_OperatingSystemImpl.h"
-
-#include <psapi.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include <malloc.h>
-#pragma warning (push,0)
-#include <windows.h>
-#pragma warning (pop)
-#include <stdio.h>
-#include <time.h>
-#include <stdint.h>
-#include <assert.h>
-
-/* Disable warnings due to broken header files from Microsoft... */
-#pragma warning(push, 3)
-#include <pdh.h>
-#include <pdhmsg.h>
-#include <process.h>
-#pragma warning(pop)
-
-typedef unsigned __int32 juint;
-typedef unsigned __int64 julong;
-
-static void set_low(jlong* value, jint low) {
- *value &= (jlong)0xffffffff << 32;
- *value |= (jlong)(julong)(juint)low;
-}
-
-static void set_high(jlong* value, jint high) {
- *value &= (jlong)(julong)(juint)0xffffffff;
- *value |= (jlong)high << 32;
-}
-
-static jlong jlong_from(jint h, jint l) {
- jlong result = 0; // initialization to avoid warning
- set_high(&result, h);
- set_low(&result, l);
- return result;
-}
-
-static HANDLE main_process;
-
-static void perfInit(void);
-
-JNIEXPORT void JNICALL
-Java_sun_management_OperatingSystemImpl_initialize0
- (JNIEnv *env, jclass cls)
-{
- main_process = GetCurrentProcess();
- perfInit();
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize0
- (JNIEnv *env, jobject mbean)
-{
- PROCESS_MEMORY_COUNTERS pmc;
- if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) {
- return (jlong)-1L;
- } else {
- return (jlong) pmc.PagefileUsage;
- }
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize0
- (JNIEnv *env, jobject mbean)
-{
- MEMORYSTATUSEX ms;
- ms.dwLength = sizeof(ms);
- GlobalMemoryStatusEx(&ms);
- return (jlong) ms.ullTotalPageFile;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize0
- (JNIEnv *env, jobject mbean)
-{
- MEMORYSTATUSEX ms;
- ms.dwLength = sizeof(ms);
- GlobalMemoryStatusEx(&ms);
- return (jlong) ms.ullAvailPageFile;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getProcessCpuTime0
- (JNIEnv *env, jobject mbean)
-{
-
- FILETIME process_creation_time, process_exit_time,
- process_user_time, process_kernel_time;
-
- // Using static variables declared above
- // Units are 100-ns intervals. Convert to ns.
- GetProcessTimes(main_process, &process_creation_time,
- &process_exit_time,
- &process_kernel_time, &process_user_time);
- return (jlong_from(process_user_time.dwHighDateTime,
- process_user_time.dwLowDateTime) +
- jlong_from(process_kernel_time.dwHighDateTime,
- process_kernel_time.dwLowDateTime)) * 100;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize0
- (JNIEnv *env, jobject mbean)
-{
- MEMORYSTATUSEX ms;
- ms.dwLength = sizeof(ms);
- GlobalMemoryStatusEx(&ms);
- return (jlong) ms.ullAvailPhys;
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize0
- (JNIEnv *env, jobject mbean)
-{
- MEMORYSTATUSEX ms;
- ms.dwLength = sizeof(ms);
- GlobalMemoryStatusEx(&ms);
- return (jlong) ms.ullTotalPhys;
-}
-
-/* Performance Data Helper API (PDH) support */
-
-typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(
- HQUERY hQuery,
- LPCSTR szFullCounterPath,
- DWORD dwUserData,
- HCOUNTER *phCounter
- );
-typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(
- LPCWSTR szDataSource,
- DWORD dwUserData,
- HQUERY *phQuery
- );
-typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(
- HQUERY hQuery
- );
-
-typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(
- LPCTSTR szDataSource,
- LPCTSTR szMachineName,
- LPCTSTR szObjectName,
- LPTSTR mszCounterList,
- LPDWORD pcchCounterListLength,
- LPTSTR mszInstanceList,
- LPDWORD pcchInstanceListLength,
- DWORD dwDetailLevel,
- DWORD dwFlags
- );
-typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(
- HCOUNTER hCounter
- );
-typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(
- LPCSTR szMachineName,
- DWORD dwNameIndex,
- LPSTR szNameBuffer,
- LPDWORD pcchNameBufferSize
- );
-typedef DWORD (WINAPI *PdhCloseQueryFunc)(
- HQUERY hQuery
- );
-
-typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(
- HCOUNTER hCounter,
- DWORD dwFormat,
- LPDWORD lpdwType,
- PPDH_FMT_COUNTERVALUE pValue
- );
-
-static PdhAddCounterFunc PdhAddCounter_i;
-static PdhOpenQueryFunc PdhOpenQuery_i;
-static PdhCloseQueryFunc PdhCloseQuery_i;
-static PdhCollectQueryDataFunc PdhCollectQueryData_i;
-static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;
-static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;
-static PdhRemoveCounterFunc PdhRemoveCounter_i;
-static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;
-
-/*
- * Struct for PDH queries.
- */
-typedef struct {
- HQUERY query;
- uint64_t lastUpdate; // Last time query was updated (ticks)
-} UpdateQueryS, *UpdateQueryP;
-
-// Min time between query updates (ticks)
-static const int MIN_UPDATE_INTERVAL = 500;
-
-/*
- * Struct for a PDH query with multiple counters.
- */
-typedef struct {
- UpdateQueryS query;
- HCOUNTER* counters;
- int noOfCounters;
-} MultipleCounterQueryS, *MultipleCounterQueryP;
-
-/*
- * Struct for a PDH query with a single counter.
- */
-typedef struct {
- UpdateQueryS query;
- HCOUNTER counter;
-} SingleCounterQueryS, *SingleCounterQueryP;
-
-
-typedef struct {
- CRITICAL_SECTION cs;
- DWORD owningThread;
- DWORD recursionCount;
-} PdhCriticalSectionS, *PdhCriticalSectionP;
-
-static PdhCriticalSectionS initializationLock;
-
-static void InitializePdhCriticalSection(PdhCriticalSectionP criticalSection) {
- assert(criticalSection);
-
- InitializeCriticalSection(&criticalSection->cs);
- criticalSection->owningThread = 0;
- criticalSection->recursionCount = 0;
-}
-
-static void EnterPdhCriticalSection(PdhCriticalSectionP criticalSection) {
- assert(criticalSection);
-
- EnterCriticalSection(&criticalSection->cs);
- criticalSection->recursionCount++;
- if (!criticalSection->owningThread) {
- criticalSection->owningThread = GetCurrentThreadId();
- }
-}
-
-static void LeavePdhCriticalSection(PdhCriticalSectionP criticalSection) {
- assert(criticalSection);
- assert(GetCurrentThreadId() == criticalSection->owningThread);
- assert(criticalSection->recursionCount >= 1);
-
- criticalSection->recursionCount--;
- if (!criticalSection->recursionCount) {
- criticalSection->owningThread = 0;
- }
- LeaveCriticalSection(&criticalSection->cs);
-}
-
-/*
- * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
- * http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
- * The index value for the base system counters and objects like processor,
- * process, thread, memory, and so forth are always the same irrespective
- * of the localized version of the operating system or service pack installed.
- * To find the correct index for an object or counter, inspect the registry key/value:
- * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
- */
-static const DWORD PDH_PROCESSOR_IDX = 238;
-static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
-static const DWORD PDH_PROCESS_IDX = 230;
-static const DWORD PDH_ID_PROCESS_IDX = 784;
-
-/* useful pdh fmt's */
-static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
-static const size_t OBJECT_COUNTER_FMT_LEN = 2;
-static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
-static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
-static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
-static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
-
-static const char* pdhProcessImageName = NULL; /* "java" */
-static char* pdhIDProcessCounterFmt = NULL; /* "\Process(java#%d)\ID Process" */
-
-static int numberOfJavaProcessesAtInitialization = 0;
-
-/*
- * Currently used CPU queries/counters and variables
- */
-static SingleCounterQueryP processTotalCPULoad = NULL;
-static MultipleCounterQueryP multiCounterCPULoad = NULL;
-static double cpuFactor = .0;
-static DWORD numCpus = 0;
-
-/*
- * Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.
- * Let's just ignore it, since we make sure we have enough buffer anyway.
- */
-static int
-pdhFail(PDH_STATUS pdhStat) {
- return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
-}
-
-static const char*
-allocateAndCopy(const char* const originalString) {
- size_t len;
- char* allocatedString;
-
- assert(originalString);
-
- len = strlen(originalString);
-
- allocatedString = malloc(len + 1);
-
- if (!allocatedString) {
- return NULL;
- }
-
- strncpy(allocatedString, originalString, len);
- allocatedString[len] = '\0';
-
- return allocatedString;
-}
-
-/*
- * Allocates memory into the supplied pointer and
- * fills it with the localized PDH artifact description, if indexed correctly.
- * Caller owns the memory from the point of returning from this function.
- *
- * @param index the PDH counter index as specified in the registry
- * @param ppBuffer pointer to a char*.
- * @return 0 if successful, negative on failure.
- */
-static int
-lookupNameByIndex(DWORD index, char** ppBuffer) {
- DWORD size;
-
- assert(ppBuffer);
-
- /* determine size needed */
- if (PdhLookupPerfNameByIndex_i(NULL, index, NULL, &size) != PDH_MORE_DATA) {
- /* invalid index? */
- return -1;
- }
-
- *ppBuffer = malloc((size_t)size);
-
- if (!*ppBuffer) {
- return -1;
- }
-
- if (PdhLookupPerfNameByIndex_i(NULL, index, *ppBuffer, &size) != ERROR_SUCCESS) {
- free(*ppBuffer);
- *ppBuffer = NULL;
- return -1;
- }
-
- /* windows vista does not null-terminate the string
- * (although the docs says it will) */
- (*ppBuffer)[size - 1] = '\0';
-
- return 0;
-}
-
-/*
-* Construct a fully qualified PDH path
-*
-* @param objectName a PDH Object string representation (required)
-* @param counterName a PDH Counter string representation (required)
-* @param imageName a process image name string, ex. "java" (opt)
-* @param instance an instance string, ex. "0", "1", ... (opt)
-* @return the fully qualified PDH path.
-*
-* Caller will own the returned malloc:ed string
-*/
-static const char*
-makeFullCounterPath(const char* const objectName,
- const char* const counterName,
- const char* const imageName,
- const char* const instance) {
-
- size_t fullCounterPathLen;
- char* fullCounterPath;
-
- assert(objectName);
- assert(counterName);
-
- fullCounterPathLen = strlen(objectName);
- fullCounterPathLen += strlen(counterName);
-
- if (imageName) {
- /*
- * For paths using the "Process" Object.
- *
- * Examples:
- * abstract: "\Process(imageName#instance)\Counter"
- * actual: "\Process(java#2)\ID Process"
- */
- fullCounterPathLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
- fullCounterPathLen += strlen(imageName);
-
- /*
- * imageName must be passed together with an associated
- * instance "number" ("0", "1", "2", ...).
- * This is required in order to create valid "Process" Object paths.
- *
- * Examples: "\Process(java#0)", \Process(java#1"), ...
- */
- assert(instance);
-
- fullCounterPathLen += strlen(instance);
-
- fullCounterPath = malloc(fullCounterPathLen + 1);
-
- if (!fullCounterPath) {
- return NULL;
- }
-
- _snprintf(fullCounterPath,
- fullCounterPathLen,
- PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
- objectName,
- imageName,
- instance,
- counterName);
- } else {
- if (instance) {
- /*
- * For paths where the Object has multiple instances.
- *
- * Examples:
- * abstract: "\Object(instance)\Counter"
- * actual: "\Processor(0)\% Privileged Time"
- */
- fullCounterPathLen += strlen(instance);
- fullCounterPathLen += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
- } else {
- /*
- * For "normal" paths.
- *
- * Examples:
- * abstract: "\Object\Counter"
- * actual: "\Memory\Available Mbytes"
- */
- fullCounterPathLen += OBJECT_COUNTER_FMT_LEN;
- }
-
- fullCounterPath = malloc(fullCounterPathLen + 1);
-
- if (!fullCounterPath) {
- return NULL;
- }
-
- if (instance) {
- _snprintf(fullCounterPath,
- fullCounterPathLen,
- OBJECT_WITH_INSTANCES_COUNTER_FMT,
- objectName,
- instance,
- counterName);
- } else {
- _snprintf(fullCounterPath,
- fullCounterPathLen,
- OBJECT_COUNTER_FMT,
- objectName,
- counterName);
- }
- }
-
- fullCounterPath[fullCounterPathLen] = '\0';
-
- return fullCounterPath;
-}
-
-/*
- * Resolves an index for a PDH artifact to
- * a localized, malloc:ed string representation.
- * Caller will own the returned malloc:ed string.
- *
- * @param pdhArtifactIndex PDH index
- * @return malloc:ed string representation
- * of the requested pdh artifact (localized).
- * NULL on failure.
- */
-static const char*
-getPdhLocalizedArtifact(DWORD pdhArtifactIndex) {
- char* pdhLocalizedArtifactString;
-
- if (lookupNameByIndex(pdhArtifactIndex,
- &pdhLocalizedArtifactString) != 0) {
- return NULL;
- }
-
- return pdhLocalizedArtifactString;
-}
-
-static void
-pdhCleanup(HQUERY* const query, HCOUNTER* const counter) {
- if (counter && *counter) {
- PdhRemoveCounter_i(*counter);
- *counter = NULL;
- }
- if (query && *query) {
- PdhCloseQuery_i(*query);
- *query = NULL;
- }
-}
-
-static void
-destroySingleCounter(SingleCounterQueryP counterQuery) {
- if (counterQuery) {
- pdhCleanup(&counterQuery->query.query, &counterQuery->counter);
- }
-}
-
-static void
-destroyMultiCounter(MultipleCounterQueryP multiCounterQuery) {
- int i;
- if (multiCounterQuery) {
- if (multiCounterQuery->counters) {
- for (i = 0; i < multiCounterQuery->noOfCounters; i++) {
- pdhCleanup(NULL, &multiCounterQuery->counters[i]);
- }
- free(multiCounterQuery->counters);
- multiCounterQuery->counters = NULL;
- }
- pdhCleanup(&multiCounterQuery->query.query, NULL);
- }
-}
-
-static int
-openQuery(HQUERY* const query) {
- assert(query);
-
- if (PdhOpenQuery_i(NULL, 0, query) != ERROR_SUCCESS) {
- return -1;
- }
-
- return 0;
-}
-
-static int
-addCounter(HQUERY query,
- const char* const fullCounterPath,
- HCOUNTER* const counter) {
-
- assert(fullCounterPath);
- assert(counter);
-
- if (PdhAddCounter_i(query,
- fullCounterPath,
- 0,
- counter) != ERROR_SUCCESS) {
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Sets up the supplied SingleCounterQuery to listen for the specified counter.
- *
- * @param counterQuery the counter query to set up.
- * @param fullCounterPath the string specifying the full path to the counter.
- * @returns 0 if successful, negative on failure.
- */
-static int
-initializeSingleCounterQuery(SingleCounterQueryP counterQuery,
- const char* const fullCounterPath) {
- assert(counterQuery);
- assert(fullCounterPath);
-
- if (openQuery(&counterQuery->query.query) == 0) {
- if (addCounter(counterQuery->query.query,
- fullCounterPath,
- &counterQuery->counter) == 0) {
- return 0;
- }
- }
-
- return -1;
-}
-
-/*
- * Sets up a SingleCounterQuery
- *
- * param counter the counter query to set up.
- * param localizedObject string representing the PDH object to query
- * param localizedCounter string representing the PDH counter to query
- * param processImageName if the counter query needs the process image name ("java")
- * param instance if the counter has instances, this is the instance ("\Processor(0)\")
- where 0 is the instance
- * param firstSampleOnInit for counters that need two queries to yield their values,
- the first query can be issued just after initialization
- *
- * @returns 0 if successful, negative on failure.
- */
-static int
-initializeSingleCounter(SingleCounterQueryP const counter,
- const char* const localizedObject,
- const char* const localizedCounter,
- const char* const processImageName,
- const char* const instance,
- BOOL firstSampleOnInit) {
- int retValue = -1;
-
- const char* fullCounterPath = makeFullCounterPath(localizedObject,
- localizedCounter,
- processImageName,
- instance);
-
- if (fullCounterPath) {
-
- assert(counter);
-
- if (initializeSingleCounterQuery(counter, fullCounterPath) == 0) {
- /*
- * According to the MSDN documentation, rate counters must be read twice:
- *
- * "Obtaining the value of rate counters such as Page faults/sec requires that
- * PdhCollectQueryData be called twice, with a specific time interval between
- * the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
- * implement the waiting period between the two calls to PdhCollectQueryData."
- *
- * Take the first sample here already to allow for the next (first) "real" sample
- * to succeed.
- */
- if (firstSampleOnInit) {
- PdhCollectQueryData_i(counter->query.query);
- }
-
- retValue = 0;
- }
- free((char*)fullCounterPath);
- }
-
- return retValue;
-}
-
-static void
-perfInit(void) {
- InitializePdhCriticalSection(&initializationLock);
-}
-
-static int
-getProcessID() {
- static int myPid = 0;
- if (0 == myPid) {
- myPid = _getpid();
- }
- return myPid;
-}
-
-/*
- * Working against the Process object and it's related counters is inherently problematic
- * when using the PDH API:
- *
- * For PDH, a process is not primarily identified by it's process id,
- * but with a sequential number, for example \Process(java#0), \Process(java#1), ....
- * The really bad part is that this list is reset as soon as one process exits:
- * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
- *
- * The PDH query api requires a process identifier to be submitted when registering
- * a query, but as soon as the list resets, the query is invalidated (since the name
- * changed).
- *
- * Solution:
- * The #number identifier for a Process query can only decrease after process creation.
- *
- * Therefore we create an array of counter queries for all process object instances
- * up to and including ourselves:
- *
- * Ex. we come in as third process instance (java#2), we then create and register
- * queries for the following Process object instances:
- * java#0, java#1, java#2
- *
- * currentQueryIndexForProcess() keeps track of the current "correct" query
- * (in order to keep this index valid when the list resets from underneath,
- * ensure to call getCurrentQueryIndexForProcess() before every query involving
- * Process object instance data).
- */
-static int
-currentQueryIndexForProcess(void) {
- HQUERY tmpQuery = NULL;
- HCOUNTER handleCounter = NULL;
- int retValue = -1;
-
- assert(pdhProcessImageName);
- assert(pdhIDProcessCounterFmt);
-
- if (openQuery(&tmpQuery) == 0) {
- int index;
-
- /* iterate over all instance indexes and try to find our own pid */
- for (index = 0; index < INT_MAX; ++index) {
- char fullIDProcessCounterPath[MAX_PATH];
- PDH_FMT_COUNTERVALUE counterValue;
- PDH_STATUS res;
-
- _snprintf(fullIDProcessCounterPath,
- MAX_PATH,
- pdhIDProcessCounterFmt,
- index);
-
- if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) {
- break;
- }
-
- res = PdhCollectQueryData_i(tmpQuery);
-
- if (PDH_INVALID_HANDLE == res || PDH_NO_DATA == res) {
- break;
- }
-
- PdhGetFormattedCounterValue_i(handleCounter,
- PDH_FMT_LONG,
- NULL,
- &counterValue);
- /*
- * This check seems to be needed for Win2k SMP boxes, since
- * they for some reason don't return PDH_NO_DATA for non existing
- * counters.
- */
- if (counterValue.CStatus != PDH_CSTATUS_VALID_DATA) {
- break;
- }
-
- if ((LONG)getProcessID() == counterValue.longValue) {
- retValue = index;
- break;
- }
- }
- }
-
- pdhCleanup(&tmpQuery, &handleCounter);
-
- return retValue;
-}
-
-/*
- * If successful, returns the #index corresponding to our PID
- * as resolved by the pdh query:
- * "\Process(java#index)\ID Process" (or localized equivalent)
- *
- * This function should be called before attempting to read
- * from any Process related counter(s), and the return value
- * is the index to be used for indexing an array of Process object query's:
- *
- * Example:
- * processTotalCPULoad[currentQueryIndex].query
- *
- * Returns -1 on failure.
- */
-static int
-getCurrentQueryIndexForProcess() {
- int currentQueryIndex = currentQueryIndexForProcess();
-
- assert(currentQueryIndex >= 0 &&
- currentQueryIndex < numberOfJavaProcessesAtInitialization);
-
- return currentQueryIndex;
-}
-
-/*
- * Returns the PDH string identifying the current process image name.
- * Use this name as a qualifier when getting counters from the PDH Process Object
- * representing your process.
-
- * Example:
- * "\Process(java#0)\Virtual Bytes" - where "java" is the PDH process
- * image name.
- *
- * Please note that the process image name is not necessarily "java",
- * hence the use of GetModuleFileName() to detect the process image name.
- *
- * @return the process image name to be used when retrieving
- * PDH counters from the current process. The caller will
- own the returned malloc:ed string. NULL if failure.
- */
-static const char*
-getPdhProcessImageName() {
- char moduleName[MAX_PATH];
- char* processImageName;
- char* dotPos;
-
- // Find our module name and use it to extract the image name used by PDH
- DWORD getmfnReturn = GetModuleFileName(NULL, moduleName, sizeof(moduleName));
-
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- return NULL;
- }
-
- if (getmfnReturn >= MAX_PATH || 0 == getmfnReturn) {
- return NULL;
- }
-
- processImageName = strrchr(moduleName, '\\'); //drop path
- processImageName++; //skip slash
- dotPos = strrchr(processImageName, '.'); //drop .exe
- dotPos[0] = '\0';
-
- return allocateAndCopy(processImageName);
-}
-
-/*
- * Sets up the supplied MultipleCounterQuery to check on the processors via PDH CPU counters.
- * TODO: Refactor and prettify as with the the SingleCounter queries
- * if more MultipleCounterQueries are discovered/needed.
- *
- * @param multiCounterCPULoad a pointer to a MultipleCounterQueryS, will be filled in with
- * the necessary info to check the PDH processor counters.
- * @return 0 if successful, negative on failure.
- */
-static int
-initializeMultipleCounterForCPUs(MultipleCounterQueryP multiCounterCPULoad) {
- DWORD cSize = 0;
- DWORD iSize = 0;
- DWORD pCount;
- DWORD index;
- char* processor = NULL; //'Processor' == PDH_PROCESSOR_IDX
- char* time = NULL; //'Time' == PDH_PROCESSOR_TIME_IDX
- char* instances = NULL;
- char* tmp;
- int retValue = -1;
- PDH_STATUS pdhStat;
-
- if (lookupNameByIndex(PDH_PROCESSOR_IDX, &processor) != 0) {
- goto end;
- }
-
- if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX, &time) != 0) {
- goto end;
- }
-
- //ok, now we have enough to enumerate all processors.
- pdhStat = PdhEnumObjectItems_i(
- NULL, // reserved
- NULL, // local machine
- processor, // object to enumerate
- NULL, // pass in NULL buffers
- &cSize, // and 0 length to get
- NULL, // required size
- &iSize, // of the buffers in chars
- PERF_DETAIL_WIZARD, // counter detail level
- 0);
-
- if (pdhFail(pdhStat)) {
- goto end;
- }
-
- instances = calloc(iSize, 1);
-
- if (!instances) {
- goto end;
- }
-
- cSize = 0;
-
- pdhStat = PdhEnumObjectItems_i(
- NULL, // reserved
- NULL, // local machine
- processor, // object to enumerate
- NULL, // pass in NULL buffers
- &cSize,
- instances, // now allocated to be filled in
- &iSize, // and size is known
- PERF_DETAIL_WIZARD, // counter detail level
- 0);
-
- if (pdhFail(pdhStat)) {
- goto end;
- }
-
- // enumerate the Processor instances ("\Processor(0)", "\Processor(1)", ..., "\Processor(_Total)")
- for (pCount = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], pCount++);
-
- assert(pCount == numCpus+1);
-
- //ok, we now have the number of Processor instances - allocate an HCOUNTER for each
- multiCounterCPULoad->counters = (HCOUNTER*)malloc(pCount * sizeof(HCOUNTER));
-
- if (!multiCounterCPULoad->counters) {
- goto end;
- }
-
- multiCounterCPULoad->noOfCounters = pCount;
-
- if (openQuery(&multiCounterCPULoad->query.query) != 0) {
- goto end;
- }
-
- // fetch instance and register its corresponding HCOUNTER with the query
- for (index = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], ++index) {
- const char* const fullCounterPath = makeFullCounterPath(processor, time, NULL, tmp);
-
- if (!fullCounterPath) {
- goto end;
- }
-
- retValue = addCounter(multiCounterCPULoad->query.query,
- fullCounterPath,
- &multiCounterCPULoad->counters[index]);
-
- free((char*)fullCounterPath);
-
- if (retValue != 0) {
- goto end;
- }
- }
-
- // Query once to initialize the counters which require at least two samples
- // (like the % CPU usage) to calculate correctly.
- PdhCollectQueryData_i(multiCounterCPULoad->query.query);
-
- end:
- if (processor) {
- free(processor);
- }
-
- if (time) {
- free(time);
- }
-
- if (instances) {
- free(instances);
- }
-
- return retValue;
-}
-
-/*
- * Dynamically sets up function pointers to the PDH library.
- *
- * @param h HMODULE for the PDH library
- * @return 0 on success, negative on failure.
- */
-static int
-bindPdhFunctionPointers(HMODULE h) {
- assert(h);
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- /* The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods */
- PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");
- PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");
- PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");
- PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");
- PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");
- PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");
- PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");
- PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");
-
- if (!PdhAddCounter_i || !PdhOpenQuery_i ||
- !PdhCloseQuery_i || !PdhCollectQueryData_i ||
- !PdhGetFormattedCounterValue_i || !PdhEnumObjectItems_i ||
- !PdhRemoveCounter_i || !PdhLookupPerfNameByIndex_i)
- {
- return -1;
- }
- return 0;
-}
-
-/*
- * Returns the counter value as a double for the specified query.
- * Will collect the query data and update the counter values as necessary.
- *
- * @param query the query to update (if needed).
- * @param c the counter to read.
- * @param value where to store the formatted value.
- * @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)
- * @return 0 if no error
- * -1 if PdhCollectQueryData fails
- * -2 if PdhGetFormattedCounterValue fails
- */
-static int
-getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {
- clock_t now = clock();
-
- /*
- * Need to limit how often we update the query
- * to minimize the Heisenberg effect.
- * (PDH behaves erratically if the counters are
- * queried too often, especially counters that
- * store and use values from two consecutive updates,
- * like cpu load.)
- */
- if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {
- if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {
- return -1;
- }
- query->lastUpdate = now;
- }
-
- if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {
- return -2;
- }
-
- return 0;
-}
-
-static int
-allocateAndInitializePdhConstants() {
- const char* pdhLocalizedProcessObject = NULL;
- const char* pdhLocalizedIDProcessCounter = NULL;
- size_t pdhIDProcessCounterFmtLen;
- int currentQueryIndex;
- int retValue = -1;
-
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- assert(!pdhProcessImageName);
- pdhProcessImageName = getPdhProcessImageName();
- if (!pdhProcessImageName) {
- goto end;
- }
-
- pdhLocalizedProcessObject = getPdhLocalizedArtifact(PDH_PROCESS_IDX);
- if (!pdhLocalizedProcessObject) {
- goto end;
- }
-
- pdhLocalizedIDProcessCounter = getPdhLocalizedArtifact(PDH_ID_PROCESS_IDX);
- if (!pdhLocalizedIDProcessCounter) {
- goto end;
- }
-
- assert(!pdhIDProcessCounterFmt);
-
- pdhIDProcessCounterFmtLen = strlen(pdhProcessImageName);
- pdhIDProcessCounterFmtLen += strlen(pdhLocalizedProcessObject);
- pdhIDProcessCounterFmtLen += strlen(pdhLocalizedIDProcessCounter);
- pdhIDProcessCounterFmtLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
- pdhIDProcessCounterFmtLen += 2; // "%d"
-
- assert(pdhIDProcessCounterFmtLen < MAX_PATH);
- pdhIDProcessCounterFmt = malloc(pdhIDProcessCounterFmtLen + 1);
- if (!pdhIDProcessCounterFmt) {
- goto end;
- }
-
- /* "\Process(java#%d)\ID Process" */
- _snprintf(pdhIDProcessCounterFmt,
- pdhIDProcessCounterFmtLen,
- PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
- pdhLocalizedProcessObject,
- pdhProcessImageName,
- "%d",
- pdhLocalizedIDProcessCounter);
-
- pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0';
-
- assert(0 == numberOfJavaProcessesAtInitialization);
- currentQueryIndex = currentQueryIndexForProcess();
- if (-1 == currentQueryIndex) {
- goto end;
- }
-
- numberOfJavaProcessesAtInitialization = currentQueryIndex + 1;
- assert(numberOfJavaProcessesAtInitialization >= 1);
-
- retValue = 0;
-
- end:
-
- if (pdhLocalizedProcessObject) {
- free((char*)pdhLocalizedProcessObject);
- }
-
- if (pdhLocalizedIDProcessCounter) {
- free((char*)pdhLocalizedIDProcessCounter);
- }
-
- return retValue;
-}
-
-static void
-deallocatePdhConstants() {
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- if (pdhProcessImageName) {
- free((char*)pdhProcessImageName);
- pdhProcessImageName = NULL;
- }
-
- if (pdhIDProcessCounterFmt) {
- free(pdhIDProcessCounterFmt);
- pdhIDProcessCounterFmt = NULL;
- }
-
- numberOfJavaProcessesAtInitialization = 0;
-}
-
-static int
-initializeCPUCounters() {
- SYSTEM_INFO si;
- char* localizedProcessObject;
- char* localizedProcessorTimeCounter;
- int i;
- int retValue = -1;
-
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- assert(0 == numCpus);
- GetSystemInfo(&si);
- numCpus = si.dwNumberOfProcessors;
- assert(numCpus >= 1);
-
- /* Initialize the denominator for the jvm load calculations */
- assert(.0 == cpuFactor);
- cpuFactor = numCpus * 100;
-
- if (lookupNameByIndex(PDH_PROCESS_IDX,
- &localizedProcessObject) == 0) {
-
- if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX,
- &localizedProcessorTimeCounter) == 0) {
-
- assert(processTotalCPULoad);
- assert(pdhProcessImageName);
-
- for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
- char instanceIndexBuffer[32];
- retValue = initializeSingleCounter(&processTotalCPULoad[i],
- localizedProcessObject,
- localizedProcessorTimeCounter,
- pdhProcessImageName,
- itoa(i, instanceIndexBuffer, 10),
- TRUE);
- if (retValue != 0) {
- break;
- }
- }
- free(localizedProcessorTimeCounter);
- }
- free(localizedProcessObject);
- }
-
- if (retValue != 0) {
- return -1;
- }
-
- assert(multiCounterCPULoad);
- return initializeMultipleCounterForCPUs(multiCounterCPULoad);
-}
-
-static void
-deallocateCPUCounters() {
- int i;
-
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- if (processTotalCPULoad) {
- for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {
- destroySingleCounter(&processTotalCPULoad[i]);
- }
- free(processTotalCPULoad);
- processTotalCPULoad = NULL;
- }
-
- if (multiCounterCPULoad) {
- destroyMultiCounter(multiCounterCPULoad);
- free(multiCounterCPULoad);
- multiCounterCPULoad = NULL;
- }
-
- cpuFactor = .0;
- numCpus = 0;
-}
-
-static void
-pdhInitErrorHandler(HMODULE h) {
- assert(GetCurrentThreadId() == initializationLock.owningThread);
-
- deallocatePdhConstants();
-
- if (h) {
- FreeLibrary(h);
- }
-}
-
-/*
- * Helper to initialize the PDH library, function pointers and constants.
- *
- * @return 0 if successful, negative on failure.
- */
-static int
-pdhInit() {
- static BOOL initialized = FALSE;
- int retValue;
-
- if (initialized) {
- return 0;
- }
-
- retValue = 0;
-
- EnterPdhCriticalSection(&initializationLock); {
- if (!initialized) {
- HMODULE h = NULL;
- if ((h = LoadLibrary("pdh.dll")) == NULL) {
- retValue = -1;
- } else if (bindPdhFunctionPointers(h) < 0) {
- retValue = -1;
- } else if (allocateAndInitializePdhConstants() < 0) {
- retValue = -1;
- }
-
- if (0 == retValue) {
- initialized = TRUE;
- } else {
- pdhInitErrorHandler(h);
- }
- }
- } LeavePdhCriticalSection(&initializationLock);
-
- return retValue;
-}
-
-static int
-allocateCPUCounters() {
- assert(GetCurrentThreadId() == initializationLock.owningThread);
- assert(numberOfJavaProcessesAtInitialization >= 1);
- assert(!processTotalCPULoad);
- assert(!multiCounterCPULoad);
-
- /*
- * Create an array of Process object queries, for each instance
- * up to and including our own (java#0, java#1, java#2, ...).
- */
- processTotalCPULoad = calloc(numberOfJavaProcessesAtInitialization,
- sizeof(SingleCounterQueryS));
-
- if (!processTotalCPULoad) {
- return -1;
- }
-
- multiCounterCPULoad = calloc(1, sizeof(MultipleCounterQueryS));
-
- if (!multiCounterCPULoad) {
- return -1;
- }
-
- return 0;
-}
-
-static int
-initializePdhCPUCounters() {
- static BOOL initialized = FALSE;
- int retValue;
-
- if (initialized) {
- return 0;
- }
-
- retValue = 0;
-
- EnterPdhCriticalSection(&initializationLock); {
- if (!initialized) {
- if (pdhInit() < 0) {
- retValue = -1;
- } else if (allocateCPUCounters() < 0) {
- retValue = -1;
- } else if (initializeCPUCounters() < 0) {
- retValue = -1;
- }
-
- if (0 == retValue) {
- initialized = TRUE;
- } else {
- deallocateCPUCounters();
- }
- }
- } LeavePdhCriticalSection(&initializationLock);
-
- return retValue;
-}
-
-static int
-perfCPUInit() {
- return initializePdhCPUCounters();
-}
-
-static double
-perfGetProcessCPULoad() {
- PDH_FMT_COUNTERVALUE cv;
- int currentQueryIndex;
-
- if (perfCPUInit() < 0) {
- // warn?
- return -1.0;
- }
-
- currentQueryIndex = getCurrentQueryIndexForProcess();
-
- if (getPerformanceData(&processTotalCPULoad[currentQueryIndex].query,
- processTotalCPULoad[currentQueryIndex].counter,
- &cv,
- PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == 0) {
- double d = cv.doubleValue / cpuFactor;
- d = min(1, d);
- d = max(0, d);
- return d;
- }
- return -1.0;
-}
-
-static double
-perfGetCPULoad(int which) {
- PDH_FMT_COUNTERVALUE cv;
- HCOUNTER c;
-
- if (perfCPUInit() < 0) {
- // warn?
- return -1.0;
- }
-
- if (-1 == which) {
- c = multiCounterCPULoad->counters[multiCounterCPULoad->noOfCounters - 1];
- } else {
- if (which < multiCounterCPULoad->noOfCounters) {
- c = multiCounterCPULoad->counters[which];
- } else {
- return -1.0;
- }
- }
- if (getPerformanceData(&multiCounterCPULoad->query, c, &cv, PDH_FMT_DOUBLE ) == 0) {
- return cv.doubleValue / 100;
- }
- return -1.0;
-}
-
-JNIEXPORT jdouble JNICALL
-Java_sun_management_OperatingSystemImpl_getSystemCpuLoad0
-(JNIEnv *env, jobject dummy)
-{
- return perfGetCPULoad(-1);
-}
-
-JNIEXPORT jdouble JNICALL
-Java_sun_management_OperatingSystemImpl_getProcessCpuLoad0
-(JNIEnv *env, jobject dummy)
-{
- return perfGetProcessCPULoad();
-}