Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/management/OperatingSystemImpl.c
32287 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "jni.h"26#include "jni_util.h"27#include "jlong.h"28#include "jvm.h"29#include "management.h"30#include "sun_management_OperatingSystemImpl.h"3132#include <psapi.h>33#include <errno.h>34#include <stdlib.h>3536#include <malloc.h>37#pragma warning (push,0)38#include <windows.h>39#pragma warning (pop)40#include <stdio.h>41#include <time.h>42#include <stdint.h>43#include <assert.h>4445/* Disable warnings due to broken header files from Microsoft... */46#pragma warning(push, 3)47#include <pdh.h>48#include <pdhmsg.h>49#include <process.h>50#pragma warning(pop)5152typedef unsigned __int32 juint;53typedef unsigned __int64 julong;5455static void set_low(jlong* value, jint low) {56*value &= (jlong)0xffffffff << 32;57*value |= (jlong)(julong)(juint)low;58}5960static void set_high(jlong* value, jint high) {61*value &= (jlong)(julong)(juint)0xffffffff;62*value |= (jlong)high << 32;63}6465static jlong jlong_from(jint h, jint l) {66jlong result = 0; // initialization to avoid warning67set_high(&result, h);68set_low(&result, l);69return result;70}7172static HANDLE main_process;7374static void perfInit(void);7576JNIEXPORT void JNICALL77Java_sun_management_OperatingSystemImpl_initialize78(JNIEnv *env, jclass cls)79{80main_process = GetCurrentProcess();81perfInit();82}8384JNIEXPORT jlong JNICALL85Java_sun_management_OperatingSystemImpl_getCommittedVirtualMemorySize086(JNIEnv *env, jobject mbean)87{88PROCESS_MEMORY_COUNTERS pmc;89if (GetProcessMemoryInfo(main_process, &pmc, sizeof(PROCESS_MEMORY_COUNTERS)) == 0) {90return (jlong)-1L;91} else {92return (jlong) pmc.PagefileUsage;93}94}9596JNIEXPORT jlong JNICALL97Java_sun_management_OperatingSystemImpl_getTotalSwapSpaceSize98(JNIEnv *env, jobject mbean)99{100MEMORYSTATUSEX ms;101ms.dwLength = sizeof(ms);102GlobalMemoryStatusEx(&ms);103return (jlong) ms.ullTotalPageFile;104}105106JNIEXPORT jlong JNICALL107Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize108(JNIEnv *env, jobject mbean)109{110MEMORYSTATUSEX ms;111ms.dwLength = sizeof(ms);112GlobalMemoryStatusEx(&ms);113return (jlong) ms.ullAvailPageFile;114}115116JNIEXPORT jlong JNICALL117Java_sun_management_OperatingSystemImpl_getProcessCpuTime118(JNIEnv *env, jobject mbean)119{120121FILETIME process_creation_time, process_exit_time,122process_user_time, process_kernel_time;123124// Using static variables declared above125// Units are 100-ns intervals. Convert to ns.126GetProcessTimes(main_process, &process_creation_time,127&process_exit_time,128&process_kernel_time, &process_user_time);129return (jlong_from(process_user_time.dwHighDateTime,130process_user_time.dwLowDateTime) +131jlong_from(process_kernel_time.dwHighDateTime,132process_kernel_time.dwLowDateTime)) * 100;133}134135JNIEXPORT jlong JNICALL136Java_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize137(JNIEnv *env, jobject mbean)138{139MEMORYSTATUSEX ms;140ms.dwLength = sizeof(ms);141GlobalMemoryStatusEx(&ms);142return (jlong) ms.ullAvailPhys;143}144145JNIEXPORT jlong JNICALL146Java_sun_management_OperatingSystemImpl_getTotalPhysicalMemorySize147(JNIEnv *env, jobject mbean)148{149MEMORYSTATUSEX ms;150ms.dwLength = sizeof(ms);151GlobalMemoryStatusEx(&ms);152return (jlong) ms.ullTotalPhys;153}154155/* Performance Data Helper API (PDH) support */156157typedef PDH_STATUS (WINAPI *PdhAddCounterFunc)(158HQUERY hQuery,159LPCSTR szFullCounterPath,160DWORD dwUserData,161HCOUNTER *phCounter162);163typedef PDH_STATUS (WINAPI *PdhOpenQueryFunc)(164LPCWSTR szDataSource,165DWORD dwUserData,166HQUERY *phQuery167);168typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)(169HQUERY hQuery170);171172typedef PDH_STATUS (WINAPI *PdhEnumObjectItemsFunc)(173LPCTSTR szDataSource,174LPCTSTR szMachineName,175LPCTSTR szObjectName,176LPTSTR mszCounterList,177LPDWORD pcchCounterListLength,178LPTSTR mszInstanceList,179LPDWORD pcchInstanceListLength,180DWORD dwDetailLevel,181DWORD dwFlags182);183typedef PDH_STATUS (WINAPI *PdhRemoveCounterFunc)(184HCOUNTER hCounter185);186typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndexFunc)(187LPCSTR szMachineName,188DWORD dwNameIndex,189LPSTR szNameBuffer,190LPDWORD pcchNameBufferSize191);192typedef DWORD (WINAPI *PdhCloseQueryFunc)(193HQUERY hQuery194);195196typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)(197HCOUNTER hCounter,198DWORD dwFormat,199LPDWORD lpdwType,200PPDH_FMT_COUNTERVALUE pValue201);202203static PdhAddCounterFunc PdhAddCounter_i;204static PdhOpenQueryFunc PdhOpenQuery_i;205static PdhCloseQueryFunc PdhCloseQuery_i;206static PdhCollectQueryDataFunc PdhCollectQueryData_i;207static PdhGetFormattedCounterValueFunc PdhGetFormattedCounterValue_i;208static PdhEnumObjectItemsFunc PdhEnumObjectItems_i;209static PdhRemoveCounterFunc PdhRemoveCounter_i;210static PdhLookupPerfNameByIndexFunc PdhLookupPerfNameByIndex_i;211212/*213* Struct for PDH queries.214*/215typedef struct {216HQUERY query;217uint64_t lastUpdate; // Last time query was updated (ticks)218} UpdateQueryS, *UpdateQueryP;219220// Min time between query updates (ticks)221static const int MIN_UPDATE_INTERVAL = 500;222223/*224* Struct for a PDH query with multiple counters.225*/226typedef struct {227UpdateQueryS query;228HCOUNTER* counters;229int noOfCounters;230} MultipleCounterQueryS, *MultipleCounterQueryP;231232/*233* Struct for a PDH query with a single counter.234*/235typedef struct {236UpdateQueryS query;237HCOUNTER counter;238} SingleCounterQueryS, *SingleCounterQueryP;239240241typedef struct {242CRITICAL_SECTION cs;243DWORD owningThread;244DWORD recursionCount;245} PdhCriticalSectionS, *PdhCriticalSectionP;246247static PdhCriticalSectionS initializationLock;248249static void InitializePdhCriticalSection(PdhCriticalSectionP criticalSection) {250assert(criticalSection);251252InitializeCriticalSection(&criticalSection->cs);253criticalSection->owningThread = 0;254criticalSection->recursionCount = 0;255}256257static void EnterPdhCriticalSection(PdhCriticalSectionP criticalSection) {258assert(criticalSection);259260EnterCriticalSection(&criticalSection->cs);261criticalSection->recursionCount++;262if (!criticalSection->owningThread) {263criticalSection->owningThread = GetCurrentThreadId();264}265}266267static void LeavePdhCriticalSection(PdhCriticalSectionP criticalSection) {268assert(criticalSection);269assert(GetCurrentThreadId() == criticalSection->owningThread);270assert(criticalSection->recursionCount >= 1);271272criticalSection->recursionCount--;273if (!criticalSection->recursionCount) {274criticalSection->owningThread = 0;275}276LeaveCriticalSection(&criticalSection->cs);277}278279/*280* INFO: Using PDH APIs Correctly in a Localized Language (Q287159)281* http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159282* The index value for the base system counters and objects like processor,283* process, thread, memory, and so forth are always the same irrespective284* of the localized version of the operating system or service pack installed.285* To find the correct index for an object or counter, inspect the registry key/value:286* [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]287*/288static const DWORD PDH_PROCESSOR_IDX = 238;289static const DWORD PDH_PROCESSOR_TIME_IDX = 6;290static const DWORD PDH_PROCESS_IDX = 230;291static const DWORD PDH_ID_PROCESS_IDX = 784;292293/* useful pdh fmt's */294static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";295static const size_t OBJECT_COUNTER_FMT_LEN = 2;296static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";297static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;298static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";299static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;300301static const char* pdhProcessImageName = NULL; /* "java" */302static char* pdhIDProcessCounterFmt = NULL; /* "\Process(java#%d)\ID Process" */303304static int numberOfJavaProcessesAtInitialization = 0;305306/*307* Currently used CPU queries/counters and variables308*/309static SingleCounterQueryP processTotalCPULoad = NULL;310static MultipleCounterQueryP multiCounterCPULoad = NULL;311static double cpuFactor = .0;312static DWORD numCpus = 0;313314/*315* Seems WinXP PDH returns PDH_MORE_DATA whenever we send in a NULL buffer.316* Let's just ignore it, since we make sure we have enough buffer anyway.317*/318static int319pdhFail(PDH_STATUS pdhStat) {320return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;321}322323static const char*324allocateAndCopy(const char* const originalString) {325size_t len;326char* allocatedString;327328assert(originalString);329330len = strlen(originalString);331332allocatedString = malloc(len + 1);333334if (!allocatedString) {335return NULL;336}337338strncpy(allocatedString, originalString, len);339allocatedString[len] = '\0';340341return allocatedString;342}343344/*345* Allocates memory into the supplied pointer and346* fills it with the localized PDH artifact description, if indexed correctly.347* Caller owns the memory from the point of returning from this function.348*349* @param index the PDH counter index as specified in the registry350* @param ppBuffer pointer to a char*.351* @return 0 if successful, negative on failure.352*/353static int354lookupNameByIndex(DWORD index, char** ppBuffer) {355DWORD size;356357assert(ppBuffer);358359/* determine size needed */360if (PdhLookupPerfNameByIndex_i(NULL, index, NULL, &size) != PDH_MORE_DATA) {361/* invalid index? */362return -1;363}364365*ppBuffer = malloc((size_t)size);366367if (!*ppBuffer) {368return -1;369}370371if (PdhLookupPerfNameByIndex_i(NULL, index, *ppBuffer, &size) != ERROR_SUCCESS) {372free(*ppBuffer);373*ppBuffer = NULL;374return -1;375}376377/* windows vista does not null-terminate the string378* (although the docs says it will) */379(*ppBuffer)[size - 1] = '\0';380381return 0;382}383384/*385* Construct a fully qualified PDH path386*387* @param objectName a PDH Object string representation (required)388* @param counterName a PDH Counter string representation (required)389* @param imageName a process image name string, ex. "java" (opt)390* @param instance an instance string, ex. "0", "1", ... (opt)391* @return the fully qualified PDH path.392*393* Caller will own the returned malloc:ed string394*/395static const char*396makeFullCounterPath(const char* const objectName,397const char* const counterName,398const char* const imageName,399const char* const instance) {400401size_t fullCounterPathLen;402char* fullCounterPath;403404assert(objectName);405assert(counterName);406407fullCounterPathLen = strlen(objectName);408fullCounterPathLen += strlen(counterName);409410if (imageName) {411/*412* For paths using the "Process" Object.413*414* Examples:415* abstract: "\Process(imageName#instance)\Counter"416* actual: "\Process(java#2)\ID Process"417*/418fullCounterPathLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;419fullCounterPathLen += strlen(imageName);420421/*422* imageName must be passed together with an associated423* instance "number" ("0", "1", "2", ...).424* This is required in order to create valid "Process" Object paths.425*426* Examples: "\Process(java#0)", \Process(java#1"), ...427*/428assert(instance);429430fullCounterPathLen += strlen(instance);431432fullCounterPath = malloc(fullCounterPathLen + 1);433434if (!fullCounterPath) {435return NULL;436}437438_snprintf(fullCounterPath,439fullCounterPathLen,440PROCESS_OBJECT_INSTANCE_COUNTER_FMT,441objectName,442imageName,443instance,444counterName);445} else {446if (instance) {447/*448* For paths where the Object has multiple instances.449*450* Examples:451* abstract: "\Object(instance)\Counter"452* actual: "\Processor(0)\% Privileged Time"453*/454fullCounterPathLen += strlen(instance);455fullCounterPathLen += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;456} else {457/*458* For "normal" paths.459*460* Examples:461* abstract: "\Object\Counter"462* actual: "\Memory\Available Mbytes"463*/464fullCounterPathLen += OBJECT_COUNTER_FMT_LEN;465}466467fullCounterPath = malloc(fullCounterPathLen + 1);468469if (!fullCounterPath) {470return NULL;471}472473if (instance) {474_snprintf(fullCounterPath,475fullCounterPathLen,476OBJECT_WITH_INSTANCES_COUNTER_FMT,477objectName,478instance,479counterName);480} else {481_snprintf(fullCounterPath,482fullCounterPathLen,483OBJECT_COUNTER_FMT,484objectName,485counterName);486}487}488489fullCounterPath[fullCounterPathLen] = '\0';490491return fullCounterPath;492}493494/*495* Resolves an index for a PDH artifact to496* a localized, malloc:ed string representation.497* Caller will own the returned malloc:ed string.498*499* @param pdhArtifactIndex PDH index500* @return malloc:ed string representation501* of the requested pdh artifact (localized).502* NULL on failure.503*/504static const char*505getPdhLocalizedArtifact(DWORD pdhArtifactIndex) {506char* pdhLocalizedArtifactString;507508if (lookupNameByIndex(pdhArtifactIndex,509&pdhLocalizedArtifactString) != 0) {510return NULL;511}512513return pdhLocalizedArtifactString;514}515516static void517pdhCleanup(HQUERY* const query, HCOUNTER* const counter) {518if (counter && *counter) {519PdhRemoveCounter_i(*counter);520*counter = NULL;521}522if (query && *query) {523PdhCloseQuery_i(*query);524*query = NULL;525}526}527528static void529destroySingleCounter(SingleCounterQueryP counterQuery) {530if (counterQuery) {531pdhCleanup(&counterQuery->query.query, &counterQuery->counter);532}533}534535static void536destroyMultiCounter(MultipleCounterQueryP multiCounterQuery) {537int i;538if (multiCounterQuery) {539if (multiCounterQuery->counters) {540for (i = 0; i < multiCounterQuery->noOfCounters; i++) {541pdhCleanup(NULL, &multiCounterQuery->counters[i]);542}543free(multiCounterQuery->counters);544multiCounterQuery->counters = NULL;545}546pdhCleanup(&multiCounterQuery->query.query, NULL);547}548}549550static int551openQuery(HQUERY* const query) {552assert(query);553554if (PdhOpenQuery_i(NULL, 0, query) != ERROR_SUCCESS) {555return -1;556}557558return 0;559}560561static int562addCounter(HQUERY query,563const char* const fullCounterPath,564HCOUNTER* const counter) {565566assert(fullCounterPath);567assert(counter);568569if (PdhAddCounter_i(query,570fullCounterPath,5710,572counter) != ERROR_SUCCESS) {573return -1;574}575576return 0;577}578579/*580* Sets up the supplied SingleCounterQuery to listen for the specified counter.581*582* @param counterQuery the counter query to set up.583* @param fullCounterPath the string specifying the full path to the counter.584* @returns 0 if successful, negative on failure.585*/586static int587initializeSingleCounterQuery(SingleCounterQueryP counterQuery,588const char* const fullCounterPath) {589assert(counterQuery);590assert(fullCounterPath);591592if (openQuery(&counterQuery->query.query) == 0) {593if (addCounter(counterQuery->query.query,594fullCounterPath,595&counterQuery->counter) == 0) {596return 0;597}598}599600return -1;601}602603/*604* Sets up a SingleCounterQuery605*606* param counter the counter query to set up.607* param localizedObject string representing the PDH object to query608* param localizedCounter string representing the PDH counter to query609* param processImageName if the counter query needs the process image name ("java")610* param instance if the counter has instances, this is the instance ("\Processor(0)\")611where 0 is the instance612* param firstSampleOnInit for counters that need two queries to yield their values,613the first query can be issued just after initialization614*615* @returns 0 if successful, negative on failure.616*/617static int618initializeSingleCounter(SingleCounterQueryP const counter,619const char* const localizedObject,620const char* const localizedCounter,621const char* const processImageName,622const char* const instance,623BOOL firstSampleOnInit) {624int retValue = -1;625626const char* fullCounterPath = makeFullCounterPath(localizedObject,627localizedCounter,628processImageName,629instance);630631if (fullCounterPath) {632633assert(counter);634635if (initializeSingleCounterQuery(counter, fullCounterPath) == 0) {636/*637* According to the MSDN documentation, rate counters must be read twice:638*639* "Obtaining the value of rate counters such as Page faults/sec requires that640* PdhCollectQueryData be called twice, with a specific time interval between641* the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to642* implement the waiting period between the two calls to PdhCollectQueryData."643*644* Take the first sample here already to allow for the next (first) "real" sample645* to succeed.646*/647if (firstSampleOnInit) {648PdhCollectQueryData_i(counter->query.query);649}650651retValue = 0;652}653free((char*)fullCounterPath);654}655656return retValue;657}658659static void660perfInit(void) {661InitializePdhCriticalSection(&initializationLock);662}663664static int665getProcessID() {666static int myPid = 0;667if (0 == myPid) {668myPid = _getpid();669}670return myPid;671}672673/*674* Working against the Process object and it's related counters is inherently problematic675* when using the PDH API:676*677* For PDH, a process is not primarily identified by it's process id,678* but with a sequential number, for example \Process(java#0), \Process(java#1), ....679* The really bad part is that this list is reset as soon as one process exits:680* If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.681*682* The PDH query api requires a process identifier to be submitted when registering683* a query, but as soon as the list resets, the query is invalidated (since the name684* changed).685*686* Solution:687* The #number identifier for a Process query can only decrease after process creation.688*689* Therefore we create an array of counter queries for all process object instances690* up to and including ourselves:691*692* Ex. we come in as third process instance (java#2), we then create and register693* queries for the following Process object instances:694* java#0, java#1, java#2695*696* currentQueryIndexForProcess() keeps track of the current "correct" query697* (in order to keep this index valid when the list resets from underneath,698* ensure to call getCurrentQueryIndexForProcess() before every query involving699* Process object instance data).700*/701static int702currentQueryIndexForProcess(void) {703HQUERY tmpQuery = NULL;704HCOUNTER handleCounter = NULL;705int retValue = -1;706707assert(pdhProcessImageName);708assert(pdhIDProcessCounterFmt);709710if (openQuery(&tmpQuery) == 0) {711int index;712713/* iterate over all instance indexes and try to find our own pid */714for (index = 0; index < INT_MAX; ++index) {715char fullIDProcessCounterPath[MAX_PATH];716PDH_FMT_COUNTERVALUE counterValue;717PDH_STATUS res;718719_snprintf(fullIDProcessCounterPath,720MAX_PATH,721pdhIDProcessCounterFmt,722index);723724if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) {725break;726}727728res = PdhCollectQueryData_i(tmpQuery);729730if (PDH_INVALID_HANDLE == res || PDH_NO_DATA == res) {731break;732}733734PdhGetFormattedCounterValue_i(handleCounter,735PDH_FMT_LONG,736NULL,737&counterValue);738/*739* This check seems to be needed for Win2k SMP boxes, since740* they for some reason don't return PDH_NO_DATA for non existing741* counters.742*/743if (counterValue.CStatus != PDH_CSTATUS_VALID_DATA) {744break;745}746747if ((LONG)getProcessID() == counterValue.longValue) {748retValue = index;749break;750}751}752}753754pdhCleanup(&tmpQuery, &handleCounter);755756return retValue;757}758759/*760* If successful, returns the #index corresponding to our PID761* as resolved by the pdh query:762* "\Process(java#index)\ID Process" (or localized equivalent)763*764* This function should be called before attempting to read765* from any Process related counter(s), and the return value766* is the index to be used for indexing an array of Process object query's:767*768* Example:769* processTotalCPULoad[currentQueryIndex].query770*771* Returns -1 on failure.772*/773static int774getCurrentQueryIndexForProcess() {775int currentQueryIndex = currentQueryIndexForProcess();776777assert(currentQueryIndex >= 0 &&778currentQueryIndex < numberOfJavaProcessesAtInitialization);779780return currentQueryIndex;781}782783/*784* Returns the PDH string identifying the current process image name.785* Use this name as a qualifier when getting counters from the PDH Process Object786* representing your process.787788* Example:789* "\Process(java#0)\Virtual Bytes" - where "java" is the PDH process790* image name.791*792* Please note that the process image name is not necessarily "java",793* hence the use of GetModuleFileName() to detect the process image name.794*795* @return the process image name to be used when retrieving796* PDH counters from the current process. The caller will797own the returned malloc:ed string. NULL if failure.798*/799static const char*800getPdhProcessImageName() {801char moduleName[MAX_PATH];802char* processImageName;803char* dotPos;804805// Find our module name and use it to extract the image name used by PDH806DWORD getmfnReturn = GetModuleFileName(NULL, moduleName, sizeof(moduleName));807808if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {809return NULL;810}811812if (getmfnReturn >= MAX_PATH || 0 == getmfnReturn) {813return NULL;814}815816processImageName = strrchr(moduleName, '\\'); //drop path817processImageName++; //skip slash818dotPos = strrchr(processImageName, '.'); //drop .exe819dotPos[0] = '\0';820821return allocateAndCopy(processImageName);822}823824/*825* Sets up the supplied MultipleCounterQuery to check on the processors via PDH CPU counters.826* TODO: Refactor and prettify as with the the SingleCounter queries827* if more MultipleCounterQueries are discovered/needed.828*829* @param multiCounterCPULoad a pointer to a MultipleCounterQueryS, will be filled in with830* the necessary info to check the PDH processor counters.831* @return 0 if successful, negative on failure.832*/833static int834initializeMultipleCounterForCPUs(MultipleCounterQueryP multiCounterCPULoad) {835DWORD cSize = 0;836DWORD iSize = 0;837DWORD pCount;838DWORD index;839char* processor = NULL; //'Processor' == PDH_PROCESSOR_IDX840char* time = NULL; //'Time' == PDH_PROCESSOR_TIME_IDX841char* instances = NULL;842char* tmp;843int retValue = -1;844PDH_STATUS pdhStat;845846if (lookupNameByIndex(PDH_PROCESSOR_IDX, &processor) != 0) {847goto end;848}849850if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX, &time) != 0) {851goto end;852}853854//ok, now we have enough to enumerate all processors.855pdhStat = PdhEnumObjectItems_i(856NULL, // reserved857NULL, // local machine858processor, // object to enumerate859NULL, // pass in NULL buffers860&cSize, // and 0 length to get861NULL, // required size862&iSize, // of the buffers in chars863PERF_DETAIL_WIZARD, // counter detail level8640);865866if (pdhFail(pdhStat)) {867goto end;868}869870instances = calloc(iSize, 1);871872if (!instances) {873goto end;874}875876cSize = 0;877878pdhStat = PdhEnumObjectItems_i(879NULL, // reserved880NULL, // local machine881processor, // object to enumerate882NULL, // pass in NULL buffers883&cSize,884instances, // now allocated to be filled in885&iSize, // and size is known886PERF_DETAIL_WIZARD, // counter detail level8870);888889if (pdhFail(pdhStat)) {890goto end;891}892893// enumerate the Processor instances ("\Processor(0)", "\Processor(1)", ..., "\Processor(_Total)")894for (pCount = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], pCount++);895896assert(pCount == numCpus+1);897898//ok, we now have the number of Processor instances - allocate an HCOUNTER for each899multiCounterCPULoad->counters = (HCOUNTER*)malloc(pCount * sizeof(HCOUNTER));900901if (!multiCounterCPULoad->counters) {902goto end;903}904905multiCounterCPULoad->noOfCounters = pCount;906907if (openQuery(&multiCounterCPULoad->query.query) != 0) {908goto end;909}910911// fetch instance and register its corresponding HCOUNTER with the query912for (index = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[strlen(tmp)+1], ++index) {913const char* const fullCounterPath = makeFullCounterPath(processor, time, NULL, tmp);914915if (!fullCounterPath) {916goto end;917}918919retValue = addCounter(multiCounterCPULoad->query.query,920fullCounterPath,921&multiCounterCPULoad->counters[index]);922923free((char*)fullCounterPath);924925if (retValue != 0) {926goto end;927}928}929930// Query once to initialize the counters which require at least two samples931// (like the % CPU usage) to calculate correctly.932PdhCollectQueryData_i(multiCounterCPULoad->query.query);933934end:935if (processor) {936free(processor);937}938939if (time) {940free(time);941}942943if (instances) {944free(instances);945}946947return retValue;948}949950/*951* Dynamically sets up function pointers to the PDH library.952*953* @param h HMODULE for the PDH library954* @return 0 on success, negative on failure.955*/956static int957bindPdhFunctionPointers(HMODULE h) {958assert(h);959assert(GetCurrentThreadId() == initializationLock.owningThread);960961/* The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods */962PdhAddCounter_i = (PdhAddCounterFunc)GetProcAddress(h, "PdhAddCounterA");963PdhOpenQuery_i = (PdhOpenQueryFunc)GetProcAddress(h, "PdhOpenQueryA");964PdhCloseQuery_i = (PdhCloseQueryFunc)GetProcAddress(h, "PdhCloseQuery");965PdhCollectQueryData_i = (PdhCollectQueryDataFunc)GetProcAddress(h, "PdhCollectQueryData");966PdhGetFormattedCounterValue_i = (PdhGetFormattedCounterValueFunc)GetProcAddress(h, "PdhGetFormattedCounterValue");967PdhEnumObjectItems_i = (PdhEnumObjectItemsFunc)GetProcAddress(h, "PdhEnumObjectItemsA");968PdhRemoveCounter_i = (PdhRemoveCounterFunc)GetProcAddress(h, "PdhRemoveCounter");969PdhLookupPerfNameByIndex_i = (PdhLookupPerfNameByIndexFunc)GetProcAddress(h, "PdhLookupPerfNameByIndexA");970971if (!PdhAddCounter_i || !PdhOpenQuery_i ||972!PdhCloseQuery_i || !PdhCollectQueryData_i ||973!PdhGetFormattedCounterValue_i || !PdhEnumObjectItems_i ||974!PdhRemoveCounter_i || !PdhLookupPerfNameByIndex_i)975{976return -1;977}978return 0;979}980981/*982* Returns the counter value as a double for the specified query.983* Will collect the query data and update the counter values as necessary.984*985* @param query the query to update (if needed).986* @param c the counter to read.987* @param value where to store the formatted value.988* @param format the format to use (i.e. PDH_FMT_DOUBLE, PDH_FMT_LONG etc)989* @return 0 if no error990* -1 if PdhCollectQueryData fails991* -2 if PdhGetFormattedCounterValue fails992*/993static int994getPerformanceData(UpdateQueryP query, HCOUNTER c, PDH_FMT_COUNTERVALUE* value, DWORD format) {995clock_t now = clock();996997/*998* Need to limit how often we update the query999* to minimize the Heisenberg effect.1000* (PDH behaves erratically if the counters are1001* queried too often, especially counters that1002* store and use values from two consecutive updates,1003* like cpu load.)1004*/1005if (now - query->lastUpdate > MIN_UPDATE_INTERVAL) {1006if (PdhCollectQueryData_i(query->query) != ERROR_SUCCESS) {1007return -1;1008}1009query->lastUpdate = now;1010}10111012if (PdhGetFormattedCounterValue_i(c, format, NULL, value) != ERROR_SUCCESS) {1013return -2;1014}10151016return 0;1017}10181019static int1020allocateAndInitializePdhConstants() {1021const char* pdhLocalizedProcessObject = NULL;1022const char* pdhLocalizedIDProcessCounter = NULL;1023size_t pdhIDProcessCounterFmtLen;1024int currentQueryIndex;1025int retValue = -1;10261027assert(GetCurrentThreadId() == initializationLock.owningThread);10281029assert(!pdhProcessImageName);1030pdhProcessImageName = getPdhProcessImageName();1031if (!pdhProcessImageName) {1032goto end;1033}10341035pdhLocalizedProcessObject = getPdhLocalizedArtifact(PDH_PROCESS_IDX);1036if (!pdhLocalizedProcessObject) {1037goto end;1038}10391040pdhLocalizedIDProcessCounter = getPdhLocalizedArtifact(PDH_ID_PROCESS_IDX);1041if (!pdhLocalizedIDProcessCounter) {1042goto end;1043}10441045assert(!pdhIDProcessCounterFmt);10461047pdhIDProcessCounterFmtLen = strlen(pdhProcessImageName);1048pdhIDProcessCounterFmtLen += strlen(pdhLocalizedProcessObject);1049pdhIDProcessCounterFmtLen += strlen(pdhLocalizedIDProcessCounter);1050pdhIDProcessCounterFmtLen += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;1051pdhIDProcessCounterFmtLen += 2; // "%d"10521053assert(pdhIDProcessCounterFmtLen < MAX_PATH);1054pdhIDProcessCounterFmt = malloc(pdhIDProcessCounterFmtLen + 1);1055if (!pdhIDProcessCounterFmt) {1056goto end;1057}10581059/* "\Process(java#%d)\ID Process" */1060_snprintf(pdhIDProcessCounterFmt,1061pdhIDProcessCounterFmtLen,1062PROCESS_OBJECT_INSTANCE_COUNTER_FMT,1063pdhLocalizedProcessObject,1064pdhProcessImageName,1065"%d",1066pdhLocalizedIDProcessCounter);10671068pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0';10691070assert(0 == numberOfJavaProcessesAtInitialization);1071currentQueryIndex = currentQueryIndexForProcess();1072if (-1 == currentQueryIndex) {1073goto end;1074}10751076numberOfJavaProcessesAtInitialization = currentQueryIndex + 1;1077assert(numberOfJavaProcessesAtInitialization >= 1);10781079retValue = 0;10801081end:10821083if (pdhLocalizedProcessObject) {1084free((char*)pdhLocalizedProcessObject);1085}10861087if (pdhLocalizedIDProcessCounter) {1088free((char*)pdhLocalizedIDProcessCounter);1089}10901091return retValue;1092}10931094static void1095deallocatePdhConstants() {1096assert(GetCurrentThreadId() == initializationLock.owningThread);10971098if (pdhProcessImageName) {1099free((char*)pdhProcessImageName);1100pdhProcessImageName = NULL;1101}11021103if (pdhIDProcessCounterFmt) {1104free(pdhIDProcessCounterFmt);1105pdhIDProcessCounterFmt = NULL;1106}11071108numberOfJavaProcessesAtInitialization = 0;1109}11101111static int1112initializeCPUCounters() {1113SYSTEM_INFO si;1114char* localizedProcessObject;1115char* localizedProcessorTimeCounter;1116int i;1117int retValue = -1;11181119assert(GetCurrentThreadId() == initializationLock.owningThread);11201121assert(0 == numCpus);1122GetSystemInfo(&si);1123numCpus = si.dwNumberOfProcessors;1124assert(numCpus >= 1);11251126/* Initialize the denominator for the jvm load calculations */1127assert(.0 == cpuFactor);1128cpuFactor = numCpus * 100;11291130if (lookupNameByIndex(PDH_PROCESS_IDX,1131&localizedProcessObject) == 0) {11321133if (lookupNameByIndex(PDH_PROCESSOR_TIME_IDX,1134&localizedProcessorTimeCounter) == 0) {11351136assert(processTotalCPULoad);1137assert(pdhProcessImageName);11381139for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {1140char instanceIndexBuffer[32];1141retValue = initializeSingleCounter(&processTotalCPULoad[i],1142localizedProcessObject,1143localizedProcessorTimeCounter,1144pdhProcessImageName,1145itoa(i, instanceIndexBuffer, 10),1146TRUE);1147if (retValue != 0) {1148break;1149}1150}1151free(localizedProcessorTimeCounter);1152}1153free(localizedProcessObject);1154}11551156if (retValue != 0) {1157return -1;1158}11591160assert(multiCounterCPULoad);1161return initializeMultipleCounterForCPUs(multiCounterCPULoad);1162}11631164static void1165deallocateCPUCounters() {1166int i;11671168assert(GetCurrentThreadId() == initializationLock.owningThread);11691170if (processTotalCPULoad) {1171for (i = 0; i < numberOfJavaProcessesAtInitialization; ++i) {1172destroySingleCounter(&processTotalCPULoad[i]);1173}1174free(processTotalCPULoad);1175processTotalCPULoad = NULL;1176}11771178if (multiCounterCPULoad) {1179destroyMultiCounter(multiCounterCPULoad);1180free(multiCounterCPULoad);1181multiCounterCPULoad = NULL;1182}11831184cpuFactor = .0;1185numCpus = 0;1186}11871188static void1189pdhInitErrorHandler(HMODULE h) {1190assert(GetCurrentThreadId() == initializationLock.owningThread);11911192deallocatePdhConstants();11931194if (h) {1195FreeLibrary(h);1196}1197}11981199/*1200* Helper to initialize the PDH library, function pointers and constants.1201*1202* @return 0 if successful, negative on failure.1203*/1204static int1205pdhInit() {1206static BOOL initialized = FALSE;1207int retValue;12081209if (initialized) {1210return 0;1211}12121213retValue = 0;12141215EnterPdhCriticalSection(&initializationLock); {1216if (!initialized) {1217HMODULE h = NULL;1218if ((h = LoadLibrary("pdh.dll")) == NULL) {1219retValue = -1;1220} else if (bindPdhFunctionPointers(h) < 0) {1221retValue = -1;1222} else if (allocateAndInitializePdhConstants() < 0) {1223retValue = -1;1224}12251226if (0 == retValue) {1227initialized = TRUE;1228} else {1229pdhInitErrorHandler(h);1230}1231}1232} LeavePdhCriticalSection(&initializationLock);12331234return retValue;1235}12361237static int1238allocateCPUCounters() {1239assert(GetCurrentThreadId() == initializationLock.owningThread);1240assert(numberOfJavaProcessesAtInitialization >= 1);1241assert(!processTotalCPULoad);1242assert(!multiCounterCPULoad);12431244/*1245* Create an array of Process object queries, for each instance1246* up to and including our own (java#0, java#1, java#2, ...).1247*/1248processTotalCPULoad = calloc(numberOfJavaProcessesAtInitialization,1249sizeof(SingleCounterQueryS));12501251if (!processTotalCPULoad) {1252return -1;1253}12541255multiCounterCPULoad = calloc(1, sizeof(MultipleCounterQueryS));12561257if (!multiCounterCPULoad) {1258return -1;1259}12601261return 0;1262}12631264static int1265initializePdhCPUCounters() {1266static BOOL initialized = FALSE;1267int retValue;12681269if (initialized) {1270return 0;1271}12721273retValue = 0;12741275EnterPdhCriticalSection(&initializationLock); {1276if (!initialized) {1277if (pdhInit() < 0) {1278retValue = -1;1279} else if (allocateCPUCounters() < 0) {1280retValue = -1;1281} else if (initializeCPUCounters() < 0) {1282retValue = -1;1283}12841285if (0 == retValue) {1286initialized = TRUE;1287} else {1288deallocateCPUCounters();1289}1290}1291} LeavePdhCriticalSection(&initializationLock);12921293return retValue;1294}12951296static int1297perfCPUInit() {1298return initializePdhCPUCounters();1299}13001301static double1302perfGetProcessCPULoad() {1303PDH_FMT_COUNTERVALUE cv;1304int currentQueryIndex;13051306if (perfCPUInit() < 0) {1307// warn?1308return -1.0;1309}13101311currentQueryIndex = getCurrentQueryIndexForProcess();13121313if (getPerformanceData(&processTotalCPULoad[currentQueryIndex].query,1314processTotalCPULoad[currentQueryIndex].counter,1315&cv,1316PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == 0) {1317double d = cv.doubleValue / cpuFactor;1318d = min(1, d);1319d = max(0, d);1320return d;1321}1322return -1.0;1323}13241325static double1326perfGetCPULoad(int which) {1327PDH_FMT_COUNTERVALUE cv;1328HCOUNTER c;13291330if (perfCPUInit() < 0) {1331// warn?1332return -1.0;1333}13341335if (-1 == which) {1336c = multiCounterCPULoad->counters[multiCounterCPULoad->noOfCounters - 1];1337} else {1338if (which < multiCounterCPULoad->noOfCounters) {1339c = multiCounterCPULoad->counters[which];1340} else {1341return -1.0;1342}1343}1344if (getPerformanceData(&multiCounterCPULoad->query, c, &cv, PDH_FMT_DOUBLE ) == 0) {1345return cv.doubleValue / 100;1346}1347return -1.0;1348}13491350JNIEXPORT jdouble JNICALL1351Java_sun_management_OperatingSystemImpl_getSystemCpuLoad1352(JNIEnv *env, jobject dummy)1353{1354return perfGetCPULoad(-1);1355}13561357JNIEXPORT jdouble JNICALL1358Java_sun_management_OperatingSystemImpl_getProcessCpuLoad1359(JNIEnv *env, jobject dummy)1360{1361return perfGetProcessCPULoad();1362}136313641365