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