changeset 59363:8fe5ada6695d

8245042: Improve scalability of reading Windows Performance counters via PDH when using the Process object Reviewed-by: dcubed, egahlin
author mgronlun
date Wed, 20 May 2020 12:06:05 +0200
parents db19c7c917a2
children 2499ae33ef07
files src/hotspot/os/windows/os_perf_windows.cpp src/hotspot/os/windows/pdh_interface.cpp src/hotspot/os/windows/pdh_interface.hpp
diffstat 3 files changed, 721 insertions(+), 605 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/os/windows/os_perf_windows.cpp	Wed May 20 11:59:09 2020 +0200
+++ b/src/hotspot/os/windows/os_perf_windows.cpp	Wed May 20 12:06:05 2020 +0200
@@ -30,6 +30,7 @@
 #include "pdh_interface.hpp"
 #include "runtime/os_perf.hpp"
 #include "runtime/os.hpp"
+#include "runtime/semaphore.inline.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include CPU_HEADER(vm_version_ext)
@@ -45,18 +46,15 @@
  * 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 query
+ * 1. Create a query
  * 2. Add counters to the query
  * 3. Collect the performance data using the query
- * 4. Display the performance data using the counters associated with 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.
@@ -76,27 +74,26 @@
 static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;
 static const DWORD PDH_SYSTEM_IDX = 2;
 
-/* useful pdh fmt's */
+/* useful pdh fmt's for the general form: \object(instance#index)\counter */
 static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
 static const size_t OBJECT_COUNTER_FMT_LEN = 2;
 static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
 static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
-static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
-static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
+static const char* const PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s#%s)\\%s";
+static const size_t PROCESS_OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 5;
+static const char* const PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT = "\\%s(%s*)\\%s";
+static const size_t PROCESS_OBJECT_WITH_INSTANCES_WILDCARD_FMT_LEN = 5;
 
-static const char* process_image_name = NULL; // for example, "java" but could have another image name
-static char* pdh_IDProcess_counter_fmt = NULL;   // "\Process(java#%d)\ID Process" */
-
-// 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;
+/* 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 query;
+  HQUERY pdh_query_handle;
   s8     lastUpdate; // Last time query was updated.
 } UpdateQueryS, *UpdateQueryP;
 
@@ -122,77 +119,89 @@
 
 typedef struct {
   MultiCounterQuerySetS set;
-  int                   process_index;
+  int                   process_idx;
 } ProcessQueryS, *ProcessQueryP;
 
-static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
+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 (query != NULL && *query != NULL) {
-    PdhDll::PdhCloseQuery(*query);
-    *query = 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 void destroy_counter_query(CounterQueryP query) {
-  assert(query != NULL, "invariant");
-  pdh_cleanup(&query->query.query, &query->counter);
-  FREE_C_HEAP_OBJ(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_counter_query(MultiCounterQueryP counter_query) {
-  if (counter_query != NULL) {
-    for (int i = 0; i < counter_query->noOfCounters; ++i) {
-      pdh_cleanup(NULL, &counter_query->counters[i]);
+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, counter_query->counters);
-    pdh_cleanup(&counter_query->query.query, NULL);
-    FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query);
+    FREE_C_HEAP_ARRAY(char, query->counters);
+    close_query(&query->query.pdh_query_handle, NULL);
+    FREE_C_HEAP_ARRAY(MultiCounterQueryS, query);
   }
 }
 
-static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) {
-  for (int i = 0; i < counter_query_set->size; i++) {
-    for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
-      pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
+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, counter_query_set->queries[i].counters);
-    pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
+    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, counter_query_set->queries);
+  FREE_C_HEAP_ARRAY(MultiCounterQueryS, query_set->queries);
 }
 
-static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
-  destroy_multi_counter_query(counter_query_set);
-  FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
+static void destroy(MultiCounterQuerySetP query) {
+  destroy_query_set(query);
+  FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, query);
 }
 
-static void destroy_counter_query(ProcessQueryP process_query) {
-  destroy_multi_counter_query(&process_query->set);
-  FREE_C_HEAP_OBJ(process_query);
-}
-
-static int open_query(HQUERY* query) {
-  return PdhDll::PdhOpenQuery(NULL, 0, query);
-}
-
-template <typename QueryP>
-static int open_query(QueryP query) {
-  return open_query(&query->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) {
@@ -205,17 +214,17 @@
   query->noOfCounters = (int)nofCounters;
 }
 
-static void allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {
-  assert(query_set != NULL, "invariant");
-  assert(!query_set->initialized, "invariant");
-  for (int i = 0; i < query_set->size; ++i) {
-    allocate_counters(&query_set->queries[i], 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 process_query, size_t nofCounters) {
-  assert(process_query != NULL, "invariant");
-  allocate_counters(&process_query->set, 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) {
@@ -224,17 +233,17 @@
   query->noOfCounters = 0;
 }
 
-static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
+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(path != NULL, "invariant");
-  if (query->query == NULL) {
-    if (open_query(query) != ERROR_SUCCESS) {
+  assert(counter_path != NULL, "invariant");
+  if (query->pdh_query_handle == NULL) {
+    if (open_query(query) != OS_OK) {
       return OS_ERR;
     }
   }
-  assert(query->query != NULL, "invariant");
-  PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);
+  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;
   }
@@ -249,212 +258,276 @@
   *  Take the first sample here already to allow for the next "real" sample
   *  to succeed.
   */
