1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "iphlp_interface.hpp"
  27 #include "logging/log.hpp"
  28 #include "memory/allocation.inline.hpp"
  29 #include "memory/resourceArea.hpp"
  30 #include "pdh_interface.hpp"
  31 #include "runtime/os_perf.hpp"
  32 #include "runtime/os.hpp"
  33 #include "utilities/macros.hpp"
  34 #include "vm_version_ext_x86.hpp"
  35 #include <math.h>
  36 #include <psapi.h>
  37 #include <TlHelp32.h>
  38 
  39 /*
  40  * Windows provides a vast plethora of performance objects and counters,
  41  * consumption of which is assisted using the Performance Data Helper (PDH) interface.
  42  * We import a selected few api entry points from PDH, see pdh_interface.hpp.
  43  *
  44  * The code located in this file is to a large extent an abstraction over much of the
  45  * plumbing needed to start consuming an object and/or counter of choice.
  46  *
  47  */
  48 
  49  /*
  50  * How to use:
  51  * 1. Create query
  52  * 2. Add counters to the query
  53  * 3. Collect the performance data using the query
  54  * 4. Display the performance data using the counters associated with the query
  55  * 5. Destroy query (counter destruction implied)
  56  */
  57 
  58 /*
  59  * Every PDH artifact, like processor, process, thread, memory, and so forth are
  60  * identified with an index that is always the same irrespective
  61  * of the localized version of the operating system or service pack installed.
  62  * INFO: Using PDH APIs Correctly in a Localized Language (Q287159)
  63  *   http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159
  64  *
  65  * To find the correct index for an object or counter, inspect the registry key / value:
  66  * [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter]
  67  *
  68  * some common PDH indexes
  69  */
  70 static const DWORD PDH_PROCESSOR_IDX = 238;
  71 static const DWORD PDH_PROCESSOR_TIME_IDX = 6;
  72 static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144;
  73 static const DWORD PDH_PROCESS_IDX = 230;
  74 static const DWORD PDH_ID_PROCESS_IDX = 784;
  75 static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146;
  76 static const DWORD PDH_SYSTEM_IDX = 2;
  77 
  78 /* useful pdh fmt's */
  79 static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s";
  80 static const size_t OBJECT_COUNTER_FMT_LEN = 2;
  81 static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s";
  82 static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4;
  83 static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s";
  84 static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5;
  85 
  86 static const char* process_image_name = NULL; // for example, "java" but could have another image name
  87 static char* pdh_IDProcess_counter_fmt = NULL;   // "\Process(java#%d)\ID Process" */
  88 
  89 // Need to limit how often we update a query to minimize the heisenberg effect.
  90 // (PDH behaves erratically if the counters are queried too often, especially counters that
  91 // store and use values from two consecutive updates, like cpu load.)
  92 static const int min_update_interval_millis = 500;
  93 
  94 /*
  95 * Structs for PDH queries.
  96 */
  97 typedef struct {
  98   HQUERY query;
  99   s8     lastUpdate; // Last time query was updated (current millis).
 100 } UpdateQueryS, *UpdateQueryP;
 101 
 102 
 103 typedef struct {
 104   UpdateQueryS query;
 105   HCOUNTER     counter;
 106   bool         initialized;
 107 } CounterQueryS, *CounterQueryP;
 108 
 109 typedef struct {
 110   UpdateQueryS query;
 111   HCOUNTER*    counters;
 112   int          noOfCounters;
 113   bool         initialized;
 114 } MultiCounterQueryS, *MultiCounterQueryP;
 115 
 116 typedef struct {
 117   MultiCounterQueryP queries;
 118   int                size;
 119   bool               initialized;
 120 } MultiCounterQuerySetS, *MultiCounterQuerySetP;
 121 
 122 typedef struct {
 123   MultiCounterQuerySetS set;
 124   int                   process_index;
 125 } ProcessQueryS, *ProcessQueryP;
 126 
 127 static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) {
 128   if (counter != NULL && *counter != NULL) {
 129     PdhDll::PdhRemoveCounter(*counter);
 130     *counter = NULL;
 131   }
 132   if (query != NULL && *query != NULL) {
 133     PdhDll::PdhCloseQuery(*query);
 134     *query = NULL;
 135   }
 136 }
 137 
 138 static CounterQueryP create_counter_query() {
 139   CounterQueryP const query = NEW_C_HEAP_OBJ(CounterQueryS, mtInternal);
 140   memset(query, 0, sizeof(CounterQueryS));
 141   return query;
 142 }
 143 
 144 static void destroy_counter_query(CounterQueryP query) {
 145   assert(query != NULL, "invariant");
 146   pdh_cleanup(&query->query.query, &query->counter);
 147   FREE_C_HEAP_OBJ(query);
 148 }
 149 
 150 static MultiCounterQueryP create_multi_counter_query() {
 151   MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal);
 152   memset(query, 0, sizeof(MultiCounterQueryS));
 153   return query;
 154 }
 155 
 156 static void destroy_counter_query(MultiCounterQueryP counter_query) {
 157   if (counter_query != NULL) {
 158     for (int i = 0; i < counter_query->noOfCounters; ++i) {
 159       pdh_cleanup(NULL, &counter_query->counters[i]);
 160     }
 161     FREE_C_HEAP_ARRAY(char, counter_query->counters);
 162     pdh_cleanup(&counter_query->query.query, NULL);
 163     FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query);
 164   }
 165 }
 166 
 167 static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) {
 168   for (int i = 0; i < counter_query_set->size; i++) {
 169     for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) {
 170       pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]);
 171     }
 172     FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters);
 173     pdh_cleanup(&counter_query_set->queries[i].query.query, NULL);
 174   }
 175   FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries);
 176 }
 177 
 178 static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) {
 179   destroy_multi_counter_query(counter_query_set);
 180   FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set);
 181 }
 182 
 183 static void destroy_counter_query(ProcessQueryP process_query) {
 184   destroy_multi_counter_query(&process_query->set);
 185   FREE_C_HEAP_OBJ(process_query);
 186 }
 187 
 188 static int open_query(HQUERY* query) {
 189   return PdhDll::PdhOpenQuery(NULL, 0, query);
 190 }
 191 
 192 template <typename QueryP>
 193 static int open_query(QueryP query) {
 194   return open_query(&query->query);
 195 }
 196 
 197 static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) {
 198   assert(query != NULL, "invariant");
 199   assert(!query->initialized, "invariant");
 200   assert(0 == query->noOfCounters, "invariant");
 201   assert(query->counters == NULL, "invariant");
 202   query->counters = NEW_C_HEAP_ARRAY(HCOUNTER, nofCounters, mtInternal);
 203   if (query->counters == NULL) {
 204     return OS_ERR;
 205   }
 206   memset(query->counters, 0, nofCounters * sizeof(HCOUNTER));
 207   query->noOfCounters = (int)nofCounters;
 208   return OS_OK;
 209 }
 210 
 211 static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) {
 212   assert(query_set != NULL, "invariant");
 213   assert(!query_set->initialized, "invariant");
 214   for (int i = 0; i < query_set->size; ++i) {
 215     if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) {
 216       return OS_ERR;
 217     }
 218   }
 219   return OS_OK;
 220 }
 221 
 222 static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) {
 223   assert(process_query != NULL, "invariant");
 224   return allocate_counters(&process_query->set, nofCounters);
 225 }
 226 
 227 static void deallocate_counters(MultiCounterQueryP query) {
 228   if (query->counters != NULL) {
 229     FREE_C_HEAP_ARRAY(char, query->counters);
 230     query->counters = NULL;
 231     query->noOfCounters = 0;
 232   }
 233 }
 234 
 235 static OSReturn add_counter(UpdateQueryP query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 236   assert(query != NULL, "invariant");
 237   assert(counter != NULL, "invariant");
 238   assert(path != NULL, "invariant");
 239   if (query->query == NULL) {
 240     if (open_query(query) != ERROR_SUCCESS) {
 241       return OS_ERR;
 242     }
 243   }
 244   assert(query->query != NULL, "invariant");
 245   PDH_STATUS status = PdhDll::PdhAddCounter(query->query, path, 0, counter);
 246   if (PDH_CSTATUS_NO_OBJECT == status || PDH_CSTATUS_NO_COUNTER == status) {
 247     return OS_ERR;
 248   }
 249   /*
 250   * According to the MSDN documentation, rate counters must be read twice:
 251   *
 252   * "Obtaining the value of rate counters such as Page faults/sec requires that
 253   *  PdhCollectQueryData be called twice, with a specific time interval between
 254   *  the two calls, before calling PdhGetFormattedCounterValue. Call Sleep to
 255   *  implement the waiting period between the two calls to PdhCollectQueryData."
 256   *
 257   *  Take the first sample here already to allow for the next "real" sample
 258   *  to succeed.
 259   */
 260   if (first_sample_on_init) {
 261     PdhDll::PdhCollectQueryData(query->query);
 262   }
 263   return OS_OK;
 264 }
 265 
 266 template <typename QueryP>
 267 static OSReturn add_counter(QueryP counter_query, HCOUNTER* counter, const char* path, bool first_sample_on_init) {
 268   assert(counter_query != NULL, "invariant");
 269   assert(counter != NULL, "invariant");
 270   assert(path != NULL, "invariant");
 271   return add_counter(&counter_query->query, counter, path, first_sample_on_init);
 272 }
 273 
 274 static OSReturn add_counter(CounterQueryP counter_query, const char* path, bool first_sample_on_init) {
 275   if (add_counter(counter_query, &counter_query->counter, path, first_sample_on_init) != OS_OK) {
 276     // performance counter might be disabled in the registry
 277     return OS_ERR;
 278   }
 279   counter_query->initialized = true;
 280   return OS_OK;
 281 }
 282 
 283 static OSReturn add_process_counter(MultiCounterQueryP query, int slot_index, const char* path, bool first_sample_on_init) {
 284   assert(query != NULL, "invariant");
 285   assert(slot_index < query->noOfCounters, "invariant");
 286   assert(query->counters[slot_index] == NULL, "invariant");
 287   const OSReturn ret = add_counter(query, &query->counters[slot_index], path, first_sample_on_init);
 288   if (OS_OK == ret) {
 289     if (slot_index + 1 == query->noOfCounters) {
 290       query->initialized = true;
 291     }
 292   }
 293   return ret;
 294 }
 295 
 296 static int collect_query_data(UpdateQueryP update_query) {
 297   assert(update_query != NULL, "invariant");
 298   const s8 now = os::javaTimeMillis();
 299   if (now - update_query->lastUpdate > min_update_interval_millis) {
 300     if (PdhDll::PdhCollectQueryData(update_query->query) != ERROR_SUCCESS) {
 301       return OS_ERR;
 302     }
 303     update_query->lastUpdate = now;
 304   }
 305   return OS_OK;
 306 }
 307 
 308 template <typename Query>
 309 static int collect_query_data(Query* counter_query) {
 310   assert(counter_query != NULL, "invariant");
 311   return collect_query_data(&counter_query->query);
 312 }
 313 
 314 static int formatted_counter_value(HCOUNTER counter, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
 315   assert(value != NULL, "invariant");
 316   if (PdhDll::PdhGetFormattedCounterValue(counter, format, NULL, value) != ERROR_SUCCESS) {
 317     return OS_ERR;
 318   }
 319   return OS_OK;
 320 }
 321 
 322 /*
 323 * Working against the Process object and it's related counters is inherently problematic
 324 * when using the PDH API:
 325 *
 326 * Using PDH, a process is not primarily identified by the process id,
 327 * but with a sequential number, for example \Process(java#0), \Process(java#1), ...
 328 * The really bad part is that this list is reset as soon as a process exits:
 329 * If \Process(java#1) exits, \Process(java#3) now becomes \Process(java#2) etc.
 330 *
 331 * The PDH api requires a process identifier to be submitted when registering
 332 * a query, but as soon as the list resets, the query is invalidated (since the name changed).
 333 *
 334 * Solution:
 335 * The #number identifier for a Process query can only decrease after process creation.
 336 *
 337 * We therefore create an array of counter queries for all process object instances
 338 * up to and including ourselves:
 339 *
 340 * Ex. we come in as third process instance (java#2), we then create and register
 341 * queries for the following Process object instances:
 342 * java#0, java#1, java#2
 343 *
 344 * current_query_index_for_process() keeps track of the current "correct" query
 345 * (in order to keep this index valid when the list resets from underneath,
 346 * ensure to call current_query_index_for_process() before every query involving
 347 * Process object instance data).
 348 *
 349 * if unable to query, returns OS_ERR(-1)
 350 */
 351 static int current_query_index_for_process() {
 352   assert(process_image_name != NULL, "invariant");
 353   assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
 354   HQUERY tmpQuery = NULL;
 355   if (open_query(&tmpQuery) != ERROR_SUCCESS) {
 356     return OS_ERR;
 357   }
 358   char counter[512];
 359   HCOUNTER handle_counter = NULL;
 360   // iterate over all instance indexes and try to find our own pid
 361   for (int index = 0; index < max_intx; index++) {
 362     jio_snprintf(counter, sizeof(counter) - 1, pdh_IDProcess_counter_fmt, index);
 363     assert(strlen(counter) < sizeof(counter), "invariant");
 364     if (PdhDll::PdhAddCounter(tmpQuery, counter, 0, &handle_counter) != ERROR_SUCCESS) {
 365       pdh_cleanup(&tmpQuery, &handle_counter);
 366       return OS_ERR;
 367     }
 368     const PDH_STATUS res = PdhDll::PdhCollectQueryData(tmpQuery);
 369     if (res == PDH_INVALID_HANDLE || res == PDH_NO_DATA) {
 370       pdh_cleanup(&tmpQuery, &handle_counter);
 371       return OS_ERR;
 372     } else {
 373       PDH_FMT_COUNTERVALUE counter_value;
 374       formatted_counter_value(handle_counter, PDH_FMT_LONG, &counter_value);
 375       pdh_cleanup(NULL, &handle_counter);
 376       if ((LONG)os::current_process_id() == counter_value.longValue) {
 377         pdh_cleanup(&tmpQuery, NULL);
 378         return index;
 379       }
 380     }
 381   }
 382   pdh_cleanup(&tmpQuery, NULL);
 383   return OS_ERR;
 384 }
 385 
 386 static ProcessQueryP create_process_query() {
 387   const int current_process_idx = current_query_index_for_process();
 388   if (OS_ERR == current_process_idx) {
 389     return NULL;
 390   }
 391   ProcessQueryP const process_query = NEW_C_HEAP_OBJ(ProcessQueryS, mtInternal);
 392   memset(process_query, 0, sizeof(ProcessQueryS));
 393   process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal);
 394   memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1));
 395   process_query->process_index = current_process_idx;
 396   process_query->set.size = current_process_idx + 1;
 397   assert(process_query->set.size > process_query->process_index, "invariant");
 398   return process_query;
 399 }
 400 
 401 static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) {
 402   assert(process_query != NULL, "invariant");
 403   assert(process_query->process_index < process_query->set.size, "invariant");
 404   return &process_query->set.queries[process_query->process_index];
 405 }
 406 
 407 static void clear_multi_counter(MultiCounterQueryP query) {
 408   for (int i = 0; i < query->noOfCounters; ++i) {
 409     pdh_cleanup(NULL, &query->counters[i]);
 410   }
 411   pdh_cleanup(&query->query.query, NULL);
 412   query->initialized = false;
 413 }
 414 
 415 static int ensure_valid_process_query_index(ProcessQueryP process_query) {
 416   assert(process_query != NULL, "invariant");
 417   const int previous_process_idx = process_query->process_index;
 418   if (previous_process_idx == 0) {
 419     return previous_process_idx;
 420   }
 421   const int current_process_idx = current_query_index_for_process();
 422   if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx ||
 423     current_process_idx >= process_query->set.size) {
 424     return previous_process_idx;
 425   }
 426 
 427   assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!");
 428   while (current_process_idx < process_query->set.size - 1) {
 429     const int new_size = --process_query->set.size;
 430     clear_multi_counter(&process_query->set.queries[new_size]);
 431   }
 432   assert(current_process_idx < process_query->set.size, "invariant");
 433   process_query->process_index = current_process_idx;
 434   return current_process_idx;
 435 }
 436 
 437 static MultiCounterQueryP current_process_query(ProcessQueryP process_query) {
 438   assert(process_query != NULL, "invariant");
 439   const int current_process_idx = ensure_valid_process_query_index(process_query);
 440   assert(current_process_idx == process_query->process_index, "invariant");
 441   assert(current_process_idx < process_query->set.size, "invariant");
 442   return &process_query->set.queries[current_process_idx];
 443 }
 444 
 445 static int collect_process_query_data(ProcessQueryP process_query) {
 446   assert(process_query != NULL, "invariant");
 447   return collect_query_data(current_process_query(process_query));
 448 }
 449 
 450 static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) {
 451   MultiCounterQueryP const current_query = current_process_counter_query(process_query);
 452   assert(current_query != NULL, "invariant");
 453   assert(slot_index < current_query->noOfCounters, "invariant");
 454   assert(current_query->counters[slot_index] != NULL, "invariant");
 455   return formatted_counter_value(current_query->counters[slot_index], format, value);
 456 }
 457 
 458 /*
 459  * Construct a fully qualified PDH path
 460  *
 461  * @param objectName   a PDH Object string representation(required)
 462  * @param counterName  a PDH Counter string representation(required)
 463  * @param imageName    a process image name string, ex. "java" (opt)
 464  * @param instance     an instance string, ex. "0", "1", ... (opt)
 465  * @return             the fully qualified PDH path.
 466  *
 467  * Caller will need a ResourceMark.
 468  *
 469  * (PdhMakeCounterPath() seems buggy on concatenating instances, hence this function instead)
 470  */
 471 static const char* make_fully_qualified_counter_path(const char* object_name,
 472                                                      const char* counter_name,
 473                                                      const char* image_name = NULL,
 474                                                      const char* instance = NULL) {
 475   assert(object_name != NULL, "invariant");
 476   assert(counter_name != NULL, "invariant");
 477   size_t full_counter_path_len = strlen(object_name) + strlen(counter_name);
 478 
 479   char* full_counter_path;
 480   size_t jio_snprintf_result = 0;
 481   if (image_name) {
 482     /*
 483     * For paths using the "Process" Object.
 484     *
 485     * Examples:
 486     * form:   "\object_name(image_name#instance)\counter_name"
 487     * actual: "\Process(java#2)\ID Process"
 488     */
 489     full_counter_path_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
 490     full_counter_path_len += strlen(image_name);
 491     /*
 492     * image_name must be passed together with an associated
 493     * instance "number" ("0", "1", "2", ...).
 494     * This is required in order to create valid "Process" Object paths.
 495     *
 496     * Examples: "\Process(java#0)", \Process(java#1"), ...
 497     */
 498     assert(instance != NULL, "invariant");
 499     full_counter_path_len += strlen(instance);
 500     full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
 501     if (full_counter_path == NULL) {
 502       return NULL;
 503     }
 504     jio_snprintf_result = jio_snprintf(full_counter_path,
 505                                        full_counter_path_len + 1,
 506                                        PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
 507                                        object_name,
 508                                        image_name,
 509                                        instance,
 510                                        counter_name);
 511   } else {
 512     if (instance) {
 513       /*
 514       * For paths where the Object has multiple instances.
 515       *
 516       * Examples:
 517       * form:   "\object_name(instance)\counter_name"
 518       * actual: "\Processor(0)\% Privileged Time"
 519       */
 520       full_counter_path_len += strlen(instance);
 521       full_counter_path_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN;
 522     } else {
 523       /*
 524       * For "normal" paths.
 525       *
 526       * Examples:
 527       * form:   "\object_name\counter_name"
 528       * actual: "\Memory\Available Mbytes"
 529       */
 530       full_counter_path_len += OBJECT_COUNTER_FMT_LEN;
 531     }
 532     full_counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, full_counter_path_len + 1);
 533     if (full_counter_path == NULL) {
 534       return NULL;
 535     }
 536     if (instance) {
 537       jio_snprintf_result = jio_snprintf(full_counter_path,
 538                                          full_counter_path_len + 1,
 539                                          OBJECT_WITH_INSTANCES_COUNTER_FMT,
 540                                          object_name,
 541                                          instance,
 542                                          counter_name);
 543     } else {
 544       jio_snprintf_result = jio_snprintf(full_counter_path,
 545                                          full_counter_path_len + 1,
 546                                          OBJECT_COUNTER_FMT,
 547                                          object_name,
 548                                          counter_name);
 549     }
 550   }
 551   assert(full_counter_path_len == jio_snprintf_result, "invariant");
 552   return full_counter_path;
 553 }
 554 
 555 static void log_invalid_pdh_index(DWORD index) {
 556   log_warning(os)("Unable to resolve PDH index: (%ld)", index);
 557   log_warning(os)("Please check the registry if this performance object/counter is disabled");
 558 }
 559 
 560 static bool is_valid_pdh_index(DWORD index) {
 561   DWORD dummy = 0;
 562   if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &dummy) != PDH_MORE_DATA) {
 563     log_invalid_pdh_index(index);
 564     return false;
 565   }
 566   return true;
 567 }
 568 
 569 /*
 570  * Maps an index to a resource area allocated string for the localized PDH artifact.
 571  *
 572  * Caller will need a ResourceMark.
 573  *
 574  * @param index    the counter index as specified in the registry
 575  * @param ppBuffer pointer to a char*
 576  * @return         OS_OK if successful, OS_ERR on failure.
 577  */
 578 static OSReturn lookup_name_by_index(DWORD index, char** p_string) {
 579   assert(p_string != NULL, "invariant");
 580   if (!is_valid_pdh_index(index)) {
 581     return OS_ERR;
 582   }
 583   // determine size needed
 584   DWORD size = 0;
 585   PDH_STATUS status = PdhDll::PdhLookupPerfNameByIndex(NULL, index, NULL, &size);
 586   assert(status == PDH_MORE_DATA, "invariant");
 587   *p_string = NEW_RESOURCE_ARRAY_RETURN_NULL(char, size);
 588   if (*p_string== NULL) {
 589     return OS_ERR;
 590   }
 591   if (PdhDll::PdhLookupPerfNameByIndex(NULL, index, *p_string, &size) != ERROR_SUCCESS) {
 592     return OS_ERR;
 593   }
 594   if (0 == size || *p_string == NULL) {
 595     return OS_ERR;
 596   }
 597   // windows vista does not null-terminate the string (although the docs says it will)
 598   (*p_string)[size - 1] = '\0';
 599   return OS_OK;
 600 }
 601 
 602 static const char* copy_string_to_c_heap(const char* string) {
 603   assert(string != NULL, "invariant");
 604   const size_t len = strlen(string);
 605   char* const cheap_allocated_string = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
 606   if (NULL == cheap_allocated_string) {
 607     return NULL;
 608   }
 609   strncpy(cheap_allocated_string, string, len + 1);
 610   return cheap_allocated_string;
 611 }
 612 
 613 /*
 614 * Maps an index to a resource area allocated string for the localized PDH artifact.
 615 *
 616 * Caller will need a ResourceMark.
 617 *
 618 * @param index    the counter index as specified in the registry
 619 * @return         localized pdh artifact string if successful, NULL on failure.
 620 */
 621 static const char* pdh_localized_artifact(DWORD pdh_artifact_index) {
 622   char* pdh_localized_artifact_string = NULL;
 623   // get localized name from pdh artifact index
 624   if (lookup_name_by_index(pdh_artifact_index, &pdh_localized_artifact_string) != OS_OK) {
 625     return NULL;
 626   }
 627   return pdh_localized_artifact_string;
 628 }
 629 
 630 /*
 631  * Returns the PDH string identifying the current process image name.
 632  * Use this prefix when getting counters from the PDH process object
 633  * representing your process.
 634  * Ex. "Process(java#0)\Virtual Bytes" - where "java" is the PDH process
 635  * image description.
 636  *
 637  * Caller needs ResourceMark.
 638  *
 639  * @return the process image description. NULL if the call failed.
 640 */
 641 static const char* pdh_process_image_name() {
 642   char* module_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, MAX_PATH);
 643   if (NULL == module_name) {
 644     return NULL;
 645   }
 646   // Find our module name and use it to extract the image name used by PDH
 647   DWORD getmfn_return = GetModuleFileName(NULL, module_name, MAX_PATH);
 648   if (getmfn_return >= MAX_PATH || 0 == getmfn_return) {
 649     return NULL;
 650   }
 651   if (os::get_last_error() == ERROR_INSUFFICIENT_BUFFER) {
 652     return NULL;
 653   }
 654   char* process_image_name = strrchr(module_name, '\\'); //drop path
 655   process_image_name++;                                  //skip slash
 656   char* dot_pos = strrchr(process_image_name, '.');      //drop .exe
 657   dot_pos[0] = '\0';
 658   return process_image_name;
 659 }
 660 
 661 static void deallocate_pdh_constants() {
 662   if (process_image_name != NULL) {
 663     FREE_C_HEAP_ARRAY(char, process_image_name);
 664     process_image_name = NULL;
 665   }
 666   if (pdh_IDProcess_counter_fmt != NULL) {
 667     FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt);
 668     pdh_IDProcess_counter_fmt = NULL;
 669   }
 670 }
 671 
 672 static int allocate_pdh_constants() {
 673   assert(process_image_name == NULL, "invariant");
 674   const char* pdh_image_name = pdh_process_image_name();
 675   if (pdh_image_name == NULL) {
 676     return OS_ERR;
 677   }
 678   process_image_name = copy_string_to_c_heap(pdh_image_name);
 679 
 680   const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX);
 681   if (pdh_localized_process_object == NULL) {
 682     return OS_ERR;
 683   }
 684 
 685   const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX);
 686   if (pdh_localized_IDProcess_counter == NULL) {
 687     return OS_ERR;
 688   }
 689 
 690   size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name);
 691   pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object);
 692   pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter);
 693   pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN;
 694   pdh_IDProcess_counter_fmt_len += 2; // "%d"
 695 
 696   assert(pdh_IDProcess_counter_fmt == NULL, "invariant");
 697   pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal);
 698   if (pdh_IDProcess_counter_fmt == NULL) {
 699     return OS_ERR;
 700   }
 701 
 702   /* "\Process(java#%d)\ID Process" */
 703   const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt,
 704                                   pdh_IDProcess_counter_fmt_len + 1,
 705                                   PROCESS_OBJECT_INSTANCE_COUNTER_FMT,
 706                                   pdh_localized_process_object,
 707                                   process_image_name,
 708                                   "%d",
 709                                   pdh_localized_IDProcess_counter);
 710 
 711   assert(pdh_IDProcess_counter_fmt != NULL, "invariant");
 712   assert(len == pdh_IDProcess_counter_fmt_len, "invariant");
 713   return OS_OK;
 714 }
 715 
 716 /*
 717  * Enuerate the Processor PDH object and returns a buffer containing the enumerated instances.
 718  * Caller needs ResourceMark;
 719  *
 720  * @return  buffer if successful, NULL on failure.
 721 */
 722 static const char* enumerate_cpu_instances() {
 723   char* processor; //'Processor' == PDH_PROCESSOR_IDX
 724   if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
 725     return NULL;
 726   }
 727   DWORD c_size = 0;
 728   DWORD i_size = 0;
 729   // enumerate all processors.
 730   PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
 731                                                   NULL, // local machine
 732                                                   processor, // object to enumerate
 733                                                   NULL,
 734                                                   &c_size,
 735                                                   NULL, // instance buffer is NULL and
 736                                                   &i_size,  // pass 0 length in order to get the required size
 737                                                   PERF_DETAIL_WIZARD, // counter detail level
 738                                                   0);
 739   if (PdhDll::PdhStatusFail((pdhStat))) {
 740     return NULL;
 741   }
 742   char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size);
 743   if (instances == NULL) {
 744     return NULL;
 745   }
 746   c_size = 0;
 747   pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved
 748                                        NULL, // local machine
 749                                        processor, // object to enumerate
 750                                        NULL,
 751                                        &c_size,
 752                                        instances, // now instance buffer is allocated to be filled in
 753                                        &i_size, // and the required size is known
 754                                        PERF_DETAIL_WIZARD, // counter detail level
 755                                        0);
 756   if (PdhDll::PdhStatusFail((pdhStat))) {
 757     return NULL;
 758   }
 759   return instances;
 760 }
 761 
 762 static int count_logical_cpus(const char* instances) {
 763   assert(instances != NULL, "invariant");
 764   // count logical instances.
 765   DWORD count;
 766   char* tmp;
 767   for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++);
 768   // PDH reports an instance for each logical processor plus an instance for the total (_Total)
 769   assert(count == os::processor_count() + 1, "invalid enumeration!");
 770   return count - 1;
 771 }
 772 
 773 static int number_of_logical_cpus() {
 774   static int numberOfCPUS = 0;
 775   if (numberOfCPUS == 0) {
 776     const char* instances = enumerate_cpu_instances();
 777     if (instances == NULL) {
 778       return OS_ERR;
 779     }
 780     numberOfCPUS = count_logical_cpus(instances);
 781   }
 782   return numberOfCPUS;
 783 }
 784 
 785 static double cpu_factor() {
 786   static DWORD  numCpus = 0;
 787   static double cpuFactor = .0;
 788   if (numCpus == 0) {
 789     numCpus = number_of_logical_cpus();
 790     assert(os::processor_count() <= (int)numCpus, "invariant");
 791     cpuFactor = numCpus * 100;
 792   }
 793   return cpuFactor;
 794 }
 795 
 796 static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) {
 797   log_warning(os)("Unable to register PDH query for \"%s\"", full_counter_name);
 798   log_warning(os)("Please check the registry if this performance object/counter is disabled");
 799 }
 800 
 801 static int initialize_cpu_query_counters(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
 802   assert(cpu_query != NULL, "invariant");
 803   assert(cpu_query->counters != NULL, "invariant");
 804   char* processor; //'Processor' == PDH_PROCESSOR_IDX
 805   if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) {
 806     return OS_ERR;
 807   }
 808   char* counter_name = NULL;
 809   if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) {
 810     return OS_ERR;
 811   }
 812   if (cpu_query->query.query == NULL) {
 813     if (open_query(cpu_query)) {
 814       return OS_ERR;
 815     }
 816   }
 817   assert(cpu_query->query.query != NULL, "invariant");
 818   size_t counter_len = strlen(processor);
 819   counter_len += strlen(counter_name);
 820   counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s"
 821 
 822   DWORD index;
 823   char* tmp;
 824   const char* instances = enumerate_cpu_instances();
 825   for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) {
 826     const size_t tmp_len = strlen(tmp);
 827     char* counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, counter_len + tmp_len + 1);
 828     if (counter_path == NULL) {
 829       return OS_ERR;
 830     }
 831     const size_t jio_snprintf_result = jio_snprintf(counter_path,
 832                                                     counter_len + tmp_len + 1,
 833                                                     OBJECT_WITH_INSTANCES_COUNTER_FMT,
 834                                                     processor,
 835                                                     tmp, // instance "0", "1", .."_Total"
 836                                                     counter_name);
 837     assert(counter_len + tmp_len == jio_snprintf_result, "invariant");
 838     if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) {
 839       // performance counter is disabled in registry and not accessible via PerfLib
 840       log_error_message_on_no_PDH_artifact(counter_path);
 841       // return OS_OK to have the system continue to run without the missing counter
 842       return OS_OK;
 843     }
 844   }
 845   cpu_query->initialized = true;
 846   // Query once to initialize the counters which require at least two samples
 847   // (like the % CPU usage) to calculate correctly.
 848   collect_query_data(cpu_query);
 849   return OS_OK;
 850 }
 851 
 852 static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) {
 853   assert(cpu_query != NULL, "invariant");
 854   assert(!cpu_query->initialized, "invariant");
 855   const int logical_cpu_count = number_of_logical_cpus();
 856   assert(logical_cpu_count >= os::processor_count(), "invariant");
 857   // we also add another counter for instance "_Total"
 858   if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) {
 859     return OS_ERR;
 860   }
 861   assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant");
 862   return initialize_cpu_query_counters(cpu_query, pdh_counter_idx);
 863 }
 864 
 865 static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) {
 866   char* localized_process_object;
 867   if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) {
 868     return OS_ERR;
 869   }
 870   assert(localized_process_object != NULL, "invariant");
 871   char* localized_counter_name;
 872   if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) {
 873     return OS_ERR;
 874   }
 875   assert(localized_counter_name != NULL, "invariant");
 876   for (int i = 0; i < process_query->set.size; ++i) {
 877     char instanceIndexBuffer[32];
 878     const char* counter_path = make_fully_qualified_counter_path(localized_process_object,
 879                                                                  localized_counter_name,
 880                                                                  process_image_name,
 881                                                                  itoa(i, instanceIndexBuffer, 10));
 882     if (counter_path == NULL) {
 883       return OS_ERR;
 884     }
 885     MultiCounterQueryP const query = &process_query->set.queries[i];
 886     if (add_process_counter(query, slot_index, counter_path, true)) {
 887       return OS_ERR;
 888     }
 889   }
 890   return OS_OK;
 891 }
 892 
 893 static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) {
 894   if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) {
 895     return NULL;
 896   }
 897   CounterQueryP const query = create_counter_query();
 898   const char* object = pdh_localized_artifact(pdh_object_idx);
 899   assert(object != NULL, "invariant");
 900   const char* counter = pdh_localized_artifact(pdh_counter_idx);
 901   assert(counter != NULL, "invariant");
 902   const char* full_counter_path = make_fully_qualified_counter_path(object, counter);
 903   assert(full_counter_path != NULL, "invariant");
 904   add_counter(query, full_counter_path, true);
 905   return query;
 906 }
 907 
 908 static void deallocate() {
 909   deallocate_pdh_constants();
 910   PdhDll::PdhDetach();
 911 }
 912 
 913 static LONG critical_section = 0;
 914 static LONG reference_count = 0;
 915 static bool pdh_initialized = false;
 916 
 917 static void on_initialization_failure() {
 918   // still holder of critical section
 919   deallocate();
 920   InterlockedExchangeAdd(&reference_count, -1);
 921 }
 922 
 923 static OSReturn initialize() {
 924   ResourceMark rm;
 925   if (!PdhDll::PdhAttach()) {
 926     return OS_ERR;
 927   }
 928   if (allocate_pdh_constants() != OS_OK) {
 929     on_initialization_failure();
 930     return OS_ERR;
 931   }
 932   return OS_OK;
 933 }
 934 
 935 /*
 936 * Helper to initialize the PDH library, function pointers, constants and counters.
 937 *
 938 * Reference counting allows for unloading of pdh.dll granted all sessions use the pair:
 939 *
 940 *   pdh_acquire();
 941 *   pdh_release();
 942 *
 943 * @return  OS_OK if successful, OS_ERR on failure.
 944 */
 945 static bool pdh_acquire() {
 946   while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
 947   InterlockedExchangeAdd(&reference_count, 1);
 948   if (pdh_initialized) {
 949     return true;
 950   }
 951   const OSReturn ret = initialize();
 952   if (OS_OK == ret) {
 953     pdh_initialized = true;
 954   }
 955   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 956   return ret == OS_OK;
 957 }
 958 
 959 static void pdh_release() {
 960   while (InterlockedCompareExchange(&critical_section, 1, 0) == 1);
 961   const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1);
 962   if (1 == prev_ref_count) {
 963     deallocate();
 964     pdh_initialized = false;
 965   }
 966   while (InterlockedCompareExchange(&critical_section, 0, 1) == 0);
 967 }
 968 
 969 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
 970   friend class CPUPerformanceInterface;
 971  private:
 972   CounterQueryP _context_switches;
 973   ProcessQueryP _process_cpu_load;
 974   MultiCounterQueryP _machine_cpu_load;
 975 
 976   int cpu_load(int which_logical_cpu, double* cpu_load);
 977   int context_switch_rate(double* rate);
 978   int cpu_load_total_process(double* cpu_load);
 979   int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad);
 980   CPUPerformance();
 981   ~CPUPerformance();
 982   bool initialize();
 983 };
 984 
 985 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
 986   friend class SystemProcessInterface;
 987  private:
 988   class ProcessIterator : public CHeapObj<mtInternal> {
 989     friend class SystemProcessInterface::SystemProcesses;
 990    private:
 991     HANDLE         _hProcessSnap;
 992     PROCESSENTRY32 _pe32;
 993     BOOL           _valid;
 994     char           _exePath[MAX_PATH];
 995     ProcessIterator();
 996     ~ProcessIterator();
 997     bool initialize();
 998 
 999     int current(SystemProcess* const process_info);
1000     int next_process();
1001     bool is_valid() const { return _valid != FALSE; }
1002     char* allocate_string(const char* str) const;
1003     int snapshot();
1004   };
1005 
1006   ProcessIterator* _iterator;
1007   SystemProcesses();
1008   ~SystemProcesses();
1009   bool initialize();
1010 
1011   // information about system processes
1012   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
1013 };
1014 
1015 CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
1016 
1017 bool CPUPerformanceInterface::CPUPerformance::initialize() {
1018   if (!pdh_acquire()) {
1019     return true;
1020   }
1021   _context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX);
1022   _process_cpu_load = create_process_query();
1023   if (_process_cpu_load == NULL) {
1024     return true;
1025   }
1026   if (allocate_counters(_process_cpu_load, 2) != OS_OK) {
1027     return true;
1028   }
1029   if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) {
1030     return true;
1031   }
1032   if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) {
1033     return true;
1034   }
1035   _process_cpu_load->set.initialized = true;
1036   _machine_cpu_load = create_multi_counter_query();
1037   if (_machine_cpu_load == NULL) {
1038     return true;
1039   }
1040   initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX);
1041   return true;
1042 }
1043 
1044 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
1045   if (_context_switches != NULL) {
1046     destroy_counter_query(_context_switches);
1047     _context_switches = NULL;
1048   }
1049   if (_process_cpu_load != NULL) {
1050     destroy_counter_query(_process_cpu_load);
1051     _process_cpu_load = NULL;
1052   }
1053   if (_machine_cpu_load != NULL) {
1054     destroy_counter_query(_machine_cpu_load);
1055     _machine_cpu_load = NULL;
1056   }
1057   pdh_release();
1058 }
1059 
1060 CPUPerformanceInterface::CPUPerformanceInterface() {
1061   _impl = NULL;
1062 }
1063 
1064 bool CPUPerformanceInterface::initialize() {
1065   _impl = new CPUPerformanceInterface::CPUPerformance();
1066   return _impl != NULL && _impl->initialize();
1067 }
1068 
1069 CPUPerformanceInterface::~CPUPerformanceInterface() {
1070   if (_impl != NULL) {
1071     delete _impl;
1072   }
1073 }
1074 
1075 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
1076   return _impl->cpu_load(which_logical_cpu, cpu_load);
1077 }
1078 
1079 int CPUPerformanceInterface::context_switch_rate(double* rate) const {
1080   return _impl->context_switch_rate(rate);
1081 }
1082 
1083 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
1084   return _impl->cpu_load_total_process(cpu_load);
1085 }
1086 
1087 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad,
1088                                                double* pjvmKernelLoad,
1089                                                double* psystemTotalLoad) const {
1090   return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
1091 }
1092 
1093 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
1094   *cpu_load = .0;
1095   if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) {
1096     return OS_ERR;
1097   }
1098   assert(_machine_cpu_load != NULL, "invariant");
1099   assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant");
1100 
1101   if (collect_query_data(_machine_cpu_load)) {
1102     return OS_ERR;
1103   }
1104   // -1 is total (all cpus)
1105   const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu;
1106   PDH_FMT_COUNTERVALUE counter_value;
1107   formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value);
1108   *cpu_load = counter_value.doubleValue / 100;
1109   return OS_OK;
1110 }
1111 
1112 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
1113   *cpu_load = .0;
1114   if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
1115     return OS_ERR;
1116   }
1117   assert(_process_cpu_load != NULL, "invariant");
1118   if (collect_process_query_data(_process_cpu_load)) {
1119     return OS_ERR;
1120   }
1121   PDH_FMT_COUNTERVALUE counter_value;
1122   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1123     return OS_ERR;
1124   }
1125   double process_load = counter_value.doubleValue / cpu_factor();
1126   process_load = MIN2<double>(1, process_load);
1127   process_load = MAX2<double>(0, process_load);
1128   *cpu_load = process_load;
1129   return OS_OK;
1130 }
1131 
1132 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad,
1133                                                                double* pjvmKernelLoad,
1134                                                                double* psystemTotalLoad) {
1135   assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!");
1136   assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!");
1137   assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!");
1138   *pjvmUserLoad = .0;
1139   *pjvmKernelLoad = .0;
1140   *psystemTotalLoad = .0;
1141 
1142   if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) {
1143     return OS_ERR;
1144   }
1145   assert(_process_cpu_load != NULL, "invariant");
1146   if (collect_process_query_data(_process_cpu_load)) {
1147     return OS_ERR;
1148   }
1149   double process_load = .0;
1150   PDH_FMT_COUNTERVALUE counter_value;
1151   // Read  PDH_PROCESSOR_TIME_IDX
1152   if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1153     return OS_ERR;
1154   }
1155   process_load = counter_value.doubleValue / cpu_factor();
1156   process_load = MIN2<double>(1, process_load);
1157   process_load = MAX2<double>(0, process_load);
1158   // Read PDH_PRIV_PROCESSOR_TIME_IDX
1159   if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) {
1160     return OS_ERR;
1161   }
1162   double kernel_load = counter_value.doubleValue / cpu_factor();
1163   kernel_load = MIN2<double>(1, kernel_load);
1164   kernel_load = MAX2<double>(0, kernel_load);
1165   *pjvmKernelLoad = kernel_load;
1166 
1167   double user_load = process_load - kernel_load;
1168   user_load = MIN2<double>(1, user_load);
1169   user_load = MAX2<double>(0, user_load);
1170   *pjvmUserLoad = user_load;
1171 
1172   if (collect_query_data(_machine_cpu_load)) {
1173     return OS_ERR;
1174   }
1175   if (formatted_counter_value(_machine_cpu_load->counters[_machine_cpu_load->noOfCounters - 1], PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
1176     return OS_ERR;
1177   }
1178   double machine_load = counter_value.doubleValue / 100;
1179   assert(machine_load >= 0, "machine_load is negative!");
1180   // clamp at user+system and 1.0
1181   if (*pjvmKernelLoad + *pjvmUserLoad > machine_load) {
1182     machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0);
1183   }
1184   *psystemTotalLoad = machine_load;
1185   return OS_OK;
1186 }
1187 
1188 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
1189   assert(rate != NULL, "invariant");
1190   *rate = .0;
1191   if (_context_switches == NULL || !_context_switches->initialized) {
1192     return OS_ERR;
1193   }
1194   assert(_context_switches != NULL, "invariant");
1195   if (collect_query_data(_context_switches) != OS_OK) {
1196     return OS_ERR;
1197   }
1198   PDH_FMT_COUNTERVALUE counter_value;
1199   if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) {
1200     return OS_ERR;
1201   }
1202   *rate = counter_value.doubleValue;
1203   return OS_OK;
1204 }
1205 
1206 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
1207   _hProcessSnap = INVALID_HANDLE_VALUE;
1208   _valid = FALSE;
1209   _pe32.dwSize = sizeof(PROCESSENTRY32);
1210 }
1211 
1212 bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
1213   return true;
1214 }
1215 
1216 int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() {
1217   // take snapshot of all process in the system
1218   _hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1219   if (_hProcessSnap == INVALID_HANDLE_VALUE) {
1220     return OS_ERR;
1221   }
1222   // step to first process
1223   _valid = Process32First(_hProcessSnap, &_pe32);
1224   return is_valid() ? OS_OK : OS_ERR;
1225 }
1226 
1227 SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
1228   if (_hProcessSnap != INVALID_HANDLE_VALUE) {
1229     CloseHandle(_hProcessSnap);
1230   }
1231 }
1232 
1233 int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
1234   assert(is_valid(), "no current process to be fetched!");
1235   assert(process_info != NULL, "process_info is NULL!");
1236   char* exePath = NULL;
1237   HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID);
1238   if (hProcess != NULL) {
1239     HMODULE hMod;
1240     DWORD cbNeeded;
1241     if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) {
1242       if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) {
1243         exePath = _exePath;
1244       }
1245     }
1246     CloseHandle (hProcess);
1247   }
1248   process_info->set_pid((int)_pe32.th32ProcessID);
1249   process_info->set_name(allocate_string(_pe32.szExeFile));
1250   process_info->set_path(allocate_string(exePath));
1251   return OS_OK;
1252 }
1253 
1254 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
1255   if (str != NULL) {
1256     return os::strdup_check_oom(str, mtInternal);
1257   }
1258   return NULL;
1259 }
1260 
1261 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
1262   _valid = Process32Next(_hProcessSnap, &_pe32);
1263   return OS_OK;
1264 }
1265 
1266 SystemProcessInterface::SystemProcesses::SystemProcesses() {
1267   _iterator = NULL;
1268 }
1269 
1270 bool SystemProcessInterface::SystemProcesses::initialize() {
1271   _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
1272   return _iterator != NULL && _iterator->initialize();
1273 }
1274 
1275 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
1276   if (_iterator != NULL) {
1277     delete _iterator;
1278     _iterator = NULL;
1279   }
1280 }
1281 
1282 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes,
1283                                                               int* no_of_sys_processes) const {
1284   assert(system_processes != NULL, "system_processes pointer is NULL!");
1285   assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
1286   assert(_iterator != NULL, "iterator is NULL!");
1287 
1288   // initialize pointers
1289   *no_of_sys_processes = 0;
1290   *system_processes = NULL;
1291 
1292   // take process snapshot
1293   if (_iterator->snapshot() != OS_OK) {
1294     return OS_ERR;
1295   }
1296 
1297   while (_iterator->is_valid()) {
1298     SystemProcess* tmp = new SystemProcess();
1299     _iterator->current(tmp);
1300 
1301     //if already existing head
1302     if (*system_processes != NULL) {
1303       //move "first to second"
1304       tmp->set_next(*system_processes);
1305     }
1306     // new head
1307     *system_processes = tmp;
1308     // increment
1309     (*no_of_sys_processes)++;
1310     // step forward
1311     _iterator->next_process();
1312   }
1313   return OS_OK;
1314 }
1315 
1316 int SystemProcessInterface::system_processes(SystemProcess** system_procs,
1317                                              int* no_of_sys_processes) const {
1318   return _impl->system_processes(system_procs, no_of_sys_processes);
1319 }
1320 
1321 SystemProcessInterface::SystemProcessInterface() {
1322   _impl = NULL;
1323 }
1324 
1325 bool SystemProcessInterface::initialize() {
1326   _impl = new SystemProcessInterface::SystemProcesses();
1327   return _impl != NULL && _impl->initialize();
1328 }
1329 
1330 SystemProcessInterface::~SystemProcessInterface() {
1331   if (_impl != NULL) {
1332     delete _impl;
1333   }
1334 }
1335 
1336 CPUInformationInterface::CPUInformationInterface() {
1337   _cpu_info = NULL;
1338 }
1339 
1340 bool CPUInformationInterface::initialize() {
1341   _cpu_info = new CPUInformation();
1342   if (NULL == _cpu_info) {
1343     return false;
1344   }
1345   _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
1346   _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
1347   _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
1348   _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
1349   _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
1350   return true;
1351 }
1352 
1353 CPUInformationInterface::~CPUInformationInterface() {
1354   if (_cpu_info != NULL) {
1355     const char* cpu_name = _cpu_info->cpu_name();
1356     if (cpu_name != NULL) {
1357       FREE_C_HEAP_ARRAY(char, cpu_name);
1358       _cpu_info->set_cpu_name(NULL);
1359     }
1360     const char* cpu_desc = _cpu_info->cpu_description();
1361     if (cpu_desc != NULL) {
1362       FREE_C_HEAP_ARRAY(char, cpu_desc);
1363       _cpu_info->set_cpu_description(NULL);
1364     }
1365     delete _cpu_info;
1366     _cpu_info = NULL;
1367   }
1368 }
1369 
1370 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
1371   if (NULL == _cpu_info) {
1372     return OS_ERR;
1373   }
1374   cpu_info = *_cpu_info; // shallow copy assignment
1375   return OS_OK;
1376 }
1377 
1378 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
1379   friend class NetworkPerformanceInterface;
1380  private:
1381   bool _iphlp_attached;
1382 
1383   NetworkPerformance();
1384   NetworkPerformance(const NetworkPerformance& rhs); // no impl
1385   NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
1386   bool initialize();
1387   ~NetworkPerformance();
1388   int network_utilization(NetworkInterface** network_interfaces) const;
1389 };
1390 
1391 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance()
1392 : _iphlp_attached(false) {
1393 }
1394 
1395 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
1396   _iphlp_attached = IphlpDll::IphlpAttach();
1397   return _iphlp_attached;
1398 }
1399 
1400 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
1401   if (_iphlp_attached) {
1402     IphlpDll::IphlpDetach();
1403   }
1404 }
1405 
1406 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
1407   MIB_IF_TABLE2* table;
1408 
1409   if (IphlpDll::GetIfTable2(&table) != NO_ERROR) {
1410     return OS_ERR;
1411   }
1412 
1413   NetworkInterface* ret = NULL;
1414   for (ULONG i = 0; i < table->NumEntries; ++i) {
1415     if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) {
1416       continue;
1417     }
1418 
1419     char buf[256];
1420     if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) {
1421       continue;
1422     }
1423 
1424     NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret);
1425     ret = cur;
1426   }
1427 
1428   IphlpDll::FreeMibTable(table);
1429   *network_interfaces = ret;
1430 
1431   return OS_OK;
1432 }
1433 
1434 NetworkPerformanceInterface::NetworkPerformanceInterface() {
1435   _impl = NULL;
1436 }
1437 
1438 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1439   if (_impl != NULL) {
1440     delete _impl;
1441   }
1442 }
1443 
1444 bool NetworkPerformanceInterface::initialize() {
1445   _impl = new NetworkPerformanceInterface::NetworkPerformance();
1446   return _impl != NULL && _impl->initialize();
1447 }
1448 
1449 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1450   return _impl->network_utilization(network_interfaces);
1451 }
--- EOF ---