products/sources/formale Sprachen/Java/openjdk-20-36_src/src/hotspot/os/windows image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: os_perf_windows.cpp   Sprache: C

/*
 * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


#include "precompiled.hpp"
#include "iphlp_interface.hpp"
#include "jvm_io.h"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "pdh_interface.hpp"
#include "runtime/os_perf.hpp"
#include "runtime/os.hpp"
#include "runtime/semaphore.inline.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"

#include <math.h>
#include <psapi.h>
#include <TlHelp32.h>

/*
 * Windows provides a vast plethora of performance objects and counters,
 * consumption of which is assisted using the Performance Data Helper (PDH) interface.
 * We import a selected few api entry points from PDH, see pdh_interface.hpp.
 *
 * The code located in this file is to a large extent an abstraction over much of the
 * plumbing needed to start consuming an object and/or counter of choice.
 *
 *
 * How to use:
 * 1. Create a query
 * 2. Add counters to the query
 * 3. Collect the performance data using the query
 * 4. Read the performance data from counters associated with the query
 * 5. Destroy query (counter destruction implied)
 *
 *
 * Every PDH artifact, like processor, process, thread, memory, and so forth are
 * identified with an index that is always the same irrespective
 * of the localized version of the operating system or service pack installed.
 * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
 *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
 *
 * To find the correct index for an object or counter, inspect the registry key / value:
 * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
 *
 * some common PDH indexes
 */

static const DWORD PDH_PROCESSOR_IDX = 238;
static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144;
static const DWORD PDH_PROCESS_IDX = 230;
static const DWORD PDH_ID_PROCESS_IDX = 784;
static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;
static const DWORD PDH_SYSTEM_IDX = 2;

/* useful pdh fmt's for the general form: \object(instance#index)\counter */
static const charconst OBJECT_COUNTER_FMT = "\\%s\\%s";
static const size_t OBJECT_COUNTER_FMT_LEN = 2;
static const charconst OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
static const charconst PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s#%s)\\%s";
static const size_t PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 5;
static const charconst PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT = "\\%s(%s*)\\%s";
static const size_t PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT_LEN = 5;

/* pdh string constants built up from fmts on initialization */
static const char* process_image_name = NULL; // e.g. "java" but could have another image name
static char* pdh_process_instance_IDProcess_counter_fmt = NULL; // "\Process(java#%d)\ID Process" */
static char* pdh_process_instance_wildcard_IDProcess_counter = NULL; // "\Process(java*)\ID Process" */

/*
* Structs for PDH queries.
*/

typedef struct {
  HQUERY pdh_query_handle;
  s8     lastUpdate; // Last time query was updated.
} UpdateQueryS, *UpdateQueryP;


typedef struct {
  UpdateQueryS query;
  HCOUNTER     counter;
  bool         initialized;
} CounterQueryS, *CounterQueryP;

typedef struct {
  UpdateQueryS query;
  HCOUNTER*    counters;
  int          noOfCounters;
  bool         initialized;
} MultiCounterQueryS, *MultiCounterQueryP;

typedef struct {
  MultiCounterQueryP queries;
  int                size;
  bool               initialized;
} MultiCounterQuerySetS, *MultiCounterQuerySetP;

typedef struct {
  MultiCounterQuerySetS set;
  int                   process_idx;
} ProcessQueryS, *ProcessQueryP;

static int open_query(HQUERY* pdh_query_handle) {
  return PdhDll::PdhOpenQuery(NULL, 0, pdh_query_handle) != ERROR_SUCCESS ? OS_ERR : OS_OK;
}

static int open_query(UpdateQueryP query) {
  return open_query(&query->pdh_query_handle);
}

template <typename QueryP>
static int open_query(QueryP query) {
  return open_query(&query->query);
}

static void close_query(HQUERY* const pdh_query_handle, HCOUNTER* const counter) {
  if (counter != NULL && *counter != NULL) {
    PdhDll::PdhRemoveCounter(*counter);
    *counter = NULL;
  }
  if (pdh_query_handle != NULL && *pdh_query_handle != NULL) {
    PdhDll::PdhCloseQuery(*pdh_query_handle);
    *pdh_query_handle = NULL;
  }
}

static void close_query(MultiCounterQueryP query) {
  for (int i = 0; i < query->noOfCounters; ++i) {
    close_query(NULL, &query->counters[i]);
  }
  close_query(&query->query.pdh_query_handle, NULL);
  query->initialized = false;
}

static CounterQueryP create_counter_query() {
  CounterQueryP const query = NEW_C_HEAP_OBJ(CounterQueryS, mtInternal);
  memset(query, 0, sizeof(CounterQueryS));
  return query;
}

static MultiCounterQueryP create_multi_counter_query() {
  MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);
  memset(query, 0, sizeof(MultiCounterQueryS));
  return query;
}

static void destroy(CounterQueryP query) {
  assert(query != NULL, "invariant");
  close_query(&query->query.pdh_query_handle, &query->counter);
  FREE_C_HEAP_OBJ(query);
}

static void destroy(MultiCounterQueryP query) {
  if (query != NULL) {
    for (int i = 0; i < query->noOfCounters; ++i) {
      close_query(NULL, &query->counters[i]);
    }
    FREE_C_HEAP_ARRAY(char, query->counters);
    close_query(&query->query.pdh_query_handle, NULL);
    FREE_C_HEAP_ARRAY(MultiCounterQueryS, query);
  }
}

static void destroy_query_set(MultiCounterQuerySetP query_set) {
  for (int i = 0; i < query_set->size; i++) {
    for (int j = 0; j < query_set->queries[i].noOfCounters; ++j) {
      close_query(NULL, &query_set->queries[i].counters[j]);
    }
    FREE_C_HEAP_ARRAY(char, query_set->queries[i].counters);
    close_query(&query_set->queries[i].query.pdh_query_handle, NULL);
  }
  FREE_C_HEAP_ARRAY(MultiCounterQueryS, query_set->queries);
}

static void destroy(MultiCounterQuerySetP query) {
  destroy_query_set(query);
  FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, query);
}

static void destroy(ProcessQueryP query) {
  destroy_query_set(&query->set);
  FREE_C_HEAP_OBJ(query);
}