-  if (first_sample_on_init) {
-    PdhDll::PdhCollectQueryData(query->query);
-  }
-  return OS_OK;
-}
-
-template <typename QueryP>
-static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
-  assert(counter_query != NULL, "invariant");
-  assert(counter != NULL, "invariant");
-  assert(path != NULL, "invariant");
-  return add_counter(&counter_query->query, counter, path, first_sample_on_init);
-}
-
-static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {
-  if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {
-    // performance counter might be disabled in the registry
-    return OS_ERR;
-  }
-  counter_query->initialized = true;
-  return OS_OK;
-}
-
-static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
-  assert(query != NULL, "invariant");
-  assert(slot_index < query->noOfCounters, "invariant");
-  assert(query->counters[slot_index] == NULL, "invariant");
-  const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
-  if (OS_OK == ret) {
-    if (slot_index + 1 == query->noOfCounters) {
-      query->initialized = true;
-    }
-  }
-  return ret;
-}
-
-static int collect_query_data(UpdateQueryP update_query) {
-  assert(update_query != NULL, "invariant");
-  const s8 now = os::javaTimeNanos();
-  if (nanos_to_millis(now - update_query->lastUpdate) > min_update_interval_millis) {
-    if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {
-      return OS_ERR;
-    }
-    update_query->lastUpdate = now;
-  }
-  return OS_OK;
-}
-
-template <typename Query>
-static int collect_query_data(Query* counter_query) {
-  assert(counter_query != NULL, "invariant");
-  return collect_query_data(&counter_query->query);
-}
-
-static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
-  assert(value != NULL, "invariant");
-  if (PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS) {
+  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);
+}
+
 /*
-* Working against the Process object and it's related counters is inherently problematic
-* when using the PDH API:
+* 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 char* const 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:
 *
-* Using PDH, a process is not primarily identified by the process id,
-* but with a sequential number, for example \Process(java#0), \Process(java#1), ...
-* The really bad part is that this list is reset as soon as a process exits:
-* If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
+* 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 PDH api requires a process identifier to be submitted when registering
-* a query, but as soon as the list resets, the query is invalidated (since the name changed).
+* 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 #number identifier for a Process query can only decrease after process creation.
+* 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:
 *
-* Ex. we come in as third process instance (java#2), we then create and register
+* 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_query_index_for_process() keeps track of the current "correct" query
-* (in order to keep this index valid when the list resets from underneath,
-* ensure to call current_query_index_for_process() before every query involving
-* Process object instance data).
+* 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.
 *
-* if unable to query, returns OS_ERR(-1)
+* returns OS_ERR(-1) if anything goes wrong in the discovery process.
 */
-static int current_query_index_for_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_IDProcess_counter_fmt != NULL, "invariant");
-  HQUERY tmpQuery = NULL;
-  if (open_query(&tmpQuery) != ERROR_SUCCESS) {
+  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;
   }
-  char counter[512];
-  HCOUNTER handle_counter = NULL;
-  // iterate over all instance indexes and try to find our own pid
-  for (int index = 0; index < max_intx; index++) {
-    jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);
-    assert(strlen(counter) < sizeof(counter), "invariant");
-    if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
-      pdh_cleanup(&tmpQuery, &handle_counter);
+  // 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;
     }
-    const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
-    if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
-      pdh_cleanup(&tmpQuery, &handle_counter);
-      return OS_ERR;
-    } else {
-      PDH_FMT_COUNTERVALUE counter_value;
-      formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
-      pdh_cleanup(NULL, &handle_counter);
-      if ((LONG)os::current_process_id() == counter_value.longValue) {
-        pdh_cleanup(&tmpQuery, NULL);
-        return index;
-      }
+    if (current_pid == pid) {
+      result = idx;
+      break;
     }
   }
