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