static void allocate_counters(MultiCounterQueryP query, size_t nofCounters) {
  assert(query != NULL, "invariant");
  assert(!query->initialized, "invariant");
  assert(0 == query->noOfCounters, "invariant");
  assert(query->counters == NULL, "invariant");
  query->counters = NEW_C_HEAP_ARRAY(HCOUNTER, nofCounters, mtInternal);
  memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));
  query->noOfCounters = (int)nofCounters;
}

static void allocate_counters(MultiCounterQuerySetP query, size_t nofCounters) {
  assert(query != NULL, "invariant");
  assert(!query->initialized, "invariant");
  for (int i = 0; i < query->size; ++i) {
    allocate_counters(&query->queries[i], nofCounters);
  }
}

static void allocate_counters(ProcessQueryP query, size_t nofCounters) {
  assert(query != NULL, "invariant");
  allocate_counters(&query->set, nofCounters);
}

static void deallocate_counters(MultiCounterQueryP query) {
  FREE_C_HEAP_ARRAY(char, query->counters);
  query->counters = NULL;
  query->noOfCounters = 0;
}

static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* counter_path, bool first_sample_on_init) {
  assert(query != NULL, "invariant");
  assert(counter != NULL, "invariant");
  assert(counter_path != NULL, "invariant");
  if (query->pdh_query_handle == NULL) {
    if (open_query(query) != OS_OK) {
      return OS_ERR;
    }
  }
  assert(query->pdh_query_handle != NULL, "invariant");
  PDH_STATUS status = PdhDll::PdhAddCounter(query->pdh_query_handle, counter_path, 0, counter);
  if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {
    return OS_ERR;
  }
  /*
  * According to the MSDN documentation, rate counters must be read twice:
  *
  * "Obtaining the value of rate counters such as Page faults/sec requires that
  *  PdhCollectQueryData be called twice, with a specific time interval between
  *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
  *  implement the waiting period between the two calls to PdhCollectQueryData."
  *
  *  Take the first sample here already to allow for the next "real" sample
  *  to succeed.
  */

  if (first_sample_on_init && PdhDll::PdhCollectQueryData(query->pdh_query_handle) != ERROR_SUCCESS) {
    return OS_ERR;
  }
  return OS_OK;
}

template <typename QueryP>
static OSReturn add_counter(QueryP query, HCOUNTER* counter, const char* counter_path, bool first_sample_on_init) {
  assert(query != NULL, "invariant");
  assert(counter != NULL, "invariant");
  assert(counter_path != NULL, "invariant");
  return add_counter(&query->query, counter, counter_path, first_sample_on_init);
}

// if add_counter fails with OS_ERR, the performance counter might be disabled in the registry
static OSReturn add_counter(CounterQueryP query, const char* counter_path, bool first_sample_on_init = true) {
  return add_counter(query, &query->counter, counter_path, first_sample_on_init);
}

static OSReturn add_counter(MultiCounterQueryP query, int counter_idx, const char* counter_path, bool first_sample_on_init) {
  assert(query != NULL, "invariant");
  assert(counter_idx < query->noOfCounters, "invariant");
  assert(query->counters[counter_idx] == NULL, "invariant");
  return add_counter(query, &query->counters[counter_idx], counter_path, first_sample_on_init);
}

// Need to limit how often we update a query to minimize the heisenberg effect.
// (PDH behaves erratically if the counters are queried too often, especially counters that
// store and use values from two consecutive updates, like cpu load.)
static const int min_update_interval_millis = 500;

static int collect(UpdateQueryP query) {
  assert(query != NULL, "invariant");
  const s8 now = os::javaTimeNanos();
  if (nanos_to_millis(now - query->lastUpdate) > min_update_interval_millis) {
    if (PdhDll::PdhCollectQueryData(query->pdh_query_handle) != ERROR_SUCCESS) {
      return OS_ERR;
    }
    query->lastUpdate = now;
  }
  return OS_OK;
}

template <typename QueryP>
static int collect(QueryP query) {
  assert(query != NULL, "invariant");
  return collect(&query->query);
}

static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
  assert(value != NULL, "invariant");
  return PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS ? OS_ERR : OS_OK;
}

static int read_counter(CounterQueryP query, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
  assert(query != NULL, "invariant");
  return formatted_counter_value(query->counter, format, value);
}

static int read_counter(MultiCounterQueryP query, int counter_idx, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
  assert(query != NULL, "invariant");
  assert(counter_idx < query->noOfCounters, "invariant");
  assert(query->counters[counter_idx] != NULL, "invariant");
  return formatted_counter_value(query->counters[counter_idx], format, value);
}

static int read_counter(ProcessQueryP query, int counter_idx, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
  assert(query != NULL, "invariant");
  MultiCounterQueryP const current_query = &query->set.queries[query->process_idx];
  assert(current_query != NULL, "invariant");
  return read_counter(current_query, counter_idx, format, value);
}

/*
* The routine expands a process object path including a wildcard to fetch the list of process instances
* having the same name, i.e. "java" or rather the value of process_image_name.
* A tally of this list is returned to the caller.
*/

static int number_of_live_process_instances() {
  char* buffer = NULL;
  DWORD size = 0;
  // determine size
  PDH_STATUS status = PdhDll::PdhExpandWildCardPath(NULL,
                                                    pdh_process_instance_wildcard_IDProcess_counter,
                                                    buffer,
                                                    &size,
                                                    PDH_NOEXPANDCOUNTERS);
  while (status == PDH_MORE_DATA) {
    buffer = NEW_RESOURCE_ARRAY(char, size);
    status = PdhDll::PdhExpandWildCardPath(NULL,
                                           pdh_process_instance_wildcard_IDProcess_counter,
                                           buffer,
                                           &size,
                                           PDH_NOEXPANDCOUNTERS);
  }
  if (status != ERROR_SUCCESS) {
    return OS_ERR;
  }
  // count the number of live process instances
  int instances = 0;
  const charconst end = buffer + size;
  for (char* next = buffer; next != end && (*next != '\0'); next = &next[strlen(next) + 1], ++instances);
  assert(instances > 0, "invariant");
  return instances;
}