-  pdh_cleanup(&tmpQuery, NULL);
-  return OS_ERR;
+  close_query(&tmp_pdh_query_handle, NULL);
+  return result;
 }
 
-static ProcessQueryP create_process_query() {
-  const int current_process_idx = current_query_index_for_process();
-  if (OS_ERR == current_process_idx) {
+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;
   }
-  ProcessQueryP const process_query = NEW_C_HEAP_OBJ(ProcessQueryS, mtInternal);
-  memset(process_query, 0, sizeof(ProcessQueryS));
-  process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
-  memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
-  process_query->process_index = current_process_idx;
-  process_query->set.size = current_process_idx + 1;
-  assert(process_query->set.size > process_query->process_index, "invariant");
-  return process_query;
-}
-
-static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) {
-  assert(process_query != NULL, "invariant");
-  assert(process_query->process_index < process_query->set.size, "invariant");
-  return &process_query->set.queries[process_query->process_index];
-}
-
-static void clear_multi_counter(MultiCounterQueryP query) {
-  for (int i = 0; i < query->noOfCounters; ++i) {
-    pdh_cleanup(NULL, &query->counters[i]);
-  }
-  pdh_cleanup(&query->query.query, NULL);
-  query->initialized = false;
+  assert(query->process_idx < query->set.size, "invariant");
+  return &query->set.queries[query->process_idx];
 }
 
-static int ensure_valid_process_query_index(ProcessQueryP process_query) {
-  assert(process_query != NULL, "invariant");
-  const int previous_process_idx = process_query->process_index;
-  if (previous_process_idx == 0) {
-    return previous_process_idx;
-  }
-  const int current_process_idx = current_query_index_for_process();
-  if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx ||
-    current_process_idx >= process_query->set.size) {
-    return previous_process_idx;
-  }
-
-  assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!");
-  while (current_process_idx < process_query->set.size - 1) {
-    const int new_size = --process_query->set.size;
-    clear_multi_counter(&process_query->set.queries[new_size]);
-  }
-  assert(current_process_idx < process_query->set.size, "invariant");
-  process_query->process_index = current_process_idx;
-  return current_process_idx;
-}
-
-static MultiCounterQueryP current_process_query(ProcessQueryP process_query) {
-  assert(process_query != NULL, "invariant");
-  const int current_process_idx = ensure_valid_process_query_index(process_query);
-  assert(current_process_idx == process_query->process_index, "invariant");
-  assert(current_process_idx < process_query->set.size, "invariant");
-  return &process_query->set.queries[current_process_idx];
-}
-
-static int collect_process_query_data(ProcessQueryP process_query) {
-  assert(process_query != NULL, "invariant");
-  return collect_query_data(current_process_query(process_query));
-}
-
-static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
-  MultiCounterQueryP const current_query = current_process_counter_query(process_query);
-  assert(current_query != NULL, "invariant");
-  assert(slot_index < current_query->noOfCounters, "invariant");
-  assert(current_query->counters[slot_index] != NULL, "invariant");
-  return formatted_counter_value(current_query->counters[slot_index], format, value);
+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 path
+ * Construct a fully qualified PDH counter path.
  *
- * @param objectName   a PDH Object string representation(required)
- * @param counterName  a PDH Counter string representation(required)
- * @param imageName    a process image name string, ex. "java" (opt)
- * @param instance     an instance string, ex. "0", "1", ... (opt)
- * @return             the fully qualified PDH 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.
  *
