Path: blob/master/src/hotspot/os/windows/os_perf_windows.cpp
40930 views
/*1* Copyright (c) 2012, 2021, 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.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "iphlp_interface.hpp"26#include "jvm_io.h"27#include "logging/log.hpp"28#include "memory/allocation.inline.hpp"29#include "memory/resourceArea.hpp"30#include "pdh_interface.hpp"31#include "runtime/os_perf.hpp"32#include "runtime/os.hpp"33#include "runtime/semaphore.inline.hpp"34#include "utilities/globalDefinitions.hpp"35#include "utilities/macros.hpp"36#include CPU_HEADER(vm_version_ext)37#include <math.h>38#include <psapi.h>39#include <TlHelp32.h>4041/*42* Windows provides a vast plethora of performance objects and counters,43* consumption of which is assisted using the Performance Data Helper (PDH) interface.44* We import a selected few api entry points from PDH, see pdh_interface.hpp.45*46* The code located in this file is to a large extent an abstraction over much of the47* plumbing needed to start consuming an object and/or counter of choice.48*49*50* How to use:51* 1. Create a query52* 2. Add counters to the query53* 3. Collect the performance data using the query54* 4. Read the performance data from counters associated with the query55* 5. Destroy query (counter destruction implied)56*57*58* Every PDH artifact, like processor, process, thread, memory, and so forth are59* identified with an index that is always the same irrespective60* of the localized version of the operating system or service pack installed.61* INFO: Using PDH APIs Correctly in a Localized Language (Q287159)62* http://support.microsoft.com/default.aspx?scid=kb;EN-US;q28715963*64* To find the correct index for an object or counter, inspect the registry key / value:65* [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]66*67* some common PDH indexes68*/69static const DWORD PDH_PROCESSOR_IDX = 238;70static const DWORD PDH_PROCESSOR_TIME_IDX = 6;71static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144;72static const DWORD PDH_PROCESS_IDX = 230;73static const DWORD PDH_ID_PROCESS_IDX = 784;74static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;75static const DWORD PDH_SYSTEM_IDX = 2;7677/* useful pdh fmt's for the general form: \object(instance#index)\counter */78static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";79static const size_t OBJECT_COUNTER_FMT_LEN = 2;80static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";81static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;82static const char* const PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s#%s)\\%s";83static const size_t PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 5;84static const char* const PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT = "\\%s(%s*)\\%s";85static const size_t PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT_LEN = 5;8687/* pdh string constants built up from fmts on initialization */88static const char* process_image_name = NULL; // e.g. "java" but could have another image name89static char* pdh_process_instance_IDProcess_counter_fmt = NULL; // "\Process(java#%d)\ID Process" */90static char* pdh_process_instance_wildcard_IDProcess_counter = NULL; // "\Process(java*)\ID Process" */9192/*93* Structs for PDH queries.94*/95typedef struct {96HQUERY pdh_query_handle;97s8 lastUpdate; // Last time query was updated.98} UpdateQueryS, *UpdateQueryP;99100101typedef struct {102UpdateQueryS query;103HCOUNTER counter;104bool initialized;105} CounterQueryS, *CounterQueryP;106107typedef struct {108UpdateQueryS query;109HCOUNTER* counters;110int noOfCounters;111bool initialized;112} MultiCounterQueryS, *MultiCounterQueryP;113114typedef struct {115MultiCounterQueryP queries;116int size;117bool initialized;118} MultiCounterQuerySetS, *MultiCounterQuerySetP;119120typedef struct {121MultiCounterQuerySetS set;122int process_idx;123} ProcessQueryS, *ProcessQueryP;124125static int open_query(HQUERY* pdh_query_handle) {126return PdhDll::PdhOpenQuery(NULL, 0, pdh_query_handle) != ERROR_SUCCESS ? OS_ERR : OS_OK;127}128129static int open_query(UpdateQueryP query) {130return open_query(&query->pdh_query_handle);131}132133template <typename QueryP>134static int open_query(QueryP query) {135return open_query(&query->query);136}137138static void close_query(HQUERY* const pdh_query_handle, HCOUNTER* const counter) {139if (counter != NULL && *counter != NULL) {140PdhDll::PdhRemoveCounter(*counter);141*counter = NULL;142}143if (pdh_query_handle != NULL && *pdh_query_handle != NULL) {144PdhDll::PdhCloseQuery(*pdh_query_handle);145*pdh_query_handle = NULL;146}147}148149static void close_query(MultiCounterQueryP query) {150for (int i = 0; i < query->noOfCounters; ++i) {151close_query(NULL, &query->counters[i]);152}153close_query(&query->query.pdh_query_handle, NULL);154query->initialized = false;155}156157static CounterQueryP create_counter_query() {158CounterQueryP const query = NEW_C_HEAP_OBJ(CounterQueryS, mtInternal);159memset(query, 0, sizeof(CounterQueryS));160return query;161}162163static MultiCounterQueryP create_multi_counter_query() {164MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);165memset(query, 0, sizeof(MultiCounterQueryS));166return query;167}168169static void destroy(CounterQueryP query) {170assert(query != NULL, "invariant");171close_query(&query->query.pdh_query_handle, &query->counter);172FREE_C_HEAP_OBJ(query);173}174175static void destroy(MultiCounterQueryP query) {176if (query != NULL) {177for (int i = 0; i < query->noOfCounters; ++i) {178close_query(NULL, &query->counters[i]);179}180FREE_C_HEAP_ARRAY(char, query->counters);181close_query(&query->query.pdh_query_handle, NULL);182FREE_C_HEAP_ARRAY(MultiCounterQueryS, query);183}184}185186static void destroy_query_set(MultiCounterQuerySetP query_set) {187for (int i = 0; i < query_set->size; i++) {188for (int j = 0; j < query_set->queries[i].noOfCounters; ++j) {189close_query(NULL, &query_set->queries[i].counters[j]);190}191FREE_C_HEAP_ARRAY(char, query_set->queries[i].counters);192close_query(&query_set->queries[i].query.pdh_query_handle, NULL);193}194FREE_C_HEAP_ARRAY(MultiCounterQueryS, query_set->queries);195}196197static void destroy(MultiCounterQuerySetP query) {198destroy_query_set(query);199FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, query);200}201202static void destroy(ProcessQueryP query) {203destroy_query_set(&query->set);204FREE_C_HEAP_OBJ(query);205}206207static void allocate_counters(MultiCounterQueryP query, size_t nofCounters) {208assert(query != NULL, "invariant");209assert(!query->initialized, "invariant");210assert(0 == query->noOfCounters, "invariant");211assert(query->counters == NULL, "invariant");212query->counters = NEW_C_HEAP_ARRAY(HCOUNTER, nofCounters, mtInternal);213memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));214query->noOfCounters = (int)nofCounters;215}216217static void allocate_counters(MultiCounterQuerySetP query, size_t nofCounters) {218assert(query != NULL, "invariant");219assert(!query->initialized, "invariant");220for (int i = 0; i < query->size; ++i) {221allocate_counters(&query->queries[i], nofCounters);222}223}224225static void allocate_counters(ProcessQueryP query, size_t nofCounters) {226assert(query != NULL, "invariant");227allocate_counters(&query->set, nofCounters);228}229230static void deallocate_counters(MultiCounterQueryP query) {231FREE_C_HEAP_ARRAY(char, query->counters);232query->counters = NULL;233query->noOfCounters = 0;234}235236static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* counter_path, bool first_sample_on_init) {237assert(query != NULL, "invariant");238assert(counter != NULL, "invariant");239assert(counter_path != NULL, "invariant");240if (query->pdh_query_handle == NULL) {241if (open_query(query) != OS_OK) {242return OS_ERR;243}244}245assert(query->pdh_query_handle != NULL, "invariant");246PDH_STATUS status = PdhDll::PdhAddCounter(query->pdh_query_handle, counter_path, 0, counter);247if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {248return OS_ERR;249}250/*251* According to the MSDN documentation, rate counters must be read twice:252*253* "Obtaining the value of rate counters such as Page faults/sec requires that254* PdhCollectQueryData be called twice, with a specific time interval between255* the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to256* implement the waiting period between the two calls to PdhCollectQueryData."257*258* Take the first sample here already to allow for the next "real" sample259* to succeed.260*/261if (first_sample_on_init && PdhDll::PdhCollectQueryData(query->pdh_query_handle) != ERROR_SUCCESS) {262return OS_ERR;263}264return OS_OK;265}266267template <typename QueryP>268static OSReturn add_counter(QueryP query, HCOUNTER* counter, const char* counter_path, bool first_sample_on_init) {269assert(query != NULL, "invariant");270assert(counter != NULL, "invariant");271assert(counter_path != NULL, "invariant");272return add_counter(&query->query, counter, counter_path, first_sample_on_init);273}274275// if add_counter fails with OS_ERR, the performance counter might be disabled in the registry276static OSReturn add_counter(CounterQueryP query, const char* counter_path, bool first_sample_on_init = true) {277return add_counter(query, &query->counter, counter_path, first_sample_on_init);278}279280static OSReturn add_counter(MultiCounterQueryP query, int counter_idx, const char* counter_path, bool first_sample_on_init) {281assert(query != NULL, "invariant");282assert(counter_idx < query->noOfCounters, "invariant");283assert(query->counters[counter_idx] == NULL, "invariant");284return add_counter(query, &query->counters[counter_idx], counter_path, first_sample_on_init);285}286287// Need to limit how often we update a query to minimize the heisenberg effect.288// (PDH behaves erratically if the counters are queried too often, especially counters that289// store and use values from two consecutive updates, like cpu load.)290static const int min_update_interval_millis = 500;291292static int collect(UpdateQueryP query) {293assert(query != NULL, "invariant");294const s8 now = os::javaTimeNanos();295if (nanos_to_millis(now - query->lastUpdate) > min_update_interval_millis) {296if (PdhDll::PdhCollectQueryData(query->pdh_query_handle) != ERROR_SUCCESS) {297return OS_ERR;298}299query->lastUpdate = now;300}301return OS_OK;302}303304template <typename QueryP>305static int collect(QueryP query) {306assert(query != NULL, "invariant");307return collect(&query->query);308}309310static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {311assert(value != NULL, "invariant");312return PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS ? OS_ERR : OS_OK;313}314315static int read_counter(CounterQueryP query, DWORD format, PDH_FMT_COUNTERVALUE* const value) {316assert(query != NULL, "invariant");317return formatted_counter_value(query->counter, format, value);318}319320static int read_counter(MultiCounterQueryP query, int counter_idx, DWORD format, PDH_FMT_COUNTERVALUE* const value) {321assert(query != NULL, "invariant");322assert(counter_idx < query->noOfCounters, "invariant");323assert(query->counters[counter_idx] != NULL, "invariant");324return formatted_counter_value(query->counters[counter_idx], format, value);325}326327static int read_counter(ProcessQueryP query, int counter_idx, DWORD format, PDH_FMT_COUNTERVALUE* const value) {328assert(query != NULL, "invariant");329MultiCounterQueryP const current_query = &query->set.queries[query->process_idx];330assert(current_query != NULL, "invariant");331return read_counter(current_query, counter_idx, format, value);332}333334/*335* The routine expands a process object path including a wildcard to fetch the list of process instances336* having the same name, i.e. "java" or rather the value of process_image_name.337* A tally of this list is returned to the caller.338*/339static int number_of_live_process_instances() {340char* buffer = NULL;341DWORD size = 0;342// determine size343PDH_STATUS status = PdhDll::PdhExpandWildCardPath(NULL,344pdh_process_instance_wildcard_IDProcess_counter,345buffer,346&size,347PDH_NOEXPANDCOUNTERS);348while (status == PDH_MORE_DATA) {349buffer = NEW_RESOURCE_ARRAY(char, size);350status = PdhDll::PdhExpandWildCardPath(NULL,351pdh_process_instance_wildcard_IDProcess_counter,352buffer,353&size,354PDH_NOEXPANDCOUNTERS);355}356if (status != ERROR_SUCCESS) {357return OS_ERR;358}359// count the number of live process instances360int instances = 0;361const char* const end = buffer + size;362for (char* next = buffer; next != end && (*next != '\0'); next = &next[strlen(next) + 1], ++instances);363assert(instances > 0, "invariant");364return instances;365}366367static PDH_STATUS pdh_process_idx_to_pid(HQUERY& pdh_query_handle, int idx, LONG* pid) {368assert(pid != NULL, "invariant");369char counter_path[PDH_MAX_COUNTER_PATH];370jio_snprintf(counter_path, sizeof(counter_path) - 1, pdh_process_instance_IDProcess_counter_fmt, idx);371assert(strlen(counter_path) < sizeof(counter_path), "invariant");372HCOUNTER counter = NULL;373PDH_STATUS status = PdhDll::PdhAddCounter(pdh_query_handle, counter_path, 0, &counter);374if (status != ERROR_SUCCESS) {375close_query(&pdh_query_handle, &counter);376return status;377}378status = PdhDll::PdhCollectQueryData(pdh_query_handle);379if (status != ERROR_SUCCESS) {380close_query(NULL, &counter);381return PDH_NO_DATA;382}383PDH_FMT_COUNTERVALUE counter_value;384status = formatted_counter_value(counter, PDH_FMT_LONG, &counter_value);385if (status != OS_OK) {386close_query(&pdh_query_handle, &counter);387return status;388}389*pid = counter_value.longValue;390close_query(NULL, &counter);391return ERROR_SUCCESS;392}393394395/*396* Max process query index is derived from the total number of live process instances, seen397* as a snap-shot at the point of initialization, i.e. processes having the same name, e.g. "java".398* The total number of live processes includes this process and this number - 1 is the maximum index399* to be used in a process query.400*/401static int max_process_query_idx = 0;402403/*404* Working with the Process object and its related counters is inherently405* problematic when using the PDH API:406*407* A process is not primarily identified by the process id, but by an opaque408* index into a list maintained by the kernel. To distinguish which409* process instance is the intended target for a query, the PDH Process API demands,410* at time of registration, a string describing the target process name concatenated411* with the value for this index. For example:412* "\Process(java#0)", "\Process(java#1)", ...413*414* The bad part is that this list is constantly in-flux as415* processes are exiting. One consequence is that processes with indexes416* greater than the one that just terminated is now shifted down by one.417* For example:418* if \Process(java#1) exits, \Process(java#2) now becomes \Process(java#1),419* \Process(java#2) becomes \Process(java#1) ...420*421* To make matters even more exciting, an already registered query is not invalidated422* when the process list changes. Instead, the query will continue to work just as before,423* or at least, so it seems.424* Only, now, the query will read performance data from another process instance!425* That's right, the performance data is now read from the process that was shifted426* down by the kernel to occupy the index slot associated with our original registration.427*428* Solution:429* The #index identifier for a Process query can only decrease after process creation.430*431* We therefore create an array of counter queries for all process object instances432* up to and including ourselves:433*434* E.g. we come in as the third process instance (java#2), we then create and register435* queries for the following Process object instances:436* java#0, java#1, java#2437*438* current_process_query_index() finds the "correct" pdh process query index by inspecting439* the pdh process list, at a particular instant, i.e. just before we issue the real process query.440* Of course, this is an inherently racy situation because the pdh process list can change at any time.441* We use current_process_query_index() to help keep the number of data errors low,442* where a data error is defined to be the result of using a stale index to query the wrong process.443*444* Ensure to call ensure_current_process_query_index() before every query involving Process object instance data.445*446* returns OS_ERR(-1) if anything goes wrong in the discovery process.447*/448449static int current_process_query_index(int previous_query_idx = 0) {450assert(max_process_query_idx >= 0, "invariant");451assert(max_process_query_idx >= previous_query_idx, "invariant");452assert(process_image_name != NULL, "invariant");453assert(pdh_process_instance_IDProcess_counter_fmt != NULL, "invariant");454int result = OS_ERR;455HQUERY tmp_pdh_query_handle = NULL;456if (open_query(&tmp_pdh_query_handle) != OS_OK) {457return OS_ERR;458}459// We need to find the correct pdh process index corresponding to our process identifier (pid).460// Begin from the index that was valid at the time of the last query. If that index is no longer valid,461// it means the pdh process list has changed, i.e. because other processes with the same name as us have terminated.462// Seek downwards to find the updated, now downshifted, list index corresponding to our pid.463static const LONG current_pid = (LONG)os::current_process_id();464const int start_idx = previous_query_idx != 0 ? previous_query_idx : max_process_query_idx;465for (int idx = start_idx; idx >= 0; --idx) {466LONG pid;467const PDH_STATUS status = pdh_process_idx_to_pid(tmp_pdh_query_handle, idx, &pid);468if (status == PDH_NO_DATA) {469// pdh process list has changed470continue;471}472if (status != ERROR_SUCCESS) {473// something went wrong, tmp_pdh_query_handle is already closed.474return OS_ERR;475}476if (current_pid == pid) {477result = idx;478break;479}480}481close_query(&tmp_pdh_query_handle, NULL);482return result;483}484485static int ensure_current_process_query_index(ProcessQueryP query) {486assert(query != NULL, "invariant");487const int previous_query_idx = query->process_idx;488if (previous_query_idx == 0) {489return previous_query_idx;490}491const int current_query_idx = current_process_query_index(previous_query_idx);492if (current_query_idx == OS_ERR || current_query_idx >= query->set.size) {493return OS_ERR;494}495if (current_query_idx == previous_query_idx) {496return previous_query_idx;497}498assert(current_query_idx >= 0 && current_query_idx < query->set.size, "out of bounds!");499while (current_query_idx < query->set.size - 1) {500const int new_size = --query->set.size;501close_query(&query->set.queries[new_size]);502}503assert(current_query_idx < query->set.size, "invariant");504query->process_idx = current_query_idx;505return OS_OK;506}507508static MultiCounterQueryP current_process_query(ProcessQueryP query) {509assert(query != NULL, "invariant");510if (ensure_current_process_query_index(query) == OS_ERR) {511return NULL;512}513assert(query->process_idx < query->set.size, "invariant");514return &query->set.queries[query->process_idx];515}516517static int collect(ProcessQueryP query) {518assert(query != NULL, "invariant");519MultiCounterQueryP current_query = current_process_query(query);520return current_query != NULL ? collect(current_query) : OS_ERR;521}522523/*524* Construct a fully qualified PDH counter path.525*526* @param object_name a PDH Object string representation(required)527* @param counter_name a PDH Counter string representation(required)528* @param image_name a process image name string, ex. "java" (opt)529* @param instance an instance string, ex. "0", "1", ... (opt)530* @return the fully qualified PDH counter path.531*532* Caller will need a ResourceMark.533*534* (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)535*/536static const char* make_fully_qualified_counter_path(const char* object_name,537const char* counter_name,538const char* image_name = NULL,539const char* instance = NULL) {540assert(object_name != NULL, "invariant");541assert(counter_name != NULL, "invariant");542size_t counter_path_len = strlen(object_name) + strlen(counter_name);543544char* counter_path;545size_t jio_snprintf_result = 0;546if (image_name) {547/*548* For paths using the "Process" Object.549*550* Examples:551* form: "\object_name(image_name#instance)\counter_name"552* actual: "\Process(java#2)\ID Process"553*/554counter_path_len += PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;555counter_path_len += strlen(image_name);556/*557* image_name must be passed together with an associated558* instance "number" ("0", "1", "2", ...).559* This is required in order to create valid "Process" Object paths.560*561* Examples: "\Process(java#0)", \Process(java#1"), ...562*/563assert(instance != NULL, "invariant");564counter_path_len += strlen(instance);565counter_path = NEW_RESOURCE_ARRAY(char, counter_path_len + 1);566jio_snprintf_result = jio_snprintf(counter_path,567counter_path_len + 1,568PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT,569object_name,570image_name,571instance,572counter_name);573} else {574if (instance) {575/*576* For paths where the Object has multiple instances.577*578* Examples:579* form: "\object_name(instance)\counter_name"580* actual: "\Processor(0)\% Privileged Time"581*/582counter_path_len += strlen(instance);583counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;584} else {585/*586* For "normal" paths.587*588* Examples:589* form: "\object_name\counter_name"590* actual: "\Memory\Available Mbytes"591*/592counter_path_len += OBJECT_COUNTER_FMT_LEN;593}594counter_path = NEW_RESOURCE_ARRAY(char, counter_path_len + 1);595if (instance) {596jio_snprintf_result = jio_snprintf(counter_path,597counter_path_len + 1,598OBJECT_WITH_INSTANCES_COUNTER_FMT,599object_name,600instance,601counter_name);602} else {603jio_snprintf_result = jio_snprintf(counter_path,604counter_path_len + 1,605OBJECT_COUNTER_FMT,606object_name,607counter_name);608}609}610assert(counter_path_len == jio_snprintf_result, "invariant");611return counter_path;612}613614static void log_invalid_pdh_index(DWORD index) {615log_warning(os)("Unable to resolve PDH index: (%ld)", index);616log_warning(os)("Please check the registry if this performance object/counter is disabled");617}618619static bool is_valid_pdh_index(DWORD index) {620DWORD dummy = 0;621if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) {622log_invalid_pdh_index(index);623return false;624}625return true;626}627628/*629* Maps an index to a resource area allocated string for the localized PDH artifact.630*631* Caller will need a ResourceMark.632*633* @param index the counter index as specified in the registry634* @param p_string pointer to a char*635* @return OS_OK if successful, OS_ERR on failure.636*/637static OSReturn lookup_name_by_index(DWORD index, char** p_string) {638assert(p_string != NULL, "invariant");639if (!is_valid_pdh_index(index)) {640return OS_ERR;641}642// determine size needed643DWORD size = 0;644PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);645assert(status == PDH_MORE_DATA, "invariant");646*p_string = NEW_RESOURCE_ARRAY(char, size);647if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {648return OS_ERR;649}650if (0 == size || *p_string == NULL) {651return OS_ERR;652}653// windows vista does not null-terminate the string (although the docs says it will)654(*p_string)[size - 1] = '\0';655return OS_OK;656}657658static const char* copy_string_to_c_heap(const char* string) {659assert(string != NULL, "invariant");660const size_t len = strlen(string);661char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);662strncpy(cheap_allocated_string, string, len + 1);663return cheap_allocated_string;664}665666/*667* Maps a pdh artifact index to a resource area allocated string representing a localized name.668*669* Caller will need a ResourceMark.670*671* @param pdh_artifact_idx the counter index as specified in the registry672* @return localized pdh artifact string if successful, NULL on failure.673*/674static const char* pdh_localized_artifact(DWORD pdh_artifact_idx) {675char* pdh_localized_artifact_string = NULL;676// get localized name for the pdh artifact idx677if (lookup_name_by_index(pdh_artifact_idx, &pdh_localized_artifact_string) != OS_OK) {678return NULL;679}680return pdh_localized_artifact_string;681}682683/*684* Returns the PDH string identifying the current process image name.685* Use this prefix when getting counters from the PDH process object686* representing your process.687* Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process688* image description.689*690* Caller needs ResourceMark.691*692* @return the process image string description, NULL if the call failed.693*/694static const char* pdh_process_image_name() {695char* module_name = NEW_RESOURCE_ARRAY(char, MAX_PATH);696// Find our module name and use it to extract the image name used by PDH697DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH);698if (getmfn_return >= MAX_PATH || 0 == getmfn_return) {699return NULL;700}701if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) {702return NULL;703}704char* process_image_name = strrchr(module_name, '\\'); //drop path705process_image_name++; //skip slash706char* dot_pos = strrchr(process_image_name, '.'); //drop .exe707dot_pos[0] = '\0';708return process_image_name;709}710711static void deallocate_pdh_constants() {712FREE_C_HEAP_ARRAY(char, process_image_name);713process_image_name = NULL;714FREE_C_HEAP_ARRAY(char, pdh_process_instance_IDProcess_counter_fmt);715pdh_process_instance_IDProcess_counter_fmt = NULL;716FREE_C_HEAP_ARRAY(char, pdh_process_instance_wildcard_IDProcess_counter);717pdh_process_instance_wildcard_IDProcess_counter = NULL;718}719720static OSReturn allocate_pdh_constants() {721assert(process_image_name == NULL, "invariant");722const char* pdh_image_name = pdh_process_image_name();723if (pdh_image_name == NULL) {724return OS_ERR;725}726process_image_name = copy_string_to_c_heap(pdh_image_name);727728const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX);729if (pdh_localized_process_object == NULL) {730return OS_ERR;731}732733const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX);734if (pdh_localized_IDProcess_counter == NULL) {735return OS_ERR;736}737738const size_t id_process_base_length = strlen(process_image_name) +739strlen(pdh_localized_process_object) +740strlen(pdh_localized_IDProcess_counter);741742const size_t pdh_IDProcess_counter_fmt_len = id_process_base_length +743PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN +7442; // "%d"745746assert(pdh_process_instance_IDProcess_counter_fmt == NULL, "invariant");747pdh_process_instance_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);748749/* "\Process(java#%d)\ID Process" */750size_t len = jio_snprintf(pdh_process_instance_IDProcess_counter_fmt,751pdh_IDProcess_counter_fmt_len + 1,752PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT,753pdh_localized_process_object,754process_image_name,755"%d",756pdh_localized_IDProcess_counter);757758assert(pdh_process_instance_IDProcess_counter_fmt != NULL, "invariant");759assert(len == pdh_IDProcess_counter_fmt_len, "invariant");760761762const size_t pdh_IDProcess_wildcard_fmt_len = id_process_base_length +763PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT_LEN;764765assert(pdh_process_instance_wildcard_IDProcess_counter == NULL, "invariant");766pdh_process_instance_wildcard_IDProcess_counter = NEW_C_HEAP_ARRAY(char, pdh_IDProcess_wildcard_fmt_len + 1, mtInternal);767768/* "\Process(java*)\ID Process" */769len = jio_snprintf(pdh_process_instance_wildcard_IDProcess_counter,770pdh_IDProcess_wildcard_fmt_len + 1,771PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT,772pdh_localized_process_object,773process_image_name,774pdh_localized_IDProcess_counter);775776assert(pdh_process_instance_wildcard_IDProcess_counter != NULL, "invariant");777assert(len == pdh_IDProcess_wildcard_fmt_len, "invariant");778return OS_OK;779}780781/*782* Enuerate the Processor PDH object and returns a buffer containing the enumerated instances.783* Caller needs ResourceMark;784*785* @return buffer if successful, NULL on failure.786*/787static const char* enumerate_cpu_instances() {788char* processor; //'Processor' == PDH_PROCESSOR_IDX789if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {790return NULL;791}792DWORD c_size = 0;793DWORD i_size = 0;794// enumerate all processors.795PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved796NULL, // local machine797processor, // object to enumerate798NULL,799&c_size,800NULL, // instance buffer is NULL and801&i_size, // pass 0 length in order to get the required size802PERF_DETAIL_WIZARD, // counter detail level8030);804if (PdhDll::PdhStatusFail((pdhStat))) {805return NULL;806}807char* const instances = NEW_RESOURCE_ARRAY(char, i_size);808c_size = 0;809pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved810NULL, // local machine811processor, // object to enumerate812NULL,813&c_size,814instances, // now instance buffer is allocated to be filled in815&i_size, // and the required size is known816PERF_DETAIL_WIZARD, // counter detail level8170);818return PdhDll::PdhStatusFail(pdhStat) ? NULL : instances;819}820821static int count_logical_cpus(const char* instances) {822assert(instances != NULL, "invariant");823// count logical instances.824DWORD count;825char* tmp;826for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++);827// PDH reports an instance for each logical processor plus an instance for the total (_Total)828assert(count == os::processor_count() + 1, "invalid enumeration!");829return count - 1;830}831832static int number_of_logical_cpus() {833static int numberOfCPUS = 0;834if (numberOfCPUS == 0) {835const char* instances = enumerate_cpu_instances();836if (instances == NULL) {837return OS_ERR;838}839numberOfCPUS = count_logical_cpus(instances);840}841return numberOfCPUS;842}843844static double cpu_factor() {845static DWORD numCpus = 0;846static double cpuFactor = .0;847if (numCpus == 0) {848numCpus = number_of_logical_cpus();849assert(os::processor_count() <= (int)numCpus, "invariant");850cpuFactor = numCpus * 100;851}852return cpuFactor;853}854855static void log_error_message_on_no_PDH_artifact(const char* counter_path) {856log_warning(os)("Unable to register PDH query for \"%s\"", counter_path);857log_warning(os)("Please check the registry if this performance object/counter is disabled");858}859860static int initialize_cpu_query_counters(MultiCounterQueryP query, DWORD pdh_counter_idx) {861assert(query != NULL, "invariant");862assert(query->counters != NULL, "invariant");863char* processor; //'Processor' == PDH_PROCESSOR_IDX864if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {865return OS_ERR;866}867char* counter_name = NULL;868if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {869return OS_ERR;870}871if (query->query.pdh_query_handle == NULL) {872if (open_query(query) != OS_OK) {873return OS_ERR;874}875}876assert(query->query.pdh_query_handle != NULL, "invariant");877size_t counter_len = strlen(processor);878counter_len += strlen(counter_name);879counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s"880const char* instances = enumerate_cpu_instances();881DWORD index = 0;882for (char* tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {883const size_t tmp_len = strlen(tmp);884char* counter_path = NEW_RESOURCE_ARRAY(char, counter_len + tmp_len + 1);885const size_t jio_snprintf_result = jio_snprintf(counter_path,886counter_len + tmp_len + 1,887OBJECT_WITH_INSTANCES_COUNTER_FMT,888processor,889tmp, // instance "0", "1", .."_Total"890counter_name);891assert(counter_len + tmp_len == jio_snprintf_result, "invariant");892if (add_counter(query, &query->counters[index], counter_path, false) != OS_OK) {893// performance counter is disabled in registry and not accessible via PerfLib894log_error_message_on_no_PDH_artifact(counter_path);895// return OS_OK to have the system continue to run without the missing counter896return OS_OK;897}898}899// Query once to initialize the counters which require at least two samples900// (like the % CPU usage) to calculate correctly.901return PdhDll::PdhCollectQueryData(query->query.pdh_query_handle) != ERROR_SUCCESS ? OS_ERR : OS_OK;902}903904static int initialize_cpu_query(MultiCounterQueryP query) {905assert(query != NULL, "invariant");906assert(!query->initialized, "invariant");907const int logical_cpu_count = number_of_logical_cpus();908assert(logical_cpu_count >= os::processor_count(), "invariant");909// we also add another counter for instance "_Total"910allocate_counters(query, logical_cpu_count + 1);911assert(query->noOfCounters == logical_cpu_count + 1, "invariant");912if (initialize_cpu_query_counters(query, PDH_PROCESSOR_TIME_IDX) != OS_OK) {913return OS_ERR;914}915query->initialized = true;916return OS_OK;917}918919static int initialize_query(CounterQueryP query, DWORD pdh_object_idx, DWORD pdh_counter_idx) {920assert(query != NULL, "invariant");921assert(!query->initialized, "invariant");922if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {923return OS_ERR;924}925const char* object = pdh_localized_artifact(pdh_object_idx);926assert(object != NULL, "invariant");927const char* counter = pdh_localized_artifact(pdh_counter_idx);928assert(counter != NULL, "invariant");929const char* counter_path = make_fully_qualified_counter_path(object, counter);930assert(counter_path != NULL, "invariant");931if (add_counter(query, counter_path, true) != OS_OK) {932return OS_ERR;933}934query->initialized = true;935return OS_OK;936}937938static int initialize_context_switches_query(CounterQueryP query) {939return initialize_query(query, PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);940}941942static ProcessQueryP create_process_query() {943const int current_process_query_idx = current_process_query_index();944if (current_process_query_idx == OS_ERR) {945return NULL;946}947ProcessQueryP const query = NEW_C_HEAP_OBJ(ProcessQueryS, mtInternal);948memset(query, 0, sizeof(ProcessQueryS));949query->process_idx = current_process_query_idx;950const int size = current_process_query_idx + 1;951query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, size, mtInternal);952memset(query->set.queries, 0, sizeof(MultiCounterQueryS) * size);953query->set.size = size;954return query;955}956957static int initialize_process_counter(ProcessQueryP process_query, int counter_idx, DWORD pdh_counter_idx) {958char* localized_process_object;959if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {960return OS_ERR;961}962assert(localized_process_object != NULL, "invariant");963char* localized_counter_name;964if (lookup_name_by_index(pdh_counter_idx, &localized_counter_name) != OS_OK) {965return OS_ERR;966}967assert(localized_counter_name != NULL, "invariant");968for (int i = 0; i < process_query->set.size; ++i) {969char instanceIndexBuffer[32];970const char* counter_path = make_fully_qualified_counter_path(localized_process_object,971localized_counter_name,972process_image_name,973itoa(i, instanceIndexBuffer, 10));974assert(counter_path != NULL, "invariant");975MultiCounterQueryP const query = &process_query->set.queries[i];976if (add_counter(query, counter_idx, counter_path, true) != OS_OK) {977return OS_ERR;978}979if (counter_idx + 1 == query->noOfCounters) {980// last counter in query implies query initialized981query->initialized = true;982}983}984return OS_OK;985}986987static int initialize_process_query(ProcessQueryP query) {988assert(query != NULL, "invariant");989assert(!query->set.initialized, "invariant");990allocate_counters(query, 2);991if (initialize_process_counter(query, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {992return OS_ERR;993}994if (initialize_process_counter(query, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {995return OS_ERR;996}997query->set.initialized = true;998return OS_OK;999}10001001static int reference_count = 0;1002static bool pdh_initialized = false;10031004class PdhMutex : public StackObj {1005private:1006static Semaphore _semaphore;1007public:1008PdhMutex() {1009_semaphore.wait();1010}1011~PdhMutex() {1012_semaphore.signal();1013}1014};10151016Semaphore PdhMutex::_semaphore(1);10171018static void on_initialization_failure() {1019// still holder of mutex1020assert(max_process_query_idx == 0, "invariant");1021deallocate_pdh_constants();1022--reference_count;1023PdhDll::PdhDetach();1024}10251026static OSReturn initialize() {1027// still holder of mutex1028ResourceMark rm;1029if (!PdhDll::PdhAttach()) {1030return OS_ERR;1031}1032if (allocate_pdh_constants() != OS_OK) {1033on_initialization_failure();1034return OS_ERR;1035}1036// Take a snapshot of the current number of live processes (including ourselves)1037// with the same name, e.g. "java", in order to derive a value for max_process_query_idx.1038const int process_instance_count = number_of_live_process_instances();1039if (process_instance_count == OS_ERR) {1040on_initialization_failure();1041return OS_ERR;1042}1043assert(process_instance_count > 0, "invariant");1044max_process_query_idx = process_instance_count - 1;1045return OS_OK;1046}10471048/*1049* Helper to initialize the PDH library, function pointers, constants and counters.1050*1051* Reference counting allows for unloading of pdh.dll granted all sessions use the pair:1052*1053* pdh_acquire();1054* pdh_release();1055*1056* @return OS_OK if successful, OS_ERR on failure.1057*/1058static OSReturn pdh_acquire() {1059PdhMutex mutex;1060reference_count++;1061if (pdh_initialized) {1062return OS_OK;1063}1064const OSReturn status = initialize();1065pdh_initialized = status == OS_OK;1066return status;1067}10681069static void pdh_release() {1070PdhMutex mutex;1071if (1 == reference_count--) {1072deallocate_pdh_constants();1073PdhDll::PdhDetach();1074pdh_initialized = false;1075}1076}10771078class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {1079friend class CPUPerformanceInterface;1080private:1081CounterQueryP _context_switches;1082ProcessQueryP _process_cpu_load;1083MultiCounterQueryP _machine_cpu_load;10841085int cpu_load(int which_logical_cpu, double* cpu_load);1086int context_switch_rate(double* rate);1087int cpu_load_total_process(double* cpu_load);1088int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* system_total_load);1089CPUPerformance();1090~CPUPerformance();1091bool initialize();1092};10931094CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}10951096bool CPUPerformanceInterface::CPUPerformance::initialize() {1097if (pdh_acquire() != OS_OK) {1098return false;1099}1100_context_switches = create_counter_query();1101assert(_context_switches != NULL, "invariant");1102if (initialize_context_switches_query(_context_switches) != OS_OK) {1103return false;1104}1105assert(_context_switches->initialized, "invariant");1106_process_cpu_load = create_process_query();1107if (_process_cpu_load == NULL) {1108return false;1109}1110if (initialize_process_query(_process_cpu_load) != OS_OK) {1111return false;1112}1113assert(_process_cpu_load->set.initialized, "invariant");1114_machine_cpu_load = create_multi_counter_query();1115assert(_machine_cpu_load != NULL, "invariant");1116if (initialize_cpu_query(_machine_cpu_load) != OS_OK) {1117return false;1118}1119assert(_machine_cpu_load->initialized, "invariant");1120return true;1121}11221123CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {1124if (_context_switches != NULL) {1125destroy(_context_switches);1126_context_switches = NULL;1127}1128if (_process_cpu_load != NULL) {1129destroy(_process_cpu_load);1130_process_cpu_load = NULL;1131}1132if (_machine_cpu_load != NULL) {1133destroy(_machine_cpu_load);1134_machine_cpu_load = NULL;1135}1136pdh_release();1137}11381139CPUPerformanceInterface::CPUPerformanceInterface() : _impl(NULL) {}11401141bool CPUPerformanceInterface::initialize() {1142_impl = new CPUPerformanceInterface::CPUPerformance();1143return _impl->initialize();1144}11451146CPUPerformanceInterface::~CPUPerformanceInterface() {1147if (_impl != NULL) {1148delete _impl;1149}1150}11511152int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {1153return _impl->cpu_load(which_logical_cpu, cpu_load);1154}11551156int CPUPerformanceInterface::context_switch_rate(double* rate) const {1157return _impl->context_switch_rate(rate);1158}11591160int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {1161return _impl->cpu_load_total_process(cpu_load);1162}11631164int CPUPerformanceInterface::cpu_loads_process(double* jvm_user_load,1165double* jvm_kernel_load,1166double* system_total_load) const {1167return _impl->cpu_loads_process(jvm_user_load, jvm_kernel_load, system_total_load);1168}11691170int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {1171*cpu_load = .0;1172if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) {1173return OS_ERR;1174}1175assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");1176if (collect(_machine_cpu_load) != OS_OK) {1177return OS_ERR;1178}1179// -1 is total (all cpus)1180const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;1181PDH_FMT_COUNTERVALUE counter_value;1182if (read_counter(_machine_cpu_load, counter_idx, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {1183return OS_ERR;1184}1185*cpu_load = counter_value.doubleValue / 100;1186return OS_OK;1187}11881189int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {1190*cpu_load = .0;1191if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {1192return OS_ERR;1193}1194if (collect(_process_cpu_load) != OS_OK) {1195return OS_ERR;1196}1197PDH_FMT_COUNTERVALUE counter_value;1198if (read_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1199return OS_ERR;1200}1201double process_load = counter_value.doubleValue / cpu_factor();1202process_load = MIN2<double>(1, process_load);1203process_load = MAX2<double>(0, process_load);1204*cpu_load = process_load;1205return OS_OK;1206}12071208int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* jvm_user_load,1209double* jvm_kernel_load,1210double* system_total_load) {1211assert(jvm_user_load != NULL, "jvm_user_load is NULL!");1212assert(jvm_kernel_load != NULL, "jvm_kernel_load is NULL!");1213assert(system_total_load != NULL, "system_total_load is NULL!");1214*jvm_user_load = .0;1215*jvm_kernel_load = .0;1216*system_total_load = .0;12171218if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {1219return OS_ERR;1220}1221if (collect(_process_cpu_load) != OS_OK) {1222return OS_ERR;1223}1224double process_load = .0;1225PDH_FMT_COUNTERVALUE counter_value;1226// Read PDH_PROCESSOR_TIME_IDX as counter_idx == 01227if (read_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1228return OS_ERR;1229}1230process_load = counter_value.doubleValue / cpu_factor();1231process_load = MIN2<double>(1, process_load);1232process_load = MAX2<double>(0, process_load);1233// Read PDH_PRIV_PROCESSOR_TIME_IDX as counter_idx == 11234if (read_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1235return OS_ERR;1236}1237double process_kernel_load = counter_value.doubleValue / cpu_factor();1238process_kernel_load = MIN2<double>(1, process_kernel_load);1239process_kernel_load = MAX2<double>(0, process_kernel_load);1240*jvm_kernel_load = process_kernel_load;12411242double user_load = process_load - process_kernel_load;1243user_load = MIN2<double>(1, user_load);1244user_load = MAX2<double>(0, user_load);1245*jvm_user_load = user_load;1246if (collect(_machine_cpu_load) != OS_OK) {1247return OS_ERR;1248}1249// Read PDH_PROCESSOR_IDX as counter_idx == _machine_cpu_load->noOfCounters - 11250if (read_counter(_machine_cpu_load, _machine_cpu_load->noOfCounters - 1, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {1251return OS_ERR;1252}1253double machine_load = counter_value.doubleValue / 100;1254assert(machine_load >= 0, "machine_load is negative!");1255// clamp at user+system and 1.01256if (*jvm_kernel_load + *jvm_user_load > machine_load) {1257machine_load = MIN2(*jvm_kernel_load + *jvm_user_load, 1.0);1258}1259*system_total_load = machine_load;1260return OS_OK;1261}12621263int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {1264assert(rate != NULL, "invariant");1265*rate = .0;1266if (_context_switches == NULL || !_context_switches->initialized) {1267return OS_ERR;1268}1269if (collect(_context_switches) != OS_OK) {1270return OS_ERR;1271}1272PDH_FMT_COUNTERVALUE counter_value;1273if (read_counter(_context_switches, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {1274return OS_ERR;1275}1276*rate = counter_value.doubleValue;1277return OS_OK;1278}12791280class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {1281friend class SystemProcessInterface;1282private:1283class ProcessIterator : public CHeapObj<mtInternal> {1284friend class SystemProcessInterface::SystemProcesses;1285private:1286HANDLE _hProcessSnap;1287PROCESSENTRY32 _pe32;1288BOOL _valid;1289char _exePath[MAX_PATH];1290ProcessIterator();1291~ProcessIterator();1292bool initialize();12931294int current(SystemProcess* const process_info);1295int next_process();1296bool is_valid() const { return _valid != FALSE; }1297char* allocate_string(const char* str) const;1298int snapshot();1299};13001301ProcessIterator* _iterator;1302SystemProcesses();1303~SystemProcesses();1304bool initialize();13051306// information about system processes1307int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;1308};13091310SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {1311_hProcessSnap = INVALID_HANDLE_VALUE;1312_valid = FALSE;1313_pe32.dwSize = sizeof(PROCESSENTRY32);1314}13151316bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {1317return true;1318}13191320int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() {1321// take snapshot of all process in the system1322_hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);1323if (_hProcessSnap == INVALID_HANDLE_VALUE) {1324return OS_ERR;1325}1326// step to first process1327_valid = Process32First(_hProcessSnap, &_pe32);1328return is_valid() ? OS_OK : OS_ERR;1329}13301331SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {1332if (_hProcessSnap != INVALID_HANDLE_VALUE) {1333CloseHandle(_hProcessSnap);1334}1335}13361337int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {1338assert(is_valid(), "no current process to be fetched!");1339assert(process_info != NULL, "process_info is NULL!");1340char* exePath = NULL;1341HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID);1342if (hProcess != NULL) {1343HMODULE hMod;1344DWORD cbNeeded;1345if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) {1346if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) {1347exePath = _exePath;1348}1349}1350CloseHandle (hProcess);1351}1352process_info->set_pid((int)_pe32.th32ProcessID);1353process_info->set_name(allocate_string(_pe32.szExeFile));1354process_info->set_path(allocate_string(exePath));1355return OS_OK;1356}13571358char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {1359return str != NULL ? os::strdup_check_oom(str, mtInternal) : NULL;1360}13611362int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {1363_valid = Process32Next(_hProcessSnap, &_pe32);1364return OS_OK;1365}13661367SystemProcessInterface::SystemProcesses::SystemProcesses() : _iterator(NULL) {}13681369bool SystemProcessInterface::SystemProcesses::initialize() {1370_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();1371return _iterator->initialize();1372}13731374SystemProcessInterface::SystemProcesses::~SystemProcesses() {1375if (_iterator != NULL) {1376delete _iterator;1377}1378}13791380int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes,1381int* no_of_sys_processes) const {1382assert(system_processes != NULL, "system_processes pointer is NULL!");1383assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");1384assert(_iterator != NULL, "iterator is NULL!");13851386// initialize pointers1387*no_of_sys_processes = 0;1388*system_processes = NULL;13891390// take process snapshot1391if (_iterator->snapshot() != OS_OK) {1392return OS_ERR;1393}13941395while (_iterator->is_valid()) {1396SystemProcess* tmp = new SystemProcess();1397_iterator->current(tmp);13981399//if already existing head1400if (*system_processes != NULL) {1401//move "first to second"1402tmp->set_next(*system_processes);1403}1404// new head1405*system_processes = tmp;1406// increment1407(*no_of_sys_processes)++;1408// step forward1409_iterator->next_process();1410}1411return OS_OK;1412}14131414int SystemProcessInterface::system_processes(SystemProcess** system_procs,1415int* no_of_sys_processes) const {1416return _impl->system_processes(system_procs, no_of_sys_processes);1417}14181419SystemProcessInterface::SystemProcessInterface() : _impl(NULL) {}14201421bool SystemProcessInterface::initialize() {1422_impl = new SystemProcessInterface::SystemProcesses();1423return _impl->initialize();1424}14251426SystemProcessInterface::~SystemProcessInterface() {1427if (_impl != NULL) {1428delete _impl;1429}1430}14311432CPUInformationInterface::CPUInformationInterface() : _cpu_info(NULL) {}14331434bool CPUInformationInterface::initialize() {1435_cpu_info = new CPUInformation();1436_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());1437_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());1438_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());1439_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());1440_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());1441return true;1442}14431444CPUInformationInterface::~CPUInformationInterface() {1445if (_cpu_info != NULL) {1446FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_name());1447_cpu_info->set_cpu_name(NULL);1448FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description());1449_cpu_info->set_cpu_description(NULL);1450delete _cpu_info;1451}1452}14531454int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {1455if (NULL == _cpu_info) {1456return OS_ERR;1457}1458cpu_info = *_cpu_info; // shallow copy assignment1459return OS_OK;1460}14611462class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {1463friend class NetworkPerformanceInterface;1464private:1465bool _iphlp_attached;14661467NetworkPerformance();1468NONCOPYABLE(NetworkPerformance);1469bool initialize();1470~NetworkPerformance();1471int network_utilization(NetworkInterface** network_interfaces) const;1472};14731474NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() : _iphlp_attached(false) {}14751476bool NetworkPerformanceInterface::NetworkPerformance::initialize() {1477_iphlp_attached = IphlpDll::IphlpAttach();1478return _iphlp_attached;1479}14801481NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {1482if (_iphlp_attached) {1483IphlpDll::IphlpDetach();1484}1485}14861487int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {1488MIB_IF_TABLE2* table;14891490if (IphlpDll::GetIfTable2(&table) != NO_ERROR) {1491return OS_ERR;1492}14931494NetworkInterface* ret = NULL;1495for (ULONG i = 0; i < table->NumEntries; ++i) {1496if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) {1497continue;1498}14991500char buf[256];1501if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) {1502continue;1503}15041505NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret);1506ret = cur;1507}15081509IphlpDll::FreeMibTable(table);1510*network_interfaces = ret;15111512return OS_OK;1513}15141515NetworkPerformanceInterface::NetworkPerformanceInterface() : _impl(NULL) {}15161517NetworkPerformanceInterface::~NetworkPerformanceInterface() {1518if (_impl != NULL) {1519delete _impl;1520}1521}15221523bool NetworkPerformanceInterface::initialize() {1524_impl = new NetworkPerformanceInterface::NetworkPerformance();1525return _impl->initialize();1526}15271528int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {1529return _impl->network_utilization(network_interfaces);1530}153115321533