static PDH_STATUS pdh_process_idx_to_pid(HQUERY& pdh_query_handle, int idx, LONG* pid) {
  assert(pid != NULL, "invariant");
  char counter_path[PDH_MAX_COUNTER_PATH];
  jio_snprintf(counter_path, sizeof(counter_path) - 1, pdh_process_instance_IDProcess_counter_fmt, idx);
  assert(strlen(counter_path) < sizeof(counter_path), "invariant");
  HCOUNTER counter = NULL;
  PDH_STATUS status = PdhDll::PdhAddCounter(pdh_query_handle, counter_path, 0, &counter);
  if (status != ERROR_SUCCESS) {
    close_query(&pdh_query_handle, &counter);
    return status;
  }
  status = PdhDll::PdhCollectQueryData(pdh_query_handle);
  if (status != ERROR_SUCCESS) {
    close_query(NULL, &counter);
    return PDH_NO_DATA;
  }
  PDH_FMT_COUNTERVALUE counter_value;
  status = formatted_counter_value(counter, PDH_FMT_LONG, &counter_value);
  if (status != OS_OK) {
    close_query(&pdh_query_handle, &counter);
    return status;
  }
  *pid = counter_value.longValue;
  close_query(NULL, &counter);
  return ERROR_SUCCESS;
}


/*
 * Max process query index is derived from the total number of live process instances, seen
 * as a snap-shot at the point of initialization, i.e. processes having the same name, e.g. "java".
 * The total number of live processes includes this process and this number - 1 is the maximum index
 * to be used in a process query.
 */

static int max_process_query_idx = 0;

/*
* Working with the Process object and its related counters is inherently
* problematic when using the PDH API:
*
* A process is not primarily identified by the process id, but by an opaque
* index into a list maintained by the kernel. To distinguish which
* process instance is the intended target for a query, the PDH Process API demands,
* at time of registration, a string describing the target process name concatenated
* with the value for this index. For example:
* "\Process(java#0)", "\Process(java#1)", ...
*
* The bad part is that this list is constantly in-flux as
* processes are exiting. One consequence is that processes with indexes
* greater than the one that just terminated is now shifted down by one.
* For example:
* if \Process(java#1) exits, \Process(java#2) now becomes \Process(java#1),
*    \Process(java#2) becomes \Process(java#1) ...
*
* To make matters even more exciting, an already registered query is not invalidated
* when the process list changes. Instead, the query will continue to work just as before,
* or at least, so it seems.
* Only, now, the query will read performance data from another process instance!
* That's right, the performance data is now read from the process that was shifted
* down by the kernel to occupy the index slot associated with our original registration.
*
* Solution:
* The #index identifier for a Process query can only decrease after process creation.
*
* We therefore create an array of counter queries for all process object instances
* up to and including ourselves:
*
* E.g. we come in as the third process instance (java#2), we then create and register
* queries for the following Process object instances:
* java#0, java#1, java#2
*
* current_process_query_index() finds the "correct" pdh process query index by inspecting
* the pdh process list, at a particular instant, i.e. just before we issue the real process query.
* Of course, this is an inherently racy situation because the pdh process list can change at any time.
* We use current_process_query_index() to help keep the number of data errors low,
* where a data error is defined to be the result of using a stale index to query the wrong process.
*
* Ensure to call ensure_current_process_query_index() before every query involving Process object instance data.
*
* returns OS_ERR(-1) if anything goes wrong in the discovery process.
*/


static int current_process_query_index(int previous_query_idx = 0) {
  assert(max_process_query_idx >= 0, "invariant");
  assert(max_process_query_idx >= previous_query_idx, "invariant");
  assert(process_image_name != NULL, "invariant");
  assert(pdh_process_instance_IDProcess_counter_fmt != NULL, "invariant");
  int result = OS_ERR;
  HQUERY tmp_pdh_query_handle = NULL;
  if (open_query(&tmp_pdh_query_handle) != OS_OK) {
    return OS_ERR;
  }
  // We need to find the correct pdh process index corresponding to our process identifier (pid).
  // Begin from the index that was valid at the time of the last query. If that index is no longer valid,
  // it means the pdh process list has changed, i.e. because other processes with the same name as us have terminated.
  // Seek downwards to find the updated, now downshifted, list index corresponding to our pid.
  static const LONG current_pid = (LONG)os::current_process_id();
  const int start_idx = previous_query_idx != 0 ? previous_query_idx : max_process_query_idx;
  for (int idx = start_idx; idx >= 0; --idx) {
    LONG pid;
    const PDH_STATUS status = pdh_process_idx_to_pid(tmp_pdh_query_handle, idx, &pid);
    if (status == PDH_NO_DATA) {
      // pdh process list has changed
      continue;
    }
    if (status != ERROR_SUCCESS) {
      // something went wrong, tmp_pdh_query_handle is already closed.
      return OS_ERR;
    }
    if (current_pid == pid) {
      result = idx;
      break;
    }
  }
  close_query(&tmp_pdh_query_handle, NULL);
  return result;
}

static int ensure_current_process_query_index(ProcessQueryP query) {
  assert(query != NULL, "invariant");
  const int previous_query_idx = query->process_idx;
  if (previous_query_idx == 0) {
    return previous_query_idx;
  }
  const int current_query_idx = current_process_query_index(previous_query_idx);
  if (current_query_idx == OS_ERR || current_query_idx >= query->set.size) {
    return OS_ERR;
  }
  if (current_query_idx == previous_query_idx) {
    return previous_query_idx;
  }
  assert(current_query_idx >= 0 && current_query_idx < query->set.size, "out of bounds!");
  while (current_query_idx < query->set.size - 1) {
    const int new_size = --query->set.size;
    close_query(&query->set.queries[new_size]);
  }
  assert(current_query_idx < query->set.size, "invariant");
  query->process_idx = current_query_idx;
  return OS_OK;
}

static MultiCounterQueryP current_process_query(ProcessQueryP query) {
  assert(query != NULL, "invariant");
  if (ensure_current_process_query_index(query) == OS_ERR) {
    return NULL;
  }
  assert(query->process_idx < query->set.size, "invariant");
  return &query->set.queries[query->process_idx];
}

static int collect(ProcessQueryP query) {
  assert(query != NULL, "invariant");
  MultiCounterQueryP current_query = current_process_query(query);
  return current_query != NULL ? collect(current_query) : OS_ERR;
}