@@ -466,9 +539,9 @@
                                                      const char* instance = NULL) {
   assert(object_name != NULL, "invariant");
   assert(counter_name != NULL, "invariant");
-  size_t full_counter_path_len = strlen(object_name) + strlen(counter_name);
+  size_t counter_path_len = strlen(object_name) + strlen(counter_name);
 
-  char* full_counter_path;
+  char* counter_path;
   size_t jio_snprintf_result = 0;
   if (image_name) {
     /*
@@ -478,8 +551,8 @@
     * form:   "\object_name(image_name#instance)\counter_name"
     * actual: "\Process(java#2)\ID Process"
     */
-    full_counter_path_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
-    full_counter_path_len += strlen(image_name);
+    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", ...).
@@ -488,14 +561,11 @@
     * Examples: "\Process(java#0)", \Process(java#1"), ...
     */
     assert(instance != NULL, "invariant");
-    full_counter_path_len += strlen(instance);
-    full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
-    if (full_counter_path == NULL) {
-      return NULL;
-    }
-    jio_snprintf_result = jio_snprintf(full_counter_path,
-                                       full_counter_path_len + 1,
-                                       PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
+    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,
@@ -509,8 +579,8 @@
       * form:   "\object_name(instance)\counter_name"
       * actual: "\Processor(0)\% Privileged Time"
       */
-      full_counter_path_len += strlen(instance);
-      full_counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
+      counter_path_len += strlen(instance);
+      counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
     } else {
       /*
       * For "normal" paths.
@@ -519,29 +589,26 @@
       * form:   "\object_name\counter_name"
       * actual: "\Memory\Available Mbytes"
       */
-      full_counter_path_len += OBJECT_COUNTER_FMT_LEN;
+      counter_path_len += OBJECT_COUNTER_FMT_LEN;
     }
-    full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
-    if (full_counter_path == NULL) {
-      return NULL;
-    }
+    counter_path = NEW_RESOURCE_ARRAY(char, counter_path_len + 1);
     if (instance) {
-      jio_snprintf_result = jio_snprintf(full_counter_path,
-                                         full_counter_path_len + 1,
+      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(full_counter_path,
-                                         full_counter_path_len + 1,
+      jio_snprintf_result = jio_snprintf(counter_path,
+                                         counter_path_len + 1,
                                          OBJECT_COUNTER_FMT,
                                          object_name,
                                          counter_name);
     }
   }
-  assert(full_counter_path_len == jio_snprintf_result, "invariant");
-  return full_counter_path;
+  assert(counter_path_len == jio_snprintf_result, "invariant");
+  return counter_path;
 }
 
 static void log_invalid_pdh_index(DWORD index) {
@@ -564,7 +631,7 @@
  * Caller will need a ResourceMark.
  *
  * @param index    the counter index as specified in the registry
- * @param ppBuffer pointer to a char*
+ * @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) {
@@ -576,10 +643,7 @@
   DWORD size = 0;
   PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);
   assert(status == PDH_MORE_DATA, "invariant");
-  *p_string = NEW_RESOURCE_ARRAY_RETURN_NULL(char, size);
-  if (*p_string== NULL) {
-    return OS_ERR;
-  }
+  *p_string = NEW_RESOURCE_ARRAY(char, size);
   if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {
     return OS_ERR;
   }
@@ -594,26 +658,23 @@
 static const char* copy_string_to_c_heap(const char* string) {
   assert(string != NULL, "invariant");
   const size_t len = strlen(string);
-  char* const cheap_allocated_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len + 1, mtInternal);
-  if (NULL == cheap_allocated_string) {
-    return NULL;
-  }
+  char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
   strncpy(cheap_allocated_string, string, len + 1);
   return cheap_allocated_string;
 }
 
 /*
-* Maps an index to a resource area allocated string for the localized PDH artifact.
+* Maps a pdh artifact index to a resource area allocated string representing a localized name.
 *
 * Caller will need a ResourceMark.
 *
-* @param index    the counter index as specified in the registry
-* @return         localized pdh artifact string if successful, NULL on failure.
+* @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_index) {
+static const char* pdh_localized_artifact(DWORD pdh_artifact_idx) {
   char* pdh_localized_artifact_string = NULL;
-  // get localized name from pdh artifact index
-  if (lookup_name_by_index(pdh_artifact_index, &pdh_localized_artifact_string) != OS_OK) {
+  // 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;
@@ -628,13 +689,10 @@
  *
  * Caller needs ResourceMark.
  *
- * @return the process image description. NULL if the call failed.
+ * @return the process image string description, NULL if the call failed.
 */
 static const char* pdh_process_image_name() {
-  char* module_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, MAX_PATH);
-  if (NULL == module_name) {
-    return NULL;
-  }
+  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) {
@@ -653,11 +711,13 @@
 static void deallocate_pdh_constants() {
   FREE_C_HEAP_ARRAY(char, process_image_name);
   process_image_name = NULL;
-  FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt);
-  pdh_IDProcess_counter_fmt = 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 int allocate_pdh_constants() {
+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) {
@@ -675,29 +735,46 @@
     return OS_ERR;
   }
 
-  size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name);
-  pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object);
-  pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter);
-  pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
-  pdh_IDProcess_counter_fmt_len += 2; // "%d"
+  const size_t id_process_base_length = strlen(process_image_name) +
+                                        strlen(pdh_localized_process_object) +
+                                        strlen(pdh_localized_IDProcess_counter);
 
