diff -r aaa6b141196c -r 62542b8be764 jdk/src/windows/native/com/sun/management/OperatingSystem_md.c --- a/jdk/src/windows/native/com/sun/management/OperatingSystem_md.c Fri Nov 08 18:17:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,941 +0,0 @@ -/* - * Copyright (c) 2003, 2011, 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 "com_sun_management_OperatingSystem.h" - -#include -#include -#include - -#include -#pragma warning (push,0) -#include -#pragma warning (pop) -#include -#include -#include -#include - -/* Disable warnings due to broken header files from Microsoft... */ -#pragma warning(push, 3) -#include -#include -#include -#pragma warning(pop) - -typedef unsigned __int32 juint; -typedef unsigned __int64 julong; - -typedef enum boolean_values { false=0, true=1}; - -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; - -int perfiInit(void); - -JNIEXPORT void JNICALL -Java_com_sun_management_OperatingSystem_initialize - (JNIEnv *env, jclass cls) -{ - main_process = GetCurrentProcess(); - perfiInit(); -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_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_com_sun_management_OperatingSystem_getTotalSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPageFile; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getFreeSwapSpaceSize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPageFile; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getProcessCpuTime - (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_com_sun_management_OperatingSystem_getFreePhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPhys; -} - -JNIEXPORT jlong JNICALL -Java_com_sun_management_OperatingSystem_getTotalPhysicalMemorySize - (JNIEnv *env, jobject mbean) -{ - MEMORYSTATUSEX ms; - ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPhys; -} - -// 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 -pdh_fail(PDH_STATUS pdhStat) { - return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA; -} - -// 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. -#define PDH_PROCESSOR_IDX ((DWORD) 238) -#define PDH_PROCESSOR_TIME_IDX ((DWORD) 6) -#define PDH_PRIV_PROCESSOR_TIME_IDX ((DWORD) 144) -#define PDH_PROCESS_IDX ((DWORD) 230) -#define PDH_ID_PROCESS_IDX ((DWORD) 784) -#define PDH_CONTEXT_SWITCH_RATE_IDX ((DWORD) 146) -#define PDH_SYSTEM_IDX ((DWORD) 2) -#define PDH_VIRTUAL_BYTES_IDX ((DWORD) 174) - -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 DWORD (WINAPI *PdhCloseQueryFunc)( - HQUERY hQuery - ); -typedef PDH_STATUS (WINAPI *PdhCollectQueryDataFunc)( - HQUERY hQuery - ); -typedef DWORD (WINAPI *PdhGetFormattedCounterValueFunc)( - HCOUNTER hCounter, - DWORD dwFormat, - LPDWORD lpdwType, - PPDH_FMT_COUNTERVALUE pValue - ); -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 PDH_STATUS (WINAPI *PdhMakeCounterPathFunc)( - PDH_COUNTER_PATH_ELEMENTS *pCounterPathElements, - LPTSTR szFullPathBuffer, - LPDWORD pcchBufferSize, - DWORD dwFlags - ); - -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; -static PdhMakeCounterPathFunc PdhMakeCounterPath_i; - -static HANDLE thisProcess; -static double cpuFactor; -static DWORD num_cpus; - -#define FT2JLONG(X) ((((jlong)X.dwHighDateTime) << 32) | ((jlong)X.dwLowDateTime)) -#define COUNTER_BUF_SIZE 256 -// Min time between query updates. -#define MIN_UPDATE_INTERVAL 500 -#define CONFIG_SUCCESSFUL 0 - -/** - * Struct for PDH queries. - */ -typedef struct { - HQUERY query; - uint64_t lastUpdate; // Last time query was updated (current millis). -} UpdateQueryS, *UpdateQueryP; - -/** - * Struct for the processor load counters. - */ -typedef struct { - UpdateQueryS query; - HCOUNTER* counters; - int noOfCounters; -} MultipleCounterQueryS, *MultipleCounterQueryP; - -/** - * Struct for the jvm process load counter. - */ -typedef struct { - UpdateQueryS query; - HCOUNTER counter; -} SingleCounterQueryS, *SingleCounterQueryP; - -static char* getProcessPDHHeader(void); - -/** - * Currently available counters. - */ -static SingleCounterQueryS cntCtxtSwitchRate; -static SingleCounterQueryS cntVirtualSize; -static SingleCounterQueryS cntProcLoad; -static SingleCounterQueryS cntProcSystemLoad; -static MultipleCounterQueryS multiCounterCPULoad; - -static CRITICAL_SECTION processHeaderLock; -static CRITICAL_SECTION initializationLock; - -/** - * Initialize the perf module at startup. - */ -int -perfiInit(void) -{ - InitializeCriticalSection(&processHeaderLock); - InitializeCriticalSection(&initializationLock); - return 0; -} - -/** - * Dynamically sets up function pointers to the PDH library. - * - * @return CONFIG_SUCCESSFUL on success, negative on failure. - */ -static int -get_functions(HMODULE h, char *ebuf, size_t elen) { - // 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"); - PdhMakeCounterPath_i = (PdhMakeCounterPathFunc)GetProcAddress(h, "PdhMakeCounterPathA"); - - if (PdhAddCounter_i == NULL || PdhOpenQuery_i == NULL || - PdhCloseQuery_i == NULL || PdhCollectQueryData_i == NULL || - PdhGetFormattedCounterValue_i == NULL || PdhEnumObjectItems_i == NULL || - PdhRemoveCounter_i == NULL || PdhLookupPerfNameByIndex_i == NULL || PdhMakeCounterPath_i == NULL) - { - _snprintf(ebuf, elen, "Required method could not be found."); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * 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 CONFIG_SUCCESSFUL 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; - now = clock(); - - // Need to limit how often we update the query - // to mimise 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 CONFIG_SUCCESSFUL; -} - -/** - * Places the resolved counter name of the counter at the specified index in the - * supplied buffer. There must be enough space in the buffer to hold the counter name. - * - * @param index the counter index as specified in the registry. - * @param buf the buffer in which to place the counter name. - * @param size the size of the counter name buffer. - * @param ebuf the error message buffer. - * @param elen the length of the error buffer. - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -find_name(DWORD index, char *buf, DWORD size) { - PDH_STATUS res; - - if ((res = PdhLookupPerfNameByIndex_i(NULL, index, buf, &size)) != ERROR_SUCCESS) { - - /* printf("Could not open counter %d: error=0x%08x", index, res); */ - /* if (res == PDH_CSTATUS_NO_MACHINE) { */ - /* printf("User probably does not have sufficient privileges to use"); */ - /* printf("performance counters. If you are running on Windows 2003"); */ - /* printf("or Windows Vista, make sure the user is in the"); */ - /* printf("Performance Logs user group."); */ - /* } */ - return -1; - } - - if (size == 0) { - /* printf("Failed to get counter name for %d: empty string", index); */ - return -1; - } - - // windows vista does not null-terminate the string (allthough the docs says it will) - buf[size - 1] = '\0'; - return CONFIG_SUCCESSFUL; -} - -/** - * Sets up the supplied SingleCounterQuery to listen for the specified counter. - * initPDH() must have been run prior to calling this function! - * - * @param counterQuery the counter query to set up. - * @param counterString the string specifying the path to the counter. - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * @returns CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initSingleCounterQuery(SingleCounterQueryP counterQuery, char *counterString) { - if (PdhOpenQuery_i(NULL, 0, &counterQuery->query.query) != ERROR_SUCCESS) { - /* printf("Could not open query for %s", counterString); */ - return -1; - } - if (PdhAddCounter_i(counterQuery->query.query, counterString, 0, &counterQuery->counter) != ERROR_SUCCESS) { - /* printf("Could not add counter %s for query", counterString); */ - if (counterQuery->counter != NULL) { - PdhRemoveCounter_i(counterQuery->counter); - } - if (counterQuery->query.query != NULL) { - PdhCloseQuery_i(counterQuery->query.query); - } - memset(counterQuery, 0, sizeof(SingleCounterQueryS)); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Sets up the supplied SingleCounterQuery to listen for the time spent - * by the HotSpot process. - * - * @param counterQuery the counter query to set up as a process counter. - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * @returns CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initProcLoadCounter(void) { - char time[COUNTER_BUF_SIZE]; - char counter[COUNTER_BUF_SIZE*2]; - - if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); - return initSingleCounterQuery(&cntProcLoad, counter); -} - -static int -initProcSystemLoadCounter(void) { - char time[COUNTER_BUF_SIZE]; - char counter[COUNTER_BUF_SIZE*2]; - - if (find_name(PDH_PRIV_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - _snprintf(counter, sizeof(counter)-1, "%s\\%s", getProcessPDHHeader(), time); - return initSingleCounterQuery(&cntProcSystemLoad, counter); -} - -/** - * Sets up the supplied MultipleCounterQuery to check on the processors. - * (Comment: Refactor and prettify as with the the SingleCounter queries - * if more MultipleCounterQueries are discovered.) - * - * initPDH() must have been run prior to calling this function. - * - * @param multiQuery a pointer to a MultipleCounterQueryS, will be filled in with - * the necessary info to check the PDH processor counters. - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -static int -initProcessorCounters(void) { - char processor[COUNTER_BUF_SIZE]; //'Processor' == #238 - char time[COUNTER_BUF_SIZE]; //'Time' == 6 - DWORD c_size, i_size; - HQUERY tmpQuery; - DWORD i, p_count; - BOOL error; - char *instances, *tmp; - PDH_STATUS pdhStat; - - c_size = i_size = 0; - tmpQuery = NULL; - error = false; - - // This __try / __except stuff is there since Windows 2000 beta (or so) sometimes triggered - // an access violation when the user had insufficient privileges to use the performance - // counters. This was previously guarded by a very ugly piece of code which disabled the - // global trap handling in JRockit. Don't know if this really is needed anymore, but otoh, - // if we keep it we don't crash on Win2k beta. /Ihse, 2005-05-30 - __try { - if (find_name(PDH_PROCESSOR_IDX, processor, sizeof(processor)-1) < 0) { - return -1; - } - } __except (EXCEPTION_EXECUTE_HANDLER) { // We'll catch all exceptions here. - /* printf("User does not have sufficient privileges to use performance counters"); */ - return -1; - } - - if (find_name(PDH_PROCESSOR_TIME_IDX, time, sizeof(time)-1) < 0) { - return -1; - } - //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 - &c_size, // and 0 length to get - NULL, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - if (pdh_fail(pdhStat)) { - /* printf("could not enumerate processors (1) error=%d", pdhStat); */ - return -1; - } - - // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) - instances = calloc(i_size, 1); - if (instances == NULL) { - /* printf("could not allocate memory (1) %d bytes", i_size); */ - error = true; - goto end; - } - - c_size = 0; - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processor, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - instances, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - if (pdh_fail(pdhStat)) { - /* printf("could not enumerate processors (2) error=%d", pdhStat); */ - error = true; - goto end; - } - //count perf count instances. - for (p_count = 0, tmp = instances; *tmp != 0; tmp = &tmp[lstrlen(tmp)+1], p_count++); - - //is this correct for HT? - assert(p_count == num_cpus+1); - - //ok, have number of perf counters. - multiCounterCPULoad.counters = calloc(p_count, sizeof(HCOUNTER)); - if (multiCounterCPULoad.counters == NULL) { - /* printf("could not allocate memory (2) count=%d", p_count); */ - error = true; - goto end; - } - - multiCounterCPULoad.noOfCounters = p_count; - - if (PdhOpenQuery_i(NULL, 0, &multiCounterCPULoad.query.query) != ERROR_SUCCESS) { - /* printf("could not create query"); */ - error = true; - goto end; - } - //now, fetch the counters. - for (i = 0, tmp = instances; *tmp != '\0'; tmp = &tmp[lstrlen(tmp)+1], i++) { - char counter[2*COUNTER_BUF_SIZE]; - - _snprintf(counter, sizeof(counter)-1, "\\%s(%s)\\%s", processor, tmp, time); - - if (PdhAddCounter_i(multiCounterCPULoad.query.query, counter, 0, &multiCounterCPULoad.counters[i]) != ERROR_SUCCESS) { - /* printf("error adding processor counter %s", counter); */ - error = true; - goto end; - } - } - - free(instances); - instances = NULL; - - // Query once to initialize the counters needing at least two queries - // (like the % CPU usage) to calculate correctly. - if (PdhCollectQueryData_i(multiCounterCPULoad.query.query) != ERROR_SUCCESS) - error = true; - - end: - if (instances != NULL) { - free(instances); - } - if (tmpQuery != NULL) { - PdhCloseQuery_i(tmpQuery); - } - if (error) { - int i; - - if (multiCounterCPULoad.counters != NULL) { - for (i = 0; i < multiCounterCPULoad.noOfCounters; i++) { - if (multiCounterCPULoad.counters[i] != NULL) { - PdhRemoveCounter_i(multiCounterCPULoad.counters[i]); - } - } - free(multiCounterCPULoad.counters[i]); - } - if (multiCounterCPULoad.query.query != NULL) { - PdhCloseQuery_i(multiCounterCPULoad.query.query); - } - memset(&multiCounterCPULoad, 0, sizeof(MultipleCounterQueryS)); - return -1; - } - return CONFIG_SUCCESSFUL; -} - -/** - * Help function that initializes the PDH process header for the JRockit process. - * (You should probably use getProcessPDHHeader() instead!) - * - * initPDH() must have been run prior to calling this function. - * - * @param ebuf the error buffer. - * @param elen the length of the error buffer. - * - * @return the PDH instance description corresponding to the JVM process. - */ -static char* -initProcessPDHHeader(void) { - static char hotspotheader[2*COUNTER_BUF_SIZE]; - - char counter[2*COUNTER_BUF_SIZE]; - char processes[COUNTER_BUF_SIZE]; //'Process' == #230 - char pid[COUNTER_BUF_SIZE]; //'ID Process' == 784 - char module_name[MAX_PATH]; - PDH_STATUS pdhStat; - DWORD c_size = 0, i_size = 0; - HQUERY tmpQuery = NULL; - int i, myPid = _getpid(); - BOOL error = false; - char *instances, *tmp, *instance_name, *dot_pos; - - tmpQuery = NULL; - myPid = _getpid(); - error = false; - - if (find_name(PDH_PROCESS_IDX, processes, sizeof(processes) - 1) < 0) { - return NULL; - } - - if (find_name(PDH_ID_PROCESS_IDX, pid, sizeof(pid) - 1) < 0) { - return NULL; - } - //time is same. - - c_size = 0; - i_size = 0; - - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processes, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - NULL, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - //ok, now we have enough to enumerate all processes - if (pdh_fail(pdhStat)) { - /* printf("Could not enumerate processes (1) error=%d", pdhStat); */ - return NULL; - } - - // use calloc because windows vista does not null terminate the instance names (allthough the docs says it will) - if ((instances = calloc(i_size, 1)) == NULL) { - /* printf("Could not allocate memory %d bytes", i_size); */ - error = true; - goto end; - } - - c_size = 0; - - pdhStat = PdhEnumObjectItems_i ( - NULL, // reserved - NULL, // local machine - processes, // object to enumerate - NULL, // pass in NULL buffers - &c_size, // and 0 length to get - instances, // required size - &i_size, // of the buffers in chars - PERF_DETAIL_WIZARD, // counter detail level - 0); - - // ok, now we have enough to enumerate all processes - if (pdh_fail(pdhStat)) { - /* printf("Could not enumerate processes (2) error=%d", pdhStat); */ - error = true; - goto end; - } - - if (PdhOpenQuery_i(NULL, 0, &tmpQuery) != ERROR_SUCCESS) { - /* printf("Could not create temporary query"); */ - error = true; - goto end; - } - - // Find our module name and use it to extract the instance name used by PDH - if (GetModuleFileName(NULL, module_name, MAX_PATH) >= MAX_PATH-1) { - /* printf("Module name truncated"); */ - error = true; - goto end; - } - instance_name = strrchr(module_name, '\\'); //drop path - instance_name++; //skip slash - dot_pos = strchr(instance_name, '.'); //drop .exe - dot_pos[0] = '\0'; - - //now, fetch the counters. - for (tmp = instances; *tmp != 0 && !error; tmp = &tmp[lstrlen(tmp)+1]) { - HCOUNTER hc = NULL; - BOOL done = false; - - // Skip until we find our own process name - if (strcmp(tmp, instance_name) != 0) { - continue; - } - - // iterate over all instance indexes and try to find our own pid - for (i = 0; !done && !error; i++){ - PDH_STATUS res; - _snprintf(counter, sizeof(counter)-1, "\\%s(%s#%d)\\%s", processes, tmp, i, pid); - - if (PdhAddCounter_i(tmpQuery, counter, 0, &hc) != ERROR_SUCCESS) { - /* printf("Failed to create process id query"); */ - error = true; - goto end; - } - - res = PdhCollectQueryData_i(tmpQuery); - - if (res == PDH_INVALID_HANDLE) { - /* printf("Failed to query process id"); */ - res = -1; - done = true; - } else if (res == PDH_NO_DATA) { - done = true; - } else { - PDH_FMT_COUNTERVALUE cv; - - PdhGetFormattedCounterValue_i(hc, PDH_FMT_LONG, NULL, &cv); - /* - * 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 (cv.CStatus != PDH_CSTATUS_VALID_DATA) { - done = true; - } else if (cv.longValue == myPid) { - _snprintf(hotspotheader, sizeof(hotspotheader)-1, "\\%s(%s#%d)\0", processes, tmp, i); - PdhRemoveCounter_i(hc); - goto end; - } - } - PdhRemoveCounter_i(hc); - } - } - end: - if (instances != NULL) { - free(instances); - } - if (tmpQuery != NULL) { - PdhCloseQuery_i(tmpQuery); - } - if (error) { - return NULL; - } - return hotspotheader; -} - -/** - * Returns the PDH string prefix identifying the HotSpot process. Use this prefix when getting - * counters from the PDH process object representing HotSpot. - * - * Note: this call may take some time to complete. - * - * @param ebuf error buffer. - * @param elen error buffer length. - * - * @return the header to be used when retrieving PDH counters from the HotSpot process. - * Will return NULL if the call failed. - */ -static char * -getProcessPDHHeader(void) { - static char *processHeader = NULL; - - EnterCriticalSection(&processHeaderLock); { - if (processHeader == NULL) { - processHeader = initProcessPDHHeader(); - } - } LeaveCriticalSection(&processHeaderLock); - return processHeader; -} - -int perfInit(void); - -double -perfGetCPULoad(int which) -{ - PDH_FMT_COUNTERVALUE cv; - HCOUNTER c; - - if (perfInit() < 0) { - // warn? - return -1.0; - } - - if (multiCounterCPULoad.query.query == NULL) { - // warn? - return -1.0; - } - - if (which == -1) { - 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 ) == CONFIG_SUCCESSFUL) { - return cv.doubleValue / 100; - } - return -1.0; -} - -double -perfGetProcessLoad(void) -{ - PDH_FMT_COUNTERVALUE cv; - - if (perfInit() < 0) { - // warn? - return -1.0; - } - - if (cntProcLoad.query.query == NULL) { - // warn? - return -1.0; - } - - if (getPerformanceData(&cntProcLoad.query, cntProcLoad.counter, &cv, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100) == CONFIG_SUCCESSFUL) { - double d = cv.doubleValue / cpuFactor; - d = min(1, d); - d = max(0, d); - return d; - } - return -1.0; -} - -/** - * Helper to initialize the PDH library. Loads the library and sets up the functions. - * Note that once loaded, we will never unload the PDH library. - * - * @return CONFIG_SUCCESSFUL if successful, negative on failure. - */ -int -perfInit(void) { - static HMODULE h; - static BOOL running, inited; - - int error; - - if (running) { - return CONFIG_SUCCESSFUL; - } - - error = CONFIG_SUCCESSFUL; - - // this is double checked locking again, but we try to bypass the worst by - // implicit membar at end of lock. - EnterCriticalSection(&initializationLock); { - if (!inited) { - char buf[64] = ""; - SYSTEM_INFO si; - - // CMH. But windows will not care about our affinity when giving - // us measurements. Need the real, raw num cpus. - - GetSystemInfo(&si); - num_cpus = si.dwNumberOfProcessors; - // Initialize the denominator for the jvm load calculations - cpuFactor = num_cpus * 100; - - /** - * Do this dynamically, so we don't fail to start on systems without pdh. - */ - if ((h = LoadLibrary("pdh.dll")) == NULL) { - /* printf("Could not load pdh.dll (%d)", GetLastError()); */ - error = -2; - } else if (get_functions(h, buf, sizeof(buf)) < 0) { - FreeLibrary(h); - h = NULL; - error = -2; - /* printf("Failed to init pdh functions: %s.\n", buf); */ - } else { - if (initProcessorCounters() != 0) { - /* printf("Failed to init system load counters.\n"); */ - } else if (initProcLoadCounter() != 0) { - /* printf("Failed to init process load counter.\n"); */ - } else if (initProcSystemLoadCounter() != 0) { - /* printf("Failed to init process system load counter.\n"); */ - } else { - inited = true; - } - } - } - } LeaveCriticalSection(&initializationLock); - - if (inited && error == CONFIG_SUCCESSFUL) { - running = true; - } - - return error; -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_OperatingSystem_getSystemCpuLoad -(JNIEnv *env, jobject dummy) -{ - return perfGetCPULoad(-1); -} - -JNIEXPORT jdouble JNICALL -Java_com_sun_management_OperatingSystem_getProcessCpuLoad -(JNIEnv *env, jobject dummy) -{ - return perfGetProcessLoad(); -}