/*
 * Construct a fully qualified PDH counter path.
 *
 * @param object_name   a PDH Object string representation(required)
 * @param counter_name  a PDH Counter string representation(required)
 * @param image_name    a process image name string, ex. "java" (opt)
 * @param instance      an instance string, ex. "0", "1", ... (opt)
 * @return              the fully qualified PDH counter path.
 *
 * Caller will need a ResourceMark.
 *
 * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)
 */

static const char* make_fully_qualified_counter_path(const char* object_name,
                                                     const char* counter_name,
                                                     const char* image_name = NULL,
                                                     const char* instance = NULL) {
  assert(object_name != NULL, "invariant");
  assert(counter_name != NULL, "invariant");
  size_t counter_path_len = strlen(object_name) + strlen(counter_name);

  char* counter_path;
  size_t jio_snprintf_result = 0;
  if (image_name) {
    /*
    * For paths using the "Process" Object.
    *
    * Examples:
    * form:   "\object_name(image_name#instance)\counter_name"
    * actual: "\Process(java#2)\ID Process"
    */

    counter_path_len += PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
    counter_path_len += strlen(image_name);
    /*
    * image_name must be passed together with an associated
    * instance "number" ("0", "1", "2", ...).
    * This is required in order to create valid "Process" Object paths.
    *
    * Examples: "\Process(java#0)", \Process(java#1"), ...
    */

    assert(instance != NULL, "invariant");
    counter_path_len += strlen(instance);
    counter_path = NEW_RESOURCE_ARRAY(char, counter_path_len + 1);
    jio_snprintf_result = jio_snprintf(counter_path,
                                       counter_path_len + 1,
                                       PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT,
                                       object_name,
                                       image_name,
                                       instance,
                                       counter_name);
  } else {
    if (instance) {
      /*
      * For paths where the Object has multiple instances.
      *
      * Examples:
      * form:   "\object_name(instance)\counter_name"
      * actual: "\Processor(0)\% Privileged Time"
      */

      counter_path_len += strlen(instance);
      counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
    } else {
      /*
      * For "normal" paths.
      *
      * Examples:
      * form:   "\object_name\counter_name"
      * actual: "\Memory\Available Mbytes"
      */

      counter_path_len += OBJECT_COUNTER_FMT_LEN;
    }
    counter_path = NEW_RESOURCE_ARRAY(char, counter_path_len + 1);
    if (instance) {
      jio_snprintf_result = jio_snprintf(counter_path,
                                         counter_path_len + 1,
                                         OBJECT_WITH_INSTANCES_COUNTER_FMT,
                                         object_name,
                                         instance,
                                         counter_name);
    } else {
      jio_snprintf_result = jio_snprintf(counter_path,
                                         counter_path_len + 1,
                                         OBJECT_COUNTER_FMT,
                                         object_name,
                                         counter_name);
    }
  }
  assert(counter_path_len == jio_snprintf_result, "invariant");
  return counter_path;
}

static void log_invalid_pdh_index(DWORD index) {
  log_warning(os)("Unable to resolve PDH index: (%ld)", index);
  log_warning(os)("Please check the registry if this performance object/counter is disabled");
}

static bool is_valid_pdh_index(DWORD index) {
  DWORD dummy = 0;
  if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) {
    log_invalid_pdh_index(index);
    return false;
  }
  return true;
}

/*
 * Maps an index to a resource area allocated string for the localized PDH artifact.
 *
 * Caller will need a ResourceMark.
 *
 * @param index    the counter index as specified in the registry
 * @param p_string pointer to a char*
 * @return         OS_OK if successful, OS_ERR on failure.
 */

static OSReturn lookup_name_by_index(DWORD index, char** p_string) {
  assert(p_string != NULL, "invariant");
  if (!is_valid_pdh_index(index)) {
    return OS_ERR;
  }
  // determine size needed
  DWORD size = 0;
  PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);
  assert(status == PDH_MORE_DATA, "invariant");
  *p_string = NEW_RESOURCE_ARRAY(char, size);
  if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {
    return OS_ERR;
  }
  if (0 == size || *p_string == NULL) {
    return OS_ERR;
  }
  // windows vista does not null-terminate the string (although the docs says it will)
  (*p_string)[size - 1] = '\0';
  return OS_OK;
}

static const char* copy_string_to_c_heap(const char* string) {
  assert(string != NULL, "invariant");
  const size_t len = strlen(string);
  charconst cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
  strncpy(cheap_allocated_string, string, len + 1);
  return cheap_allocated_string;
}

/*
* Maps a pdh artifact index to a resource area allocated string representing a localized name.
*
* Caller will need a ResourceMark.
*
* @param pdh_artifact_idx   the counter index as specified in the registry
* @return                   localized pdh artifact string if successful, NULL on failure.
*/

static const char* pdh_localized_artifact(DWORD pdh_artifact_idx) {
  char* pdh_localized_artifact_string = NULL;
  // get localized name for the pdh artifact idx
  if (lookup_name_by_index(pdh_artifact_idx, &pdh_localized_artifact_string) != OS_OK) {
    return NULL;
  }
  return pdh_localized_artifact_string;
}

/*
 * Returns the PDH string identifying the current process image name.
 * Use this prefix when getting counters from the PDH process object
 * representing your process.
 * Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process
 * image description.
 *
 * Caller needs ResourceMark.
 *
 * @return the process image string description, NULL if the call failed.
*/

static const char* pdh_process_image_name() {
  char* module_name = NEW_RESOURCE_ARRAY(char, MAX_PATH);
  // Find our module name and use it to extract the image name used by PDH
  DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH);
  if (getmfn_return >= MAX_PATH || 0 == getmfn_return) {
    return NULL;
  }
  if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) {
    return NULL;
  }
  char* process_image_name = strrchr(module_name, '\\'); //drop path
  process_image_name++;                                  //skip slash
  char* dot_pos = strrchr(process_image_name, '.');      //drop .exe
  dot_pos[0] = '\0';
  return process_image_name;
}

static void deallocate_pdh_constants() {
  FREE_C_HEAP_ARRAY(char, process_image_name);
  process_image_name = NULL;
  FREE_C_HEAP_ARRAY(char, pdh_process_instance_IDProcess_counter_fmt);
  pdh_process_instance_IDProcess_counter_fmt = NULL;
  FREE_C_HEAP_ARRAY(char, pdh_process_instance_wildcard_IDProcess_counter);
  pdh_process_instance_wildcard_IDProcess_counter = NULL;
}