-  assert(pdh_IDProcess_counter_fmt == NULL, "invariant");
-  pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);
-  if (pdh_IDProcess_counter_fmt == NULL) {
-    return OS_ERR;
-  }
+  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" */
-  const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt,
-                                  pdh_IDProcess_counter_fmt_len + 1,
-                                  PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
-                                  pdh_localized_process_object,
-                                  process_image_name,
-                                  "%d",
-                                  pdh_localized_IDProcess_counter);
+  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");
+
 
-  assert(pdh_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;
 }
 
@@ -727,10 +804,7 @@
   if (PdhDll::PdhStatusFail((pdhStat))) {
     return NULL;
   }
-  char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size);
-  if (instances == NULL) {
-    return NULL;
-  }
+  char* const instances = NEW_RESOURCE_ARRAY(char, i_size);
   c_size = 0;
   pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
                                        NULL, // local machine
@@ -741,10 +815,7 @@
                                        &i_size, // and the required size is known
                                        PERF_DETAIL_WIZARD, // counter detail level
                                        0);
-  if (PdhDll::PdhStatusFail((pdhStat))) {
-    return NULL;
-  }
-  return instances;
+  return PdhDll::PdhStatusFail(pdhStat) ? NULL : instances;
 }
 
 static int count_logical_cpus(const char* instances) {
@@ -771,7 +842,7 @@
 }
 
 static double cpu_factor() {
-  static DWORD  numCpus = 0;
+  static DWORD numCpus = 0;
   static double cpuFactor = .0;
   if (numCpus == 0) {
     numCpus = number_of_logical_cpus();
@@ -781,14 +852,14 @@
   return cpuFactor;
 }
 
-static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) {
-  log_warning(os)("Unable to register PDH query for \"%s\"", full_counter_name);
+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 cpu_query, DWORD pdh_counter_idx) {
-  assert(cpu_query != NULL, "invariant");
-  assert(cpu_query->counters != NULL, "invariant");
+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;
@@ -797,25 +868,20 @@
   if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {
     return OS_ERR;
   }
-  if (cpu_query->query.query == NULL) {
-    if (open_query(cpu_query)) {
+  if (query->query.pdh_query_handle == NULL) {
+    if (open_query(query) != OS_OK) {
       return OS_ERR;
     }
   }
-  assert(cpu_query->query.query != NULL, "invariant");
+  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"
-
-  DWORD index;
-  char* tmp;
   const char* instances = enumerate_cpu_instances();
-  for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {
+  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_RETURN_NULL(char, counter_len + tmp_len + 1);
-    if (counter_path == NULL) {
-      return OS_ERR;
-    }
+    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,
@@ -823,39 +889,79 @@
                                                     tmp, // instance "0", "1", .."_Total"
                                                     counter_name);
     assert(counter_len + tmp_len == jio_snprintf_result, "invariant");
-    if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) {
+    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;
     }
   }
-  cpu_query->initialized = true;
   // Query once to initialize the counters which require at least two samples
   // (like the % CPU usage) to calculate correctly.
-  collect_query_data(cpu_query);
+  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_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
-  assert(cpu_query != NULL, "invariant");
-  assert(!cpu_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(cpu_query, logical_cpu_count + 1);
-  assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");
-  return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
+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_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) {
+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_index, &localized_counter_name) != OS_OK) {
+  if (lookup_name_by_index(pdh_counter_idx, &localized_counter_name) != OS_OK) {
     return OS_ERR;
   }
   assert(localized_counter_name != NULL, "invariant");
@@ -865,48 +971,60 @@
                                                                  localized_counter_name,
                                                                  process_image_name,
                                                                  itoa(i, instanceIndexBuffer, 10));
-    if (counter_path == NULL) {
+    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;
     }
-    MultiCounterQueryP const query = &process_query->set.queries[i];
-    if (add_process_counter(query, slot_index, counter_path, true)) {
-      return OS_ERR;
+    if (counter_idx + 1 == query->noOfCounters) {
+      // last counter in query implies query initialized
+      query->initialized = true;
     }
   }
   return OS_OK;
 }
 
-static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
-  if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {
-    return NULL;
+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;
   }
-  CounterQueryP const query = create_counter_query();
-  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* full_counter_path = make_fully_qualified_counter_path(object, counter);
-  assert(full_counter_path != NULL, "invariant");
-  add_counter(query, full_counter_path, true);
-  return query;
+  if (initialize_process_counter(query, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
+    return OS_ERR;
+  }
+  query->set.initialized = true;
+  return OS_OK;
 }
 
