Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/windows/vm/os_perf_windows.cpp
32284 views
/*1* Copyright (c) 2012, 2018, 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 "iphlp_interface.hpp"25#include "memory/allocation.inline.hpp"26#include "memory/resourceArea.hpp"27#include "pdh_interface.hpp"28#include "runtime/os_perf.hpp"29#include "runtime/os.hpp"30#include "utilities/macros.hpp"31#include "vm_version_ext_x86.hpp"32#include <math.h>33#include <psapi.h>34#include <TlHelp32.h>3536/*37* Windows provides a vast plethora of performance objects and counters,38* consumption of which is assisted using the Performance Data Helper (PDH) interface.39* We import a selected few api entry points from PDH, see pdh_interface.hpp.40*41* The code located in this file is to a large extent an abstraction over much of the42* plumbing needed to start consuming an object and/or counter of choice.43*44*/4546/*47* How to use:48* 1. Create query49* 2. Add counters to the query50* 3. Collect the performance data using the query51* 4. Display the performance data using the counters associated with the query52* 5. Destroy query (counter destruction implied)53*/5455/*56* Every PDH artifact, like processor, process, thread, memory, and so forth are57* identified with an index that is always the same irrespective58* of the localized version of the operating system or service pack installed.59* INFO: Using PDH APIs Correctly in a Localized Language (Q287159)60* http://support.microsoft.com/default.aspx?scid=kb;EN-US;q28715961*62* To find the correct index for an object or counter, inspect the registry key / value:63* [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]64*65* some common PDH indexes66*/67static const DWORD PDH_PROCESSOR_IDX = 238;68static const DWORD PDH_PROCESSOR_TIME_IDX = 6;69static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144;70static const DWORD PDH_PROCESS_IDX = 230;71static const DWORD PDH_ID_PROCESS_IDX = 784;72static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;73static const DWORD PDH_SYSTEM_IDX = 2;7475/* useful pdh fmt's */76static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";77static const size_t OBJECT_COUNTER_FMT_LEN = 2;78static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";79static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;80static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";81static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;8283static const char* process_image_name = NULL; // for example, "java" but could have another image name84static char* pdh_IDProcess_counter_fmt = NULL; // "\Process(java#%d)\ID Process" */8586// Need to limit how often we update a query to minimize the heisenberg effect.87// (PDH behaves erratically if the counters are queried too often, especially counters that88// store and use values from two consecutive updates, like cpu load.)89static const int min_update_interval_millis = 500;9091/*92* Structs for PDH queries.93*/94typedef struct {95HQUERY query;96s8 lastUpdate; // Last time query was updated (current millis).97} UpdateQueryS, *UpdateQueryP;9899100typedef struct {101UpdateQueryS query;102HCOUNTER counter;103bool initialized;104} CounterQueryS, *CounterQueryP;105106typedef struct {107UpdateQueryS query;108HCOUNTER* counters;109int noOfCounters;110bool initialized;111} MultiCounterQueryS, *MultiCounterQueryP;112113typedef struct {114MultiCounterQueryP queries;115int size;116bool initialized;117} MultiCounterQuerySetS, *MultiCounterQuerySetP;118119typedef struct {120MultiCounterQuerySetS set;121int process_index;122} ProcessQueryS, *ProcessQueryP;123124static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {125if (counter != NULL && *counter != NULL) {126PdhDll::PdhRemoveCounter(*counter);127*counter = NULL;128}129if (query != NULL && *query != NULL) {130PdhDll::PdhCloseQuery(*query);131*query = NULL;132}133}134135static CounterQueryP create_counter_query() {136CounterQueryP const query = NEW_C_HEAP_ARRAY(CounterQueryS, 1, mtInternal);137memset(query, 0, sizeof(CounterQueryS));138return query;139}140141static void destroy_counter_query(CounterQueryP query) {142assert(query != NULL, "invariant");143pdh_cleanup(&query->query.query, &query->counter);144FREE_C_HEAP_ARRAY(CounterQueryS, query, mtInternal);145}146147static MultiCounterQueryP create_multi_counter_query() {148MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);149memset(query, 0, sizeof(MultiCounterQueryS));150return query;151}152153static void destroy_counter_query(MultiCounterQueryP counter_query) {154if (counter_query != NULL) {155for (int i = 0; i < counter_query->noOfCounters; ++i) {156pdh_cleanup(NULL, &counter_query->counters[i]);157}158FREE_C_HEAP_ARRAY(char, counter_query->counters, mtInternal);159pdh_cleanup(&counter_query->query.query, NULL);160FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query, mtInternal);161}162}163164static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) {165for (int i = 0; i < counter_query_set->size; i++) {166for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {167pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);168}169FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters, mtInternal);170pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);171}172FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries, mtInternal);173}174175static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {176destroy_multi_counter_query(counter_query_set);177FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set, mtInternal);178}179180static void destroy_counter_query(ProcessQueryP process_query) {181destroy_multi_counter_query(&process_query->set);182FREE_C_HEAP_ARRAY(ProcessQueryS, process_query, mtInternal);183}184185static int open_query(HQUERY* query) {186return PdhDll::PdhOpenQuery(NULL, 0, query);187}188189template <typename QueryP>190static int open_query(QueryP query) {191return open_query(&query->query);192}193194static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) {195assert(query != NULL, "invariant");196assert(!query->initialized, "invariant");197assert(0 == query->noOfCounters, "invariant");198assert(query->counters == NULL, "invariant");199query->counters = (HCOUNTER*)NEW_C_HEAP_ARRAY(char, nofCounters * sizeof(HCOUNTER), mtInternal);200if (query->counters == NULL) {201return OS_ERR;202}203memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));204query->noOfCounters = (int)nofCounters;205return OS_OK;206}207208static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {209assert(query_set != NULL, "invariant");210assert(!query_set->initialized, "invariant");211for (int i = 0; i < query_set->size; ++i) {212if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) {213return OS_ERR;214}215}216return OS_OK;217}218219static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) {220assert(process_query != NULL, "invariant");221return allocate_counters(&process_query->set, nofCounters);222}223224static void deallocate_counters(MultiCounterQueryP query) {225if (query->counters != NULL) {226FREE_C_HEAP_ARRAY(char, query->counters, mtInternal);227query->counters = NULL;228query->noOfCounters = 0;229}230}231232static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {233assert(query != NULL, "invariant");234assert(counter != NULL, "invariant");235assert(path != NULL, "invariant");236if (query->query == NULL) {237if (open_query(query) != ERROR_SUCCESS) {238return OS_ERR;239}240}241assert(query->query != NULL, "invariant");242PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);243if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {244return OS_ERR;245}246/*247* According to the MSDN documentation, rate counters must be read twice:248*249* "Obtaining the value of rate counters such as Page faults/sec requires that250* PdhCollectQueryData be called twice, with a specific time interval between251* the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to252* implement the waiting period between the two calls to PdhCollectQueryData."253*254* Take the first sample here already to allow for the next "real" sample255* to succeed.256*/257if (first_sample_on_init) {258PdhDll::PdhCollectQueryData(query->query);259}260return OS_OK;261}262263template <typename QueryP>264static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {265assert(counter_query != NULL, "invariant");266assert(counter != NULL, "invariant");267assert(path != NULL, "invariant");268return add_counter(&counter_query->query, counter, path, first_sample_on_init);269}270271static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {272if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {273// performance counter might be disabled in the registry274return OS_ERR;275}276counter_query->initialized = true;277return OS_OK;278}279280static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {281assert(query != NULL, "invariant");282assert(slot_index < query->noOfCounters, "invariant");283assert(query->counters[slot_index] == NULL, "invariant");284const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);285if (OS_OK == ret) {286if (slot_index + 1 == query->noOfCounters) {287query->initialized = true;288}289}290return ret;291}292293static int collect_query_data(UpdateQueryP update_query) {294assert(update_query != NULL, "invariant");295const s8 now = os::javaTimeMillis();296if (now - update_query->lastUpdate > min_update_interval_millis) {297if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {298return OS_ERR;299}300update_query->lastUpdate = now;301}302return OS_OK;303}304305template <typename Query>306static int collect_query_data(Query* counter_query) {307assert(counter_query != NULL, "invariant");308return collect_query_data(&counter_query->query);309}310311static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {312assert(value != NULL, "invariant");313if (PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS) {314return OS_ERR;315}316return OS_OK;317}318319/*320* Working against the Process object and it's related counters is inherently problematic321* when using the PDH API:322*323* Using PDH, a process is not primarily identified by the process id,324* but with a sequential number, for example \Process(java#0), \Process(java#1), ...325* The really bad part is that this list is reset as soon as a process exits:326* If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.327*328* The PDH api requires a process identifier to be submitted when registering329* a query, but as soon as the list resets, the query is invalidated (since the name changed).330*331* Solution:332* The #number identifier for a Process query can only decrease after process creation.333*334* We therefore create an array of counter queries for all process object instances335* up to and including ourselves:336*337* Ex. we come in as third process instance (java#2), we then create and register338* queries for the following Process object instances:339* java#0, java#1, java#2340*341* current_query_index_for_process() keeps track of the current "correct" query342* (in order to keep this index valid when the list resets from underneath,343* ensure to call current_query_index_for_process() before every query involving344* Process object instance data).345*346* if unable to query, returns OS_ERR(-1)347*/348static int current_query_index_for_process() {349assert(process_image_name != NULL, "invariant");350assert(pdh_IDProcess_counter_fmt != NULL, "invariant");351HQUERY tmpQuery = NULL;352if (open_query(&tmpQuery) != ERROR_SUCCESS) {353return OS_ERR;354}355char counter[512];356HCOUNTER handle_counter = NULL;357// iterate over all instance indexes and try to find our own pid358for (int index = 0; index < max_intx; index++) {359jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);360assert(strlen(counter) < sizeof(counter), "invariant");361if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {362pdh_cleanup(&tmpQuery, &handle_counter);363return OS_ERR;364}365const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);366if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {367pdh_cleanup(&tmpQuery, &handle_counter);368return OS_ERR;369} else {370PDH_FMT_COUNTERVALUE counter_value;371formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);372pdh_cleanup(NULL, &handle_counter);373if ((LONG)os::current_process_id() == counter_value.longValue) {374pdh_cleanup(&tmpQuery, NULL);375return index;376}377}378}379pdh_cleanup(&tmpQuery, NULL);380return OS_ERR;381}382383static ProcessQueryP create_process_query() {384const int current_process_idx = current_query_index_for_process();385if (OS_ERR == current_process_idx) {386return NULL;387}388ProcessQueryP const process_query = NEW_C_HEAP_ARRAY(ProcessQueryS, 1, mtInternal);389memset(process_query, 0, sizeof(ProcessQueryS));390process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);391memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));392process_query->process_index = current_process_idx;393process_query->set.size = current_process_idx + 1;394assert(process_query->set.size > process_query->process_index, "invariant");395return process_query;396}397398static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) {399assert(process_query != NULL, "invariant");400assert(process_query->process_index < process_query->set.size, "invariant");401return &process_query->set.queries[process_query->process_index];402}403404static void clear_multi_counter(MultiCounterQueryP query) {405for (int i = 0; i < query->noOfCounters; ++i) {406pdh_cleanup(NULL, &query->counters[i]);407}408pdh_cleanup(&query->query.query, NULL);409query->initialized = false;410}411412static int ensure_valid_process_query_index(ProcessQueryP process_query) {413assert(process_query != NULL, "invariant");414const int previous_process_idx = process_query->process_index;415if (previous_process_idx == 0) {416return previous_process_idx;417}418const int current_process_idx = current_query_index_for_process();419if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx ||420current_process_idx >= process_query->set.size) {421return previous_process_idx;422}423424assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!");425while (current_process_idx < process_query->set.size - 1) {426const int new_size = --process_query->set.size;427clear_multi_counter(&process_query->set.queries[new_size]);428}429assert(current_process_idx < process_query->set.size, "invariant");430process_query->process_index = current_process_idx;431return current_process_idx;432}433434static MultiCounterQueryP current_process_query(ProcessQueryP process_query) {435assert(process_query != NULL, "invariant");436const int current_process_idx = ensure_valid_process_query_index(process_query);437assert(current_process_idx == process_query->process_index, "invariant");438assert(current_process_idx < process_query->set.size, "invariant");439return &process_query->set.queries[current_process_idx];440}441442static int collect_process_query_data(ProcessQueryP process_query) {443assert(process_query != NULL, "invariant");444return collect_query_data(current_process_query(process_query));445}446447static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {448MultiCounterQueryP const current_query = current_process_counter_query(process_query);449assert(current_query != NULL, "invariant");450assert(slot_index < current_query->noOfCounters, "invariant");451assert(current_query->counters[slot_index] != NULL, "invariant");452return formatted_counter_value(current_query->counters[slot_index], format, value);453}454455/*456* Construct a fully qualified PDH path457*458* @param objectName a PDH Object string representation(required)459* @param counterName a PDH Counter string representation(required)460* @param imageName a process image name string, ex. "java" (opt)461* @param instance an instance string, ex. "0", "1", ... (opt)462* @return the fully qualified PDH path.463*464* Caller will need a ResourceMark.465*466* (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)467*/468static const char* make_fully_qualified_counter_path(const char* object_name,469const char* counter_name,470const char* image_name = NULL,471const char* instance = NULL) {472assert(object_name != NULL, "invariant");473assert(counter_name != NULL, "invariant");474size_t full_counter_path_len = strlen(object_name) + strlen(counter_name);475476char* full_counter_path;477size_t jio_snprintf_result = 0;478if (image_name) {479/*480* For paths using the "Process" Object.481*482* Examples:483* form: "\object_name(image_name#instance)\counter_name"484* actual: "\Process(java#2)\ID Process"485*/486full_counter_path_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;487full_counter_path_len += strlen(image_name);488/*489* image_name must be passed together with an associated490* instance "number" ("0", "1", "2", ...).491* This is required in order to create valid "Process" Object paths.492*493* Examples: "\Process(java#0)", \Process(java#1"), ...494*/495assert(instance != NULL, "invariant");496full_counter_path_len += strlen(instance);497full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);498if (full_counter_path == NULL) {499return NULL;500}501jio_snprintf_result = jio_snprintf(full_counter_path,502full_counter_path_len + 1,503PROCESS_OBJECT_INSTANCE_COUNTER_FMT,504object_name,505image_name,506instance,507counter_name);508} else {509if (instance) {510/*511* For paths where the Object has multiple instances.512*513* Examples:514* form: "\object_name(instance)\counter_name"515* actual: "\Processor(0)\% Privileged Time"516*/517full_counter_path_len += strlen(instance);518full_counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;519} else {520/*521* For "normal" paths.522*523* Examples:524* form: "\object_name\counter_name"525* actual: "\Memory\Available Mbytes"526*/527full_counter_path_len += OBJECT_COUNTER_FMT_LEN;528}529full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);530if (full_counter_path == NULL) {531return NULL;532}533if (instance) {534jio_snprintf_result = jio_snprintf(full_counter_path,535full_counter_path_len + 1,536OBJECT_WITH_INSTANCES_COUNTER_FMT,537object_name,538instance,539counter_name);540} else {541jio_snprintf_result = jio_snprintf(full_counter_path,542full_counter_path_len + 1,543OBJECT_COUNTER_FMT,544object_name,545counter_name);546}547}548assert(full_counter_path_len == jio_snprintf_result, "invariant");549return full_counter_path;550}551552static void log_invalid_pdh_index(DWORD index) {553if (LogJFR) tty->print_cr("Unable to resolve PDH index: (%ld)", index);554if (LogJFR) tty->print_cr("Please check the registry if this performance object/counter is disabled");555}556557static bool is_valid_pdh_index(DWORD index) {558DWORD dummy = 0;559if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) {560log_invalid_pdh_index(index);561return false;562}563return true;564}565566/*567* Maps an index to a resource area allocated string for the localized PDH artifact.568*569* Caller will need a ResourceMark.570*571* @param index the counter index as specified in the registry572* @param ppBuffer pointer to a char*573* @return OS_OK if successful, OS_ERR on failure.574*/575static OSReturn lookup_name_by_index(DWORD index, char** p_string) {576assert(p_string != NULL, "invariant");577if (!is_valid_pdh_index(index)) {578return OS_ERR;579}580// determine size needed581DWORD size = 0;582PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);583assert(status == PDH_MORE_DATA, "invariant");584*p_string = NEW_RESOURCE_ARRAY_RETURN_NULL(char, size);585if (*p_string== NULL) {586return OS_ERR;587}588if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {589return OS_ERR;590}591if (0 == size || *p_string == NULL) {592return OS_ERR;593}594// windows vista does not null-terminate the string (although the docs says it will)595(*p_string)[size - 1] = '\0';596return OS_OK;597}598599static const char* copy_string_to_c_heap(const char* string) {600assert(string != NULL, "invariant");601const size_t len = strlen(string);602char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);603if (NULL == cheap_allocated_string) {604return NULL;605}606strncpy(cheap_allocated_string, string, len + 1);607return cheap_allocated_string;608}609610/*611* Maps an index to a resource area allocated string for the localized PDH artifact.612*613* Caller will need a ResourceMark.614*615* @param index the counter index as specified in the registry616* @return localized pdh artifact string if successful, NULL on failure.617*/618static const char* pdh_localized_artifact(DWORD pdh_artifact_index) {619char* pdh_localized_artifact_string = NULL;620// get localized name from pdh artifact index621if (lookup_name_by_index(pdh_artifact_index, &pdh_localized_artifact_string) != OS_OK) {622return NULL;623}624return pdh_localized_artifact_string;625}626627/*628* Returns the PDH string identifying the current process image name.629* Use this prefix when getting counters from the PDH process object630* representing your process.631* Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process632* image description.633*634* Caller needs ResourceMark.635*636* @return the process image description. NULL if the call failed.637*/638static const char* pdh_process_image_name() {639char* module_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, MAX_PATH);640if (NULL == module_name) {641return NULL;642}643// Find our module name and use it to extract the image name used by PDH644DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH);645if (getmfn_return >= MAX_PATH || 0 == getmfn_return) {646return NULL;647}648if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) {649return NULL;650}651char* process_image_name = strrchr(module_name, '\\'); //drop path652process_image_name++; //skip slash653char* dot_pos = strrchr(process_image_name, '.'); //drop .exe654dot_pos[0] = '\0';655return process_image_name;656}657658static void deallocate_pdh_constants() {659if (process_image_name != NULL) {660FREE_C_HEAP_ARRAY(char, process_image_name, mtInternal);661process_image_name = NULL;662}663if (pdh_IDProcess_counter_fmt != NULL) {664FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt, mtInternal);665pdh_IDProcess_counter_fmt = NULL;666}667}668669static int allocate_pdh_constants() {670assert(process_image_name == NULL, "invariant");671const char* pdh_image_name = pdh_process_image_name();672if (pdh_image_name == NULL) {673return OS_ERR;674}675process_image_name = copy_string_to_c_heap(pdh_image_name);676677const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX);678if (pdh_localized_process_object == NULL) {679return OS_ERR;680}681682const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX);683if (pdh_localized_IDProcess_counter == NULL) {684return OS_ERR;685}686687size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name);688pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object);689pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter);690pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;691pdh_IDProcess_counter_fmt_len += 2; // "%d"692693assert(pdh_IDProcess_counter_fmt == NULL, "invariant");694pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);695if (pdh_IDProcess_counter_fmt == NULL) {696return OS_ERR;697}698699/* "\Process(java#%d)\ID Process" */700const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt,701pdh_IDProcess_counter_fmt_len + 1,702PROCESS_OBJECT_INSTANCE_COUNTER_FMT,703pdh_localized_process_object,704process_image_name,705"%d",706pdh_localized_IDProcess_counter);707708assert(pdh_IDProcess_counter_fmt != NULL, "invariant");709assert(len == pdh_IDProcess_counter_fmt_len, "invariant");710return OS_OK;711}712713/*714* Enuerate the Processor PDH object and returns a buffer containing the enumerated instances.715* Caller needs ResourceMark;716*717* @return buffer if successful, NULL on failure.718*/719static const char* enumerate_cpu_instances() {720char* processor; //'Processor' == PDH_PROCESSOR_IDX721if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {722return NULL;723}724DWORD c_size = 0;725DWORD i_size = 0;726// enumerate all processors.727PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved728NULL, // local machine729processor, // object to enumerate730NULL,731&c_size,732NULL, // instance buffer is NULL and733&i_size, // pass 0 length in order to get the required size734PERF_DETAIL_WIZARD, // counter detail level7350);736if (PdhDll::PdhStatusFail((pdhStat))) {737return NULL;738}739char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size);740if (instances == NULL) {741return NULL;742}743c_size = 0;744pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved745NULL, // local machine746processor, // object to enumerate747NULL,748&c_size,749instances, // now instance buffer is allocated to be filled in750&i_size, // and the required size is known751PERF_DETAIL_WIZARD, // counter detail level7520);753if (PdhDll::PdhStatusFail((pdhStat))) {754return NULL;755}756return instances;757}758759static int count_logical_cpus(const char* instances) {760assert(instances != NULL, "invariant");761// count logical instances.762DWORD count;763char* tmp;764for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++);765// PDH reports an instance for each logical processor plus an instance for the total (_Total)766assert(count == os::processor_count() + 1, "invalid enumeration!");767return count - 1;768}769770static int number_of_logical_cpus() {771static int numberOfCPUS = 0;772if (numberOfCPUS == 0) {773const char* instances = enumerate_cpu_instances();774if (instances == NULL) {775return OS_ERR;776}777numberOfCPUS = count_logical_cpus(instances);778}779return numberOfCPUS;780}781782static double cpu_factor() {783static DWORD numCpus = 0;784static double cpuFactor = .0;785if (numCpus == 0) {786numCpus = number_of_logical_cpus();787assert(os::processor_count() <= (int)numCpus, "invariant");788cpuFactor = numCpus * 100;789}790return cpuFactor;791}792793static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) {794if (LogJFR) tty->print_cr("Unable to register PDH query for \"%s\"", full_counter_name);795if (LogJFR) tty->print_cr("Please check the registry if this performance object/counter is disabled");796}797798static int initialize_cpu_query_counters(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {799assert(cpu_query != NULL, "invariant");800assert(cpu_query->counters != NULL, "invariant");801char* processor; //'Processor' == PDH_PROCESSOR_IDX802if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {803return OS_ERR;804}805char* counter_name = NULL;806if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {807return OS_ERR;808}809if (cpu_query->query.query == NULL) {810if (open_query(cpu_query)) {811return OS_ERR;812}813}814assert(cpu_query->query.query != NULL, "invariant");815size_t counter_len = strlen(processor);816counter_len += strlen(counter_name);817counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s"818819DWORD index;820char* tmp;821const char* instances = enumerate_cpu_instances();822for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {823const size_t tmp_len = strlen(tmp);824char* counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, counter_len + tmp_len + 1);825if (counter_path == NULL) {826return OS_ERR;827}828const size_t jio_snprintf_result = jio_snprintf(counter_path,829counter_len + tmp_len + 1,830OBJECT_WITH_INSTANCES_COUNTER_FMT,831processor,832tmp, // instance "0", "1", .."_Total"833counter_name);834assert(counter_len + tmp_len == jio_snprintf_result, "invariant");835if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) {836// performance counter is disabled in registry and not accessible via PerfLib837log_error_message_on_no_PDH_artifact(counter_path);838// return OS_OK to have the system continue to run without the missing counter839return OS_OK;840}841}842cpu_query->initialized = true;843// Query once to initialize the counters which require at least two samples844// (like the % CPU usage) to calculate correctly.845collect_query_data(cpu_query);846return OS_OK;847}848849static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {850assert(cpu_query != NULL, "invariant");851assert(!cpu_query->initialized, "invariant");852const int logical_cpu_count = number_of_logical_cpus();853assert(logical_cpu_count >= os::processor_count(), "invariant");854// we also add another counter for instance "_Total"855if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) {856return OS_ERR;857}858assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");859return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);860}861862static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) {863char* localized_process_object;864if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {865return OS_ERR;866}867assert(localized_process_object != NULL, "invariant");868char* localized_counter_name;869if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) {870return OS_ERR;871}872assert(localized_counter_name != NULL, "invariant");873for (int i = 0; i < process_query->set.size; ++i) {874char instanceIndexBuffer[32];875const char* counter_path = make_fully_qualified_counter_path(localized_process_object,876localized_counter_name,877process_image_name,878itoa(i, instanceIndexBuffer, 10));879if (counter_path == NULL) {880return OS_ERR;881}882MultiCounterQueryP const query = &process_query->set.queries[i];883if (add_process_counter(query, slot_index, counter_path, true)) {884return OS_ERR;885}886}887return OS_OK;888}889890static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {891if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {892return NULL;893}894CounterQueryP const query = create_counter_query();895const char* object = pdh_localized_artifact(pdh_object_idx);896assert(object != NULL, "invariant");897const char* counter = pdh_localized_artifact(pdh_counter_idx);898assert(counter != NULL, "invariant");899const char* full_counter_path = make_fully_qualified_counter_path(object, counter);900assert(full_counter_path != NULL, "invariant");901add_counter(query, full_counter_path, true);902return query;903}904905static void deallocate() {906deallocate_pdh_constants();907PdhDll::PdhDetach();908}909910static LONG critical_section = 0;911static LONG reference_count = 0;912static bool pdh_initialized = false;913914static void on_initialization_failure() {915// still holder of critical section916deallocate();917InterlockedExchangeAdd(&reference_count, -1);918}919920static OSReturn initialize() {921ResourceMark rm;922if (!PdhDll::PdhAttach()) {923return OS_ERR;924}925if (allocate_pdh_constants() != OS_OK) {926on_initialization_failure();927return OS_ERR;928}929return OS_OK;930}931932/*933* Helper to initialize the PDH library, function pointers, constants and counters.934*935* Reference counting allows for unloading of pdh.dll granted all sessions use the pair:936*937* pdh_acquire();938* pdh_release();939*940* @return OS_OK if successful, OS_ERR on failure.941*/942static bool pdh_acquire() {943while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);944InterlockedExchangeAdd(&reference_count, 1);945if (pdh_initialized) {946return true;947}948const OSReturn ret = initialize();949if (OS_OK == ret) {950pdh_initialized = true;951}952while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);953return ret == OS_OK;954}955956static void pdh_release() {957while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);958const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);959if (1 == prev_ref_count) {960deallocate();961pdh_initialized = false;962}963while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);964}965966class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {967friend class CPUPerformanceInterface;968private:969CounterQueryP _context_switches;970ProcessQueryP _process_cpu_load;971MultiCounterQueryP _machine_cpu_load;972973int cpu_load(int which_logical_cpu, double* cpu_load);974int context_switch_rate(double* rate);975int cpu_load_total_process(double* cpu_load);976int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad);977CPUPerformance();978~CPUPerformance();979bool initialize();980};981982class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {983friend class SystemProcessInterface;984private:985class ProcessIterator : public CHeapObj<mtInternal> {986friend class SystemProcessInterface::SystemProcesses;987private:988HANDLE _hProcessSnap;989PROCESSENTRY32 _pe32;990BOOL _valid;991char _exePath[MAX_PATH];992ProcessIterator();993~ProcessIterator();994bool initialize();995996int current(SystemProcess* const process_info);997int next_process();998bool is_valid() const { return _valid != FALSE; }999char* allocate_string(const char* str) const;1000int snapshot();1001};10021003ProcessIterator* _iterator;1004SystemProcesses();1005~SystemProcesses();1006bool initialize();10071008// information about system processes1009int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;1010};10111012CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}10131014bool CPUPerformanceInterface::CPUPerformance::initialize() {1015if (!pdh_acquire()) {1016return true;1017}1018_context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);1019_process_cpu_load = create_process_query();1020if (_process_cpu_load == NULL) {1021return true;1022}1023if (allocate_counters(_process_cpu_load, 2) != OS_OK) {1024return true;1025}1026if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {1027return true;1028}1029if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {1030return true;1031}1032_process_cpu_load->set.initialized = true;1033_machine_cpu_load = create_multi_counter_query();1034if (_machine_cpu_load == NULL) {1035return true;1036}1037initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX);1038return true;1039}10401041CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {1042if (_context_switches != NULL) {1043destroy_counter_query(_context_switches);1044_context_switches = NULL;1045}1046if (_process_cpu_load != NULL) {1047destroy_counter_query(_process_cpu_load);1048_process_cpu_load = NULL;1049}1050if (_machine_cpu_load != NULL) {1051destroy_counter_query(_machine_cpu_load);1052_machine_cpu_load = NULL;1053}1054pdh_release();1055}10561057CPUPerformanceInterface::CPUPerformanceInterface() {1058_impl = NULL;1059}10601061bool CPUPerformanceInterface::initialize() {1062_impl = new CPUPerformanceInterface::CPUPerformance();1063return _impl != NULL && _impl->initialize();1064}10651066CPUPerformanceInterface::~CPUPerformanceInterface() {1067if (_impl != NULL) {1068delete _impl;1069}1070}10711072int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {1073return _impl->cpu_load(which_logical_cpu, cpu_load);1074}10751076int CPUPerformanceInterface::context_switch_rate(double* rate) const {1077return _impl->context_switch_rate(rate);1078}10791080int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {1081return _impl->cpu_load_total_process(cpu_load);1082}10831084int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad,1085double* pjvmKernelLoad,1086double* psystemTotalLoad) const {1087return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);1088}10891090int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {1091*cpu_load = .0;1092if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) {1093return OS_ERR;1094}1095assert(_machine_cpu_load != NULL, "invariant");1096assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");10971098if (collect_query_data(_machine_cpu_load)) {1099return OS_ERR;1100}1101// -1 is total (all cpus)1102const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;1103PDH_FMT_COUNTERVALUE counter_value;1104formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);1105*cpu_load = counter_value.doubleValue / 100;1106return OS_OK;1107}11081109int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {1110*cpu_load = .0;1111if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {1112return OS_ERR;1113}1114assert(_process_cpu_load != NULL, "invariant");1115if (collect_process_query_data(_process_cpu_load)) {1116return OS_ERR;1117}1118PDH_FMT_COUNTERVALUE counter_value;1119if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1120return OS_ERR;1121}1122double process_load = counter_value.doubleValue / cpu_factor();1123process_load = MIN2<double>(1, process_load);1124process_load = MAX2<double>(0, process_load);1125*cpu_load = process_load;1126return OS_OK;1127}11281129int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad,1130double* pjvmKernelLoad,1131double* psystemTotalLoad) {1132assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");1133assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");1134assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");1135*pjvmUserLoad = .0;1136*pjvmKernelLoad = .0;1137*psystemTotalLoad = .0;11381139if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {1140return OS_ERR;1141}1142assert(_process_cpu_load != NULL, "invariant");1143if (collect_process_query_data(_process_cpu_load)) {1144return OS_ERR;1145}1146double process_load = .0;1147PDH_FMT_COUNTERVALUE counter_value;1148// Read PDH_PROCESSOR_TIME_IDX1149if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1150return OS_ERR;1151}1152process_load = counter_value.doubleValue / cpu_factor();1153process_load = MIN2<double>(1, process_load);1154process_load = MAX2<double>(0, process_load);1155// Read PDH_PRIV_PROCESSOR_TIME_IDX1156if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {1157return OS_ERR;1158}1159double kernel_load = counter_value.doubleValue / cpu_factor();1160kernel_load = MIN2<double>(1, kernel_load);1161kernel_load = MAX2<double>(0, kernel_load);1162*pjvmKernelLoad = kernel_load;11631164double user_load = process_load - kernel_load;1165user_load = MIN2<double>(1, user_load);1166user_load = MAX2<double>(0, user_load);1167*pjvmUserLoad = user_load;11681169if (collect_query_data(_machine_cpu_load)) {1170return OS_ERR;1171}1172if (formatted_counter_value(_machine_cpu_load->counters[_machine_cpu_load->noOfCounters - 1], PDH_FMT_DOUBLE, &counter_value) != OS_OK) {1173return OS_ERR;1174}1175double machine_load = counter_value.doubleValue / 100;1176assert(machine_load >= 0, "machine_load is negative!");1177// clamp at user+system and 1.01178if (*pjvmKernelLoad + *pjvmUserLoad > machine_load) {1179machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0);1180}1181*psystemTotalLoad = machine_load;1182return OS_OK;1183}11841185int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {1186assert(rate != NULL, "invariant");1187*rate = .0;1188if (_context_switches == NULL || !_context_switches->initialized) {1189return OS_ERR;1190}1191assert(_context_switches != NULL, "invariant");1192if (collect_query_data(_context_switches) != OS_OK) {1193return OS_ERR;1194}1195PDH_FMT_COUNTERVALUE counter_value;1196if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {1197return OS_ERR;1198}1199*rate = counter_value.doubleValue;1200return OS_OK;1201}12021203SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {1204_hProcessSnap = INVALID_HANDLE_VALUE;1205_valid = FALSE;1206_pe32.dwSize = sizeof(PROCESSENTRY32);1207}12081209bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {1210return true;1211}12121213int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() {1214// take snapshot of all process in the system1215_hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);1216if (_hProcessSnap == INVALID_HANDLE_VALUE) {1217return OS_ERR;1218}1219// step to first process1220_valid = Process32First(_hProcessSnap, &_pe32);1221return is_valid() ? OS_OK : OS_ERR;1222}12231224SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {1225if (_hProcessSnap != INVALID_HANDLE_VALUE) {1226CloseHandle(_hProcessSnap);1227}1228}12291230int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {1231assert(is_valid(), "no current process to be fetched!");1232assert(process_info != NULL, "process_info is NULL!");1233char* exePath = NULL;1234HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID);1235if (hProcess != NULL) {1236HMODULE hMod;1237DWORD cbNeeded;1238if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) {1239if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) {1240exePath = _exePath;1241}1242}1243CloseHandle (hProcess);1244}1245process_info->set_pid((int)_pe32.th32ProcessID);1246process_info->set_name(allocate_string(_pe32.szExeFile));1247process_info->set_path(allocate_string(exePath));1248return OS_OK;1249}12501251char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {1252if (str != NULL) {1253size_t len = strlen(str);1254char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);1255if (NULL == tmp) {1256return NULL;1257}1258strncpy(tmp, str, len);1259tmp[len] = '\0';1260return tmp;1261}1262return NULL;1263}12641265int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {1266_valid = Process32Next(_hProcessSnap, &_pe32);1267return OS_OK;1268}12691270SystemProcessInterface::SystemProcesses::SystemProcesses() {1271_iterator = NULL;1272}12731274bool SystemProcessInterface::SystemProcesses::initialize() {1275_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();1276return _iterator != NULL && _iterator->initialize();1277}12781279SystemProcessInterface::SystemProcesses::~SystemProcesses() {1280if (_iterator != NULL) {1281delete _iterator;1282_iterator = NULL;1283}1284}12851286int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes,1287int* no_of_sys_processes) const {1288assert(system_processes != NULL, "system_processes pointer is NULL!");1289assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");1290assert(_iterator != NULL, "iterator is NULL!");12911292// initialize pointers1293*no_of_sys_processes = 0;1294*system_processes = NULL;12951296// take process snapshot1297if (_iterator->snapshot() != OS_OK) {1298return OS_ERR;1299}13001301while (_iterator->is_valid()) {1302SystemProcess* tmp = new SystemProcess();1303_iterator->current(tmp);13041305//if already existing head1306if (*system_processes != NULL) {1307//move "first to second"1308tmp->set_next(*system_processes);1309}1310// new head1311*system_processes = tmp;1312// increment1313(*no_of_sys_processes)++;1314// step forward1315_iterator->next_process();1316}1317return OS_OK;1318}13191320int SystemProcessInterface::system_processes(SystemProcess** system_procs,1321int* no_of_sys_processes) const {1322return _impl->system_processes(system_procs, no_of_sys_processes);1323}13241325SystemProcessInterface::SystemProcessInterface() {1326_impl = NULL;1327}13281329bool SystemProcessInterface::initialize() {1330_impl = new SystemProcessInterface::SystemProcesses();1331return _impl != NULL && _impl->initialize();1332}13331334SystemProcessInterface::~SystemProcessInterface() {1335if (_impl != NULL) {1336delete _impl;1337}1338}13391340CPUInformationInterface::CPUInformationInterface() {1341_cpu_info = NULL;1342}13431344bool CPUInformationInterface::initialize() {1345_cpu_info = new CPUInformation();1346if (NULL == _cpu_info) {1347return false;1348}1349_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());1350_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());1351_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());1352_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());1353_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());1354return true;1355}13561357CPUInformationInterface::~CPUInformationInterface() {1358if (_cpu_info != NULL) {1359const char* cpu_name = _cpu_info->cpu_name();1360if (cpu_name != NULL) {1361FREE_C_HEAP_ARRAY(char, cpu_name, mtInternal);1362_cpu_info->set_cpu_name(NULL);1363}1364const char* cpu_desc = _cpu_info->cpu_description();1365if (cpu_desc != NULL) {1366FREE_C_HEAP_ARRAY(char, cpu_desc, mtInternal);1367_cpu_info->set_cpu_description(NULL);1368}1369delete _cpu_info;1370_cpu_info = NULL;1371}1372}13731374int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {1375if (NULL == _cpu_info) {1376return OS_ERR;1377}1378cpu_info = *_cpu_info; // shallow copy assignment1379return OS_OK;1380}13811382class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {1383friend class NetworkPerformanceInterface;1384private:1385bool _iphlp_attached;13861387NetworkPerformance();1388NetworkPerformance(const NetworkPerformance& rhs); // no impl1389NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl1390bool initialize();1391~NetworkPerformance();1392int network_utilization(NetworkInterface** network_interfaces) const;1393};13941395NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance()1396: _iphlp_attached(false) {1397}13981399bool NetworkPerformanceInterface::NetworkPerformance::initialize() {1400_iphlp_attached = IphlpDll::IphlpAttach();1401return _iphlp_attached;1402}14031404NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {1405if (_iphlp_attached) {1406IphlpDll::IphlpDetach();1407}1408}14091410int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {1411MIB_IF_TABLE2* table;14121413if (IphlpDll::GetIfTable2(&table) != NO_ERROR) {1414return OS_ERR;1415}14161417NetworkInterface* ret = NULL;1418for (ULONG i = 0; i < table->NumEntries; ++i) {1419if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) {1420continue;1421}14221423char buf[256];1424if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) {1425continue;1426}14271428NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret);1429ret = cur;1430}14311432IphlpDll::FreeMibTable(table);1433*network_interfaces = ret;14341435return OS_OK;1436}14371438NetworkPerformanceInterface::NetworkPerformanceInterface() {1439_impl = NULL;1440}14411442NetworkPerformanceInterface::~NetworkPerformanceInterface() {1443if (_impl != NULL) {1444delete _impl;1445}1446}14471448bool NetworkPerformanceInterface::initialize() {1449_impl = new NetworkPerformanceInterface::NetworkPerformance();1450return _impl != NULL && _impl->initialize();1451}14521453int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {1454return _impl->network_utilization(network_interfaces);1455}145614571458