static OSReturn allocate_pdh_constants() {
  assert(process_image_name == NULL, "invariant");
  const char* pdh_image_name = pdh_process_image_name();
  if (pdh_image_name == NULL) {
    return OS_ERR;
  }
  process_image_name = copy_string_to_c_heap(pdh_image_name);

  const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX);
  if (pdh_localized_process_object == NULL) {
    return OS_ERR;
  }

  const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX);
  if (pdh_localized_IDProcess_counter == NULL) {
    return OS_ERR;
  }

  const size_t id_process_base_length = strlen(process_image_name) +
                                        strlen(pdh_localized_process_object) +
                                        strlen(pdh_localized_IDProcess_counter);

  const size_t pdh_IDProcess_counter_fmt_len = id_process_base_length +
                                               PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN +
                                               2; // "%d"

  assert(pdh_process_instance_IDProcess_counter_fmt == NULL, "invariant");
  pdh_process_instance_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);

  /* "\Process(java#%d)\ID Process" */
  size_t len = jio_snprintf(pdh_process_instance_IDProcess_counter_fmt,
                            pdh_IDProcess_counter_fmt_len + 1,
                            PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT,
                            pdh_localized_process_object,
                            process_image_name,
                            "%d",
                            pdh_localized_IDProcess_counter);

  assert(pdh_process_instance_IDProcess_counter_fmt != NULL, "invariant");
  assert(len == pdh_IDProcess_counter_fmt_len, "invariant");


  const size_t pdh_IDProcess_wildcard_fmt_len = id_process_base_length +
                                                PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT_LEN;

  assert(pdh_process_instance_wildcard_IDProcess_counter == NULL, "invariant");
  pdh_process_instance_wildcard_IDProcess_counter = NEW_C_HEAP_ARRAY(char, pdh_IDProcess_wildcard_fmt_len + 1, mtInternal);

  /* "\Process(java*)\ID Process" */
  len = jio_snprintf(pdh_process_instance_wildcard_IDProcess_counter,
                     pdh_IDProcess_wildcard_fmt_len + 1,
                     PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT,
                     pdh_localized_process_object,
                     process_image_name,
                     pdh_localized_IDProcess_counter);

  assert(pdh_process_instance_wildcard_IDProcess_counter != NULL, "invariant");
  assert(len == pdh_IDProcess_wildcard_fmt_len, "invariant");
  return OS_OK;
}

/*
 * Enuerate the Processor PDH object and returns a buffer containing the enumerated instances.
 * Caller needs ResourceMark;
 *
 * @return  buffer if successful, NULL on failure.
*/

static const char* enumerate_cpu_instances() {
  char* processor; //'Processor' == PDH_PROCESSOR_IDX
  if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
    return NULL;
  }
  DWORD c_size = 0;
  DWORD i_size = 0;
  // enumerate all processors.
  PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
                                                  NULL, // local machine
                                                  processor, // object to enumerate
                                                  NULL,
                                                  &c_size,
                                                  NULL, // instance buffer is NULL and
                                                  &i_size,  // pass 0 length in order to get the required size
                                                  PERF_DETAIL_WIZARD, // counter detail level
                                                  0);
  if (PdhDll::PdhStatusFail((pdhStat))) {
    return NULL;
  }
  charconst instances = NEW_RESOURCE_ARRAY(char, i_size);
  c_size = 0;
  pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
                                       NULL, // local machine
                                       processor, // object to enumerate
                                       NULL,
                                       &c_size,
                                       instances, // now instance buffer is allocated to be filled in
                                       &i_size, // and the required size is known
                                       PERF_DETAIL_WIZARD, // counter detail level
                                       0);
  return PdhDll::PdhStatusFail(pdhStat) ? NULL : instances;
}

static int count_logical_cpus(const char* instances) {
  assert(instances != NULL, "invariant");
  // count logical instances.
  DWORD count;
  char* tmp;
  for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++);
  // PDH reports an instance for each logical processor plus an instance for the total (_Total)
  assert(count == os::processor_count() + 1, "invalid enumeration!");
  return count - 1;
}

static int number_of_logical_cpus() {
  static int numberOfCPUS = 0;
  if (numberOfCPUS == 0) {
    const char* instances = enumerate_cpu_instances();
    if (instances == NULL) {
      return OS_ERR;
    }
    numberOfCPUS = count_logical_cpus(instances);
  }
  return numberOfCPUS;
}

static double cpu_factor() {
  static DWORD numCpus = 0;
  static double cpuFactor = .0;
  if (numCpus == 0) {
    numCpus = number_of_logical_cpus();
    assert(os::processor_count() <= (int)numCpus, "invariant");
    cpuFactor = numCpus * 100;
  }
  return cpuFactor;
}

static void log_error_message_on_no_PDH_artifact(const char* counter_path) {
  log_warning(os)("Unable to register PDH query for \"%s\"", counter_path);
  log_warning(os)("Please check the registry if this performance object/counter is disabled");
}

static int initialize_cpu_query_counters(MultiCounterQueryP query, DWORD pdh_counter_idx) {
  assert(query != NULL, "invariant");
  assert(query->counters != NULL, "invariant");
  char* processor; //'Processor' == PDH_PROCESSOR_IDX
  if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
    return OS_ERR;
  }
  char* counter_name = NULL;
  if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {
    return OS_ERR;
  }
  if (query->query.pdh_query_handle == NULL) {
    if (open_query(query) != OS_OK) {
      return OS_ERR;
    }
  }
  assert(query->query.pdh_query_handle != NULL, "invariant");
  size_t counter_len = strlen(processor);
  counter_len += strlen(counter_name);
  counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s"
  const char* instances = enumerate_cpu_instances();
  DWORD index = 0;
  for (char* tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {
    const size_t tmp_len = strlen(tmp);
    char* counter_path = NEW_RESOURCE_ARRAY(char, counter_len + tmp_len + 1);
    const size_t jio_snprintf_result = jio_snprintf(counter_path,
                                                    counter_len + tmp_len + 1,
                                                    OBJECT_WITH_INSTANCES_COUNTER_FMT,
                                                    processor,
                                                    tmp, // instance "0", "1", .."_Total"
                                                    counter_name);
    assert(counter_len + tmp_len == jio_snprintf_result, "invariant");
    if (add_counter(query, &query->counters[index], counter_path, false) != OS_OK) {
      // performance counter is disabled in registry and not accessible via PerfLib
      log_error_message_on_no_PDH_artifact(counter_path);
      // return OS_OK to have the system continue to run without the missing counter
      return OS_OK;
    }
  }
  // Query once to initialize the counters which require at least two samples
  // (like the % CPU usage) to calculate correctly.
  return PdhDll::PdhCollectQueryData(query->query.pdh_query_handle) != ERROR_SUCCESS ? OS_ERR : OS_OK;
}