-static void deallocate() {
+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 LONG critical_section = 0;
-static LONG reference_count = 0;
-static bool pdh_initialized = false;
-
-static void on_initialization_failure() {
-  // still holder of critical section
-  deallocate();
-  InterlockedExchangeAdd(&reference_count, -1);
-}
-
 static OSReturn initialize() {
+  // still holder of mutex
   ResourceMark rm;
   if (!PdhDll::PdhAttach()) {
     return OS_ERR;
@@ -915,6 +1033,15 @@
     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;
 }
 
@@ -928,28 +1055,24 @@
 *
 * @return  OS_OK if successful, OS_ERR on failure.
 */
-static bool pdh_acquire() {
-  while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
-  InterlockedExchangeAdd(&reference_count, 1);
+static OSReturn pdh_acquire() {
+  PdhMutex mutex;
+  reference_count++;
   if (pdh_initialized) {
-    return true;
+    return OS_OK;
   }
-  const OSReturn ret = initialize();
-  if (OS_OK == ret) {
-    pdh_initialized = true;
-  }
-  while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
-  return ret == OS_OK;
+  const OSReturn status = initialize();
+  pdh_initialized = status == OS_OK;
+  return status;
 }
 
 static void pdh_release() {
-  while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
-  const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);
-  if (1 == prev_ref_count) {
-    deallocate();
+  PdhMutex mutex;
+  if (1 == reference_count--) {
+    deallocate_pdh_constants();
+    PdhDll::PdhDetach();
     pdh_initialized = false;
   }
-  while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 }
 
 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
@@ -962,12 +1085,198 @@
   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* psystemTotalLoad);
+  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:
@@ -998,195 +1307,6 @@
   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
 };
 
-CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
-
-bool CPUPerformanceInterface::CPUPerformance::initialize() {
-  if (!pdh_acquire()) {
-    return true;
-  }
-  _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
-  _process_cpu_load = create_process_query();
-  if (_process_cpu_load == NULL) {
-    return true;
-  }
-  allocate_counters(_process_cpu_load, 2);
-  if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
-    return true;
-  }
-  if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
-    return true;
-  }
-  _process_cpu_load->set.initialized = true;
-  _machine_cpu_load = create_multi_counter_query();
-  if (_machine_cpu_load == NULL) {
-    return true;
-  }
-  initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX);
-  return true;
-}
-
-CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
-  if (_context_switches != NULL) {
-    destroy_counter_query(_context_switches);
-    _context_switches = NULL;
-  }
-  if (_process_cpu_load != NULL) {
-    destroy_counter_query(_process_cpu_load);
-    _process_cpu_load = NULL;
-  }
-  if (_machine_cpu_load != NULL) {
-    destroy_counter_query(_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* pjvmUserLoad,
-                                               double* pjvmKernelLoad,
-                                               double* psystemTotalLoad) const {
-  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
-}
-
-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(_machine_cpu_load != NULL, "invariant");
-  assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
-
-  if (collect_query_data(_machine_cpu_load)) {
-    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;
-  formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);
-  *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;
-  }
-  assert(_process_cpu_load != NULL, "invariant");
-  if (collect_process_query_data(_process_cpu_load)) {
-    return OS_ERR;
-  }
-  PDH_FMT_COUNTERVALUE counter_value;
-  if (query_process_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* pjvmUserLoad,
-                                                               double* pjvmKernelLoad,
-                                                               double* psystemTotalLoad) {
-  assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");
-  assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");
-  assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");
-  *pjvmUserLoad = .0;
-  *pjvmKernelLoad = .0;
-  *psystemTotalLoad = .0;
-
-  if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
-    return OS_ERR;
-  }
-  assert(_process_cpu_load != NULL, "invariant");
-  if (collect_process_query_data(_process_cpu_load)) {
-    return OS_ERR;
-  }
-  double process_load = .0;
-  PDH_FMT_COUNTERVALUE counter_value;
-  // Read  PDH_PROCESSOR_TIME_IDX
-  if (query_process_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
-  if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
-    return OS_ERR;
-  }
-  double kernel_load = counter_value.doubleValue / cpu_factor();
-  kernel_load = MIN2<double>(1, kernel_load);
-  kernel_load = MAX2<double>(0, kernel_load);
-  *pjvmKernelLoad = kernel_load;
-
-  double user_load = process_load - kernel_load;
-  user_load = MIN2<double>(1, user_load);
-  user_load = MAX2<double>(0, user_load);
-  *pjvmUserLoad = user_load;
-
-  if (collect_query_data(_machine_cpu_load)) {
-    return OS_ERR;
-  }
-  if (formatted_counter_value(_machine_cpu_load->counters[_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 (*pjvmKernelLoad + *pjvmUserLoad > machine_load) {
-    machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0);
-  }
-  *psystemTotalLoad = 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;
-  }
-  assert(_context_switches != NULL, "invariant");
-  if (collect_query_data(_context_switches) != OS_OK) {
-    return OS_ERR;
-  }
-  PDH_FMT_COUNTERVALUE counter_value;
-  if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
-    return OS_ERR;
-  }
-  *rate = counter_value.doubleValue;
-  return OS_OK;
-}
-
 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
   _hProcessSnap = INVALID_HANDLE_VALUE;
   _valid = FALSE;
