alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (OperatingSystemImpl.c)

This example Java source code file (OperatingSystemImpl.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

config_successful, dword, error_success, hcounter, hquery, jnicall, jnienv, jniexport, null, pdh_status, pdhenumobjectitems_i, pdhopenquery_i, pdhremovecounter_i, winapi

The OperatingSystemImpl.c Java example source code

/*
 * 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;

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_sun_management_OperatingSystemImpl_initialize
  (JNIEnv *env, jclass cls)
{
    main_process = GetCurrentProcess();
     perfiInit();
}

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_getTotalSwapSpaceSize
  (JNIEnv *env, jobject mbean)
{
    MEMORYSTATUSEX ms;
    ms.dwLength = sizeof(ms);
    GlobalMemoryStatusEx(&ms);
    return (jlong) ms.ullTotalPageFile;
}

JNIEXPORT jlong JNICALL
Java_sun_management_OperatingSystemImpl_getFreeSwapSpaceSize
  (JNIEnv *env, jobject mbean)
{
    MEMORYSTATUSEX ms;
    ms.dwLength = sizeof(ms);
    GlobalMemoryStatusEx(&ms);
    return (jlong) ms.ullAvailPageFile;
}

JNIEXPORT jlong JNICALL
Java_sun_management_OperatingSystemImpl_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_sun_management_OperatingSystemImpl_getFreePhysicalMemorySize
  (JNIEnv *env, jobject mbean)
{
    MEMORYSTATUSEX ms;
    ms.dwLength = sizeof(ms);
    GlobalMemoryStatusEx(&ms);
    return (jlong) ms.ullAvailPhys;
}

JNIEXPORT jlong JNICALL
Java_sun_management_OperatingSystemImpl_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_sun_management_OperatingSystemImpl_getSystemCpuLoad
(JNIEnv *env, jobject dummy)
{
    return perfGetCPULoad(-1);
}

JNIEXPORT jdouble JNICALL
Java_sun_management_OperatingSystemImpl_getProcessCpuLoad
(JNIEnv *env, jobject dummy)
{
    return perfGetProcessLoad();
}

Other Java examples (source code examples)

Here is a short list of links related to this Java OperatingSystemImpl.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.