static int initialize_cpu_query(MultiCounterQueryP query) {
  assert(query != NULL, "invariant");
  assert(!query->initialized, "invariant");
  const int logical_cpu_count = number_of_logical_cpus();
  assert(logical_cpu_count >= os::processor_count(), "invariant");
  // we also add another counter for instance "_Total"
  allocate_counters(query, logical_cpu_count + 1);
  assert(query->noOfCounters == logical_cpu_count + 1, "invariant");
  if (initialize_cpu_query_counters(query, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
    return OS_ERR;
  }
  query->initialized = true;
  return OS_OK;
}

static int initialize_query(CounterQueryP query, DWORD pdh_object_idx, DWORD pdh_counter_idx) {
  assert(query != NULL, "invariant");
  assert(!query->initialized, "invariant");
  if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {
    return OS_ERR;
  }
  const char* object = pdh_localized_artifact(pdh_object_idx);
  assert(object != NULL, "invariant");
  const char* counter = pdh_localized_artifact(pdh_counter_idx);
  assert(counter != NULL, "invariant");
  const char* counter_path = make_fully_qualified_counter_path(object, counter);
  assert(counter_path != NULL, "invariant");
  if (add_counter(query, counter_path, true) != OS_OK) {
    return OS_ERR;
  }
  query->initialized = true;
  return OS_OK;
}

static int initialize_context_switches_query(CounterQueryP query) {
  return initialize_query(query, PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
}

static ProcessQueryP create_process_query() {
  const int current_process_query_idx = current_process_query_index();
  if (current_process_query_idx == OS_ERR) {
    return NULL;
  }
  ProcessQueryP const query = NEW_C_HEAP_OBJ(ProcessQueryS, mtInternal);
  memset(query, 0, sizeof(ProcessQueryS));
  query->process_idx = current_process_query_idx;
  const int size = current_process_query_idx + 1;
  query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, size, mtInternal);
  memset(query->set.queries, 0, sizeof(MultiCounterQueryS) * size);
  query->set.size = size;
  return query;
}

static int initialize_process_counter(ProcessQueryP process_query, int counter_idx, DWORD pdh_counter_idx) {
  char* localized_process_object;
  if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
    return OS_ERR;
  }
  assert(localized_process_object != NULL, "invariant");
  char* localized_counter_name;
  if (lookup_name_by_index(pdh_counter_idx, &localized_counter_name) != OS_OK) {
    return OS_ERR;
  }
  assert(localized_counter_name != NULL, "invariant");
  for (int i = 0; i < process_query->set.size; ++i) {
    char instanceIndexBuffer[32];
    const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
                                                                 localized_counter_name,
                                                                 process_image_name,
                                                                 itoa(i, instanceIndexBuffer, 10));
    assert(counter_path != NULL, "invariant");
    MultiCounterQueryP const query = &process_query->set.queries[i];
    if (add_counter(query, counter_idx, counter_path, true) != OS_OK) {
      return OS_ERR;
    }
    if (counter_idx + 1 == query->noOfCounters) {
      // last counter in query implies query initialized
      query->initialized = true;
    }
  }
  return OS_OK;
}

static int initialize_process_query(ProcessQueryP query) {
  assert(query != NULL, "invariant");
  assert(!query->set.initialized, "invariant");
  allocate_counters(query, 2);
  if (initialize_process_counter(query, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
    return OS_ERR;
  }
  if (initialize_process_counter(query, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
    return OS_ERR;
  }
  query->set.initialized = true;
  return OS_OK;
}

static int reference_count = 0;
static bool pdh_initialized = false;

class PdhMutex : public StackObj {
 private:
  static Semaphore _semaphore;
 public:
  PdhMutex() {
    _semaphore.wait();
  }
  ~PdhMutex() {
    _semaphore.signal();
  }
};

Semaphore PdhMutex::_semaphore(1);

static void on_initialization_failure() {
  // still holder of mutex
  assert(max_process_query_idx == 0, "invariant");
  deallocate_pdh_constants();
  --reference_count;
  PdhDll::PdhDetach();
}

static OSReturn initialize() {
  // still holder of mutex
  ResourceMark rm;
  if (!PdhDll::PdhAttach()) {
    return OS_ERR;
  }
  if (allocate_pdh_constants() != OS_OK) {
    on_initialization_failure();
    return OS_ERR;
  }
  // Take a snapshot of the current number of live processes (including ourselves)
  // with the same name, e.g. "java", in order to derive a value for max_process_query_idx.
  const int process_instance_count = number_of_live_process_instances();
  if (process_instance_count == OS_ERR) {
    on_initialization_failure();
    return OS_ERR;
  }
  assert(process_instance_count > 0, "invariant");
  max_process_query_idx = process_instance_count - 1;
  return OS_OK;
}

/*
* Helper to initialize the PDH library, function pointers, constants and counters.
*
* Reference counting allows for unloading of pdh.dll granted all sessions use the pair:
*
*   pdh_acquire();
*   pdh_release();
*
* @return  OS_OK if successful, OS_ERR on failure.
*/

static OSReturn pdh_acquire() {
  PdhMutex mutex;
  reference_count++;
  if (pdh_initialized) {
    return OS_OK;
  }
  const OSReturn status = initialize();
  pdh_initialized = status == OS_OK;
  return status;
}

static void pdh_release() {
  PdhMutex mutex;
  if (1 == reference_count--) {
    deallocate_pdh_constants();
    PdhDll::PdhDetach();
    pdh_initialized = false;
  }
}

class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
  friend class CPUPerformanceInterface;
 private:
  CounterQueryP _context_switches;
  ProcessQueryP _process_cpu_load;
  MultiCounterQueryP _machine_cpu_load;

  int cpu_load(int which_logical_cpu, double* cpu_load);
  int context_switch_rate(double* rate);
  int cpu_load_total_process(double* cpu_load);
  int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* system_total_load);
  CPUPerformance();
  ~CPUPerformance();
  bool initialize();
};

CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}

bool CPUPerformanceInterface::CPUPerformance::initialize() {
  if (pdh_acquire() != OS_OK) {
    return false;
  }
  _context_switches = create_counter_query();
  assert(_context_switches != NULL, "invariant");
  if (initialize_context_switches_query(_context_switches) != OS_OK) {
    return false;
  }
  assert(_context_switches->initialized, "invariant");
  _process_cpu_load = create_process_query();
  if (_process_cpu_load == NULL) {
    return false;
  }
  if (initialize_process_query(_process_cpu_load) != OS_OK) {
    return false;
  }
  assert(_process_cpu_load->set.initialized, "invariant");
  _machine_cpu_load = create_multi_counter_query();
  assert(_machine_cpu_load != NULL, "invariant");
  if (initialize_cpu_query(_machine_cpu_load) != OS_OK) {
    return false;
  }
  assert(_machine_cpu_load->initialized, "invariant");
  return true;
}

CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
  if (_context_switches != NULL) {
    destroy(_context_switches);
    _context_switches = NULL;
  }
  if (_process_cpu_load != NULL) {
    destroy(_process_cpu_load);
    _process_cpu_load = NULL;
  }
  if (_machine_cpu_load != NULL) {
    destroy(_machine_cpu_load);
    _machine_cpu_load = NULL;
  }
  pdh_release();
}

CPUPerformanceInterface::CPUPerformanceInterface() : _impl(NULL) {}

bool CPUPerformanceInterface::initialize() {
  _impl = new CPUPerformanceInterface::CPUPerformance();
  return _impl->initialize();
}

CPUPerformanceInterface::~CPUPerformanceInterface() {
  if (_impl != NULL) {
    delete _impl;
  }
}

int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
  return _impl->cpu_load(which_logical_cpu, cpu_load);
}

int CPUPerformanceInterface::context_switch_rate(double* rate) const {
  return _impl->context_switch_rate(rate);
}

int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
  return _impl->cpu_load_total_process(cpu_load);
}

int CPUPerformanceInterface::cpu_loads_process(double* jvm_user_load,
                                               double* jvm_kernel_load,
                                               double* system_total_load) const {
  return _impl->cpu_loads_process(jvm_user_load, jvm_kernel_load, system_total_load);
}

int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
  *cpu_load = .0;
  if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) {
    return OS_ERR;
  }
  assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
  if (collect(_machine_cpu_load) != OS_OK) {
    return OS_ERR;
  }
  // -1 is total (all cpus)
  const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;
  PDH_FMT_COUNTERVALUE counter_value;
  if (read_counter(_machine_cpu_load, counter_idx, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  *cpu_load = counter_value.doubleValue / 100;
  return OS_OK;
}

int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
  *cpu_load = .0;
  if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
    return OS_ERR;
  }
  if (collect(_process_cpu_load) != OS_OK) {
    return OS_ERR;
  }
  PDH_FMT_COUNTERVALUE counter_value;
  if (read_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  double process_load = counter_value.doubleValue / cpu_factor();
  process_load = MIN2<double>(1, process_load);
  process_load = MAX2<double>(0, process_load);
  *cpu_load = process_load;
  return OS_OK;
}

int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* jvm_user_load,
                                                               double* jvm_kernel_load,
                                                               double* system_total_load) {
  assert(jvm_user_load != NULL, "jvm_user_load is NULL!");
  assert(jvm_kernel_load != NULL, "jvm_kernel_load is NULL!");
  assert(system_total_load != NULL, "system_total_load is NULL!");
  *jvm_user_load = .0;
  *jvm_kernel_load = .0;
  *system_total_load = .0;

  if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
    return OS_ERR;
  }
  if (collect(_process_cpu_load) != OS_OK) {
    return OS_ERR;
  }
  double process_load = .0;
  PDH_FMT_COUNTERVALUE counter_value;
  // Read PDH_PROCESSOR_TIME_IDX as counter_idx == 0
  if (read_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  process_load = counter_value.doubleValue / cpu_factor();
  process_load = MIN2<double>(1, process_load);
  process_load = MAX2<double>(0, process_load);
  // Read PDH_PRIV_PROCESSOR_TIME_IDX as counter_idx == 1
  if (read_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  double process_kernel_load = counter_value.doubleValue / cpu_factor();
  process_kernel_load = MIN2<double>(1, process_kernel_load);
  process_kernel_load = MAX2<double>(0, process_kernel_load);
  *jvm_kernel_load = process_kernel_load;

  double user_load = process_load - process_kernel_load;
  user_load = MIN2<double>(1, user_load);
  user_load = MAX2<double>(0, user_load);
  *jvm_user_load = user_load;
  if (collect(_machine_cpu_load) != OS_OK) {
    return OS_ERR;
  }
  // Read PDH_PROCESSOR_IDX as counter_idx == _machine_cpu_load->noOfCounters - 1
  if (read_counter(_machine_cpu_load, _machine_cpu_load->noOfCounters - 1, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  double machine_load = counter_value.doubleValue / 100;
  assert(machine_load >= 0, "machine_load is negative!");
  // clamp at user+system and 1.0
  if (*jvm_kernel_load + *jvm_user_load > machine_load) {
    machine_load = MIN2(*jvm_kernel_load + *jvm_user_load, 1.0);
  }
  *system_total_load = machine_load;
  return OS_OK;
}

int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
  assert(rate != NULL, "invariant");
  *rate = .0;
  if (_context_switches == NULL || !_context_switches->initialized) {
    return OS_ERR;
  }
  if (collect(_context_switches) != OS_OK) {
    return OS_ERR;
  }
  PDH_FMT_COUNTERVALUE counter_value;
  if (read_counter(_context_switches, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
    return OS_ERR;
  }
  *rate = counter_value.doubleValue;
  return OS_OK;
}

class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
  friend class SystemProcessInterface;
 private:
  class ProcessIterator : public CHeapObj<mtInternal> {
    friend class SystemProcessInterface::SystemProcesses;
   private:
    HANDLE         _hProcessSnap;
    PROCESSENTRY32 _pe32;
    BOOL           _valid;
    char           _exePath[MAX_PATH];
    ProcessIterator();
    ~ProcessIterator();
    bool initialize();

    int current(SystemProcess* const process_info);
    int next_process();
    bool is_valid() const { return _valid != FALSE; }
    char* allocate_string(const char* str) const;
    int snapshot();
  };

  ProcessIterator* _iterator;
  SystemProcesses();
  ~SystemProcesses();
  bool initialize();

  // information about system processes
  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
};

SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
  _hProcessSnap = INVALID_HANDLE_VALUE;
  _valid = FALSE;
  _pe32.dwSize = sizeof(PROCESSENTRY32);
}

bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
  return true;
}