@@ -1236,10 +1356,7 @@
 }
 
 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
-  if (str != NULL) {
-    return os::strdup_check_oom(str, mtInternal);
-  }
-  return NULL;
+  return str != NULL ? os::strdup_check_oom(str, mtInternal) : NULL;
 }
 
 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
@@ -1247,9 +1364,7 @@
   return OS_OK;
 }
 
-SystemProcessInterface::SystemProcesses::SystemProcesses() {
-  _iterator = NULL;
-}
+SystemProcessInterface::SystemProcesses::SystemProcesses() : _iterator(NULL) {}
 
 bool SystemProcessInterface::SystemProcesses::initialize() {
   _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
@@ -1259,7 +1374,6 @@
 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
   if (_iterator != NULL) {
     delete _iterator;
-    _iterator = NULL;
   }
 }
 
@@ -1302,9 +1416,7 @@
   return _impl->system_processes(system_procs, no_of_sys_processes);
 }
 
-SystemProcessInterface::SystemProcessInterface() {
-  _impl = NULL;
-}
+SystemProcessInterface::SystemProcessInterface() : _impl(NULL) {}
 
 bool SystemProcessInterface::initialize() {
   _impl = new SystemProcessInterface::SystemProcesses();
@@ -1317,9 +1429,7 @@
   }
 }
 
-CPUInformationInterface::CPUInformationInterface() {
-  _cpu_info = NULL;
-}
+CPUInformationInterface::CPUInformationInterface() : _cpu_info(NULL) {}
 
 bool CPUInformationInterface::initialize() {
   _cpu_info = new CPUInformation();
@@ -1338,7 +1448,6 @@
     FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description());
     _cpu_info->set_cpu_description(NULL);
     delete _cpu_info;
-    _cpu_info = NULL;
   }
 }
 
@@ -1362,9 +1471,7 @@
   int network_utilization(NetworkInterface** network_interfaces) const;
 };
 
-NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance()
-: _iphlp_attached(false) {
-}
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() : _iphlp_attached(false) {}
 
 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
   _iphlp_attached = IphlpDll::IphlpAttach();
@@ -1405,9 +1512,7 @@
   return OS_OK;
 }
 
-NetworkPerformanceInterface::NetworkPerformanceInterface() {
-  _impl = NULL;
-}
+NetworkPerformanceInterface::NetworkPerformanceInterface() : _impl(NULL) {}
 
 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
   if (_impl != NULL) {
--- a/src/hotspot/os/windows/pdh_interface.cpp	Wed May 20 11:59:09 2020 +0200
+++ b/src/hotspot/os/windows/pdh_interface.cpp	Wed May 20 12:06:05 2020 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, 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
@@ -37,6 +37,7 @@
 typedef PDH_STATUS (WINAPI *PdhRemoveCounter_Fn)(HCOUNTER);
 typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndex_Fn)(LPCSTR, DWORD, LPSTR, LPDWORD);
 typedef PDH_STATUS (WINAPI *PdhMakeCounterPath_Fn)(PDH_COUNTER_PATH_ELEMENTS*, LPTSTR, LPDWORD, DWORD);
+typedef PDH_STATUS (WINAPI *PdhExpandWildCardPath_Fn)(LPCSTR, LPCSTR, PZZSTR, LPDWORD, DWORD);
 
 PdhAddCounter_Fn PdhDll::_PdhAddCounter = NULL;
 PdhOpenQuery_Fn  PdhDll::_PdhOpenQuery = NULL;
@@ -47,6 +48,7 @@
 PdhRemoveCounter_Fn PdhDll::_PdhRemoveCounter = NULL;
 PdhLookupPerfNameByIndex_Fn PdhDll::_PdhLookupPerfNameByIndex = NULL;
 PdhMakeCounterPath_Fn PdhDll::_PdhMakeCounterPath = NULL;
+PdhExpandWildCardPath_Fn PdhDll::_PdhExpandWildCardPath = NULL;
 
 LONG PdhDll::_critical_section = 0;
 LONG PdhDll::_initialized = 0;
@@ -68,6 +70,7 @@
   _PdhRemoveCounter            = (PdhRemoveCounter_Fn)::GetProcAddress(_hModule, "PdhRemoveCounter");
   _PdhLookupPerfNameByIndex    = (PdhLookupPerfNameByIndex_Fn)::GetProcAddress(_hModule, "PdhLookupPerfNameByIndexA");
   _PdhMakeCounterPath          = (PdhMakeCounterPath_Fn)::GetProcAddress(_hModule, "PdhMakeCounterPathA");
+  _PdhExpandWildCardPath       = (PdhExpandWildCardPath_Fn)::GetProcAddress(_hModule, "PdhExpandWildCardPathA");
   InterlockedExchange(&_initialized, 1);
 }
 
@@ -88,6 +91,7 @@
         _PdhRemoveCounter = NULL;
         _PdhLookupPerfNameByIndex = NULL;
         _PdhMakeCounterPath = NULL;
+        _PdhExpandWildCardPath = NULL;
         InterlockedExchange(&_initialized, 0);
       }
     }
@@ -109,7 +113,7 @@
          && _PdhCloseQuery != NULL && PdhCollectQueryData != NULL
          && _PdhGetFormattedCounterValue != NULL && _PdhEnumObjectItems != NULL
          && _PdhRemoveCounter != NULL && PdhLookupPerfNameByIndex != NULL
-         && _PdhMakeCounterPath != NULL);
+         && _PdhMakeCounterPath != NULL && _PdhExpandWildCardPath != NULL);
 }
 
 PDH_STATUS PdhDll::PdhAddCounter(HQUERY hQuery, LPCSTR szFullCounterPath, DWORD dwUserData, HCOUNTER* phCounter) {
@@ -160,6 +164,11 @@
   return _PdhMakeCounterPath(pCounterPathElements, szFullPathBuffer, pcchBufferSize, dwFlags);
 }
 
+PDH_STATUS PdhDll::PdhExpandWildCardPath(LPCSTR szDataSource, LPCSTR szWildCardPath, PZZSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags) {
+  assert(_initialized && PdhExpandWildCardPath != NULL, "PdhAvailable() not yet called");
+  return _PdhExpandWildCardPath(szDataSource, szWildCardPath, mszExpandedPathList, pcchPathListLength, dwFlags);
+}
+
 bool PdhDll::PdhStatusFail(PDH_STATUS pdhStat) {
   return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
 }
--- a/src/hotspot/os/windows/pdh_interface.hpp	Wed May 20 11:59:09 2020 +0200
+++ b/src/hotspot/os/windows/pdh_interface.hpp	Wed May 20 12:06:05 2020 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, 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
@@ -45,6 +45,7 @@
   static PDH_STATUS (WINAPI *_PdhRemoveCounter)(HCOUNTER);
   static PDH_STATUS (WINAPI *_PdhLookupPerfNameByIndex)(LPCSTR, DWORD, LPSTR, LPDWORD);
   static PDH_STATUS (WINAPI *_PdhMakeCounterPath)(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
+  static PDH_STATUS (WINAPI *_PdhExpandWildCardPath)(LPCSTR, LPCSTR, PZZSTR, LPDWORD, DWORD);
 
  public:
   static PDH_STATUS PdhAddCounter(HQUERY, LPCSTR, DWORD, HCOUNTER*);
@@ -56,6 +57,7 @@
   static PDH_STATUS PdhRemoveCounter(HCOUNTER);
   static PDH_STATUS PdhLookupPerfNameByIndex(LPCSTR, DWORD, LPSTR, LPDWORD);
   static PDH_STATUS PdhMakeCounterPath(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
+  static PDH_STATUS PdhExpandWildCardPath(LPCSTR, LPCSTR, PZZSTR, LPDWORD, DWORD);
   static bool       PdhStatusFail(PDH_STATUS pdhStat);
   static bool       PdhAttach();
   static bool       PdhDetach();