int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() {
  // take snapshot of all process in the system
  _hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (_hProcessSnap == INVALID_HANDLE_VALUE) {
    return OS_ERR;
  }
  // step to first process
  _valid = Process32First(_hProcessSnap, &_pe32);
  return is_valid() ? OS_OK : OS_ERR;
}

SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
  if (_hProcessSnap != INVALID_HANDLE_VALUE) {
    CloseHandle(_hProcessSnap);
  }
}

int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
  assert(is_valid(), "no current process to be fetched!");
  assert(process_info != NULL, "process_info is NULL!");
  char* exePath = NULL;
  HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID);
  if (hProcess != NULL) {
    HMODULE hMod;
    DWORD cbNeeded;
    if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) {
      if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) {
        exePath = _exePath;
      }
    }
    CloseHandle (hProcess);
  }
  process_info->set_pid((int)_pe32.th32ProcessID);
  process_info->set_name(allocate_string(_pe32.szExeFile));
  process_info->set_path(allocate_string(exePath));
  return OS_OK;
}

char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
  return str != NULL ? os::strdup_check_oom(str, mtInternal) : NULL;
}

int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
  _valid = Process32Next(_hProcessSnap, &_pe32);
  return OS_OK;
}

SystemProcessInterface::SystemProcesses::SystemProcesses() : _iterator(NULL) {}

bool SystemProcessInterface::SystemProcesses::initialize() {
  _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
  return _iterator->initialize();
}

SystemProcessInterface::SystemProcesses::~SystemProcesses() {
  if (_iterator != NULL) {
    delete _iterator;
  }
}

int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes,
                                                              int* no_of_sys_processes) const {
  assert(system_processes != NULL, "system_processes pointer is NULL!");
  assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
  assert(_iterator != NULL, "iterator is NULL!");

  // initialize pointers
  *no_of_sys_processes = 0;
  *system_processes = NULL;

  // take process snapshot
  if (_iterator->snapshot() != OS_OK) {
    return OS_ERR;
  }

  while (_iterator->is_valid()) {
    SystemProcess* tmp = new SystemProcess();
    _iterator->current(tmp);

    //if already existing head
    if (*system_processes != NULL) {
      //move "first to second"
      tmp->set_next(*system_processes);
    }
    // new head
    *system_processes = tmp;
    // increment
    (*no_of_sys_processes)++;
    // step forward
    _iterator->next_process();
  }
  return OS_OK;
}

int SystemProcessInterface::system_processes(SystemProcess** system_procs,
                                             int* no_of_sys_processes) const {
  return _impl->system_processes(system_procs, no_of_sys_processes);
}

SystemProcessInterface::SystemProcessInterface() : _impl(NULL) {}

bool SystemProcessInterface::initialize() {
  _impl = new SystemProcessInterface::SystemProcesses();
  return _impl->initialize();
}

SystemProcessInterface::~SystemProcessInterface() {
  if (_impl != NULL) {
    delete _impl;
  }
}

CPUInformationInterface::CPUInformationInterface() : _cpu_info(NULL) {}

bool CPUInformationInterface::initialize() {
  _cpu_info = new CPUInformation();
  VM_Version::initialize_cpu_information();
  _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads());
  _cpu_info->set_number_of_cores(VM_Version::number_of_cores());
  _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets());
  _cpu_info->set_cpu_name(VM_Version::cpu_name());
  _cpu_info->set_cpu_description(VM_Version::cpu_description());
  return true;
}

CPUInformationInterface::~CPUInformationInterface() {
  if (_cpu_info != NULL) {
    FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_name());
    _cpu_info->set_cpu_name(NULL);
    FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description());
    _cpu_info->set_cpu_description(NULL);
    delete _cpu_info;
  }
}

int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
  if (NULL == _cpu_info) {
    return OS_ERR;
  }
  cpu_info = *_cpu_info; // shallow copy assignment
  return OS_OK;
}

class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
  friend class NetworkPerformanceInterface;
 private:
  bool _iphlp_attached;

  NetworkPerformance();
  NONCOPYABLE(NetworkPerformance);
  bool initialize();
  ~NetworkPerformance();
  int network_utilization(NetworkInterface** network_interfaces) const;
};

NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() : _iphlp_attached(false) {}

bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
  _iphlp_attached = IphlpDll::IphlpAttach();
  return _iphlp_attached;
}

NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
  if (_iphlp_attached) {
    IphlpDll::IphlpDetach();
  }
}

int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
  MIB_IF_TABLE2* table;

  if (IphlpDll::GetIfTable2(&table) != NO_ERROR) {
    return OS_ERR;
  }

  NetworkInterface* ret = NULL;
  for (ULONG i = 0; i < table->NumEntries; ++i) {
    if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) {
      continue;
    }

    char buf[256];
    if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) {
      continue;
    }

    NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret);
    ret = cur;
  }

  IphlpDll::FreeMibTable(table);
  *network_interfaces = ret;

  return OS_OK;
}

NetworkPerformanceInterface::NetworkPerformanceInterface() : _impl(NULL) {}

NetworkPerformanceInterface::~NetworkPerformanceInterface() {
  if (_impl != NULL) {
    delete _impl;
  }
}

bool NetworkPerformanceInterface::initialize() {
  _impl = new NetworkPerformanceInterface::NetworkPerformance();
  return _impl->initialize();
}

int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
  return _impl->network_utilization(network_interfaces);
}

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff