Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/windows/vm/os_perf_windows.cpp
32284 views
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
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
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
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
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
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
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
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
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
186
static int open_query(HQUERY* query) {
187
return PdhDll::PdhOpenQuery(NULL, 0, query);
188
}
189
190
template <typename QueryP>
191
static int open_query(QueryP query) {
192
return open_query(&query->query);
193
}
194
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
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
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
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
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>
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
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
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
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>
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
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
*/
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
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
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
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
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
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
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
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
*/
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
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
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
*/
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
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
*/
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
*/
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
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
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
*/
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
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
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
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
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
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
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
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
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
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
915
static void on_initialization_failure() {
916
// still holder of critical section
917
deallocate();
918
InterlockedExchangeAdd(&reference_count, -1);
919
}
920
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
*/
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
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();
999
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
1013
CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {}
1014
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
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
1058
CPUPerformanceInterface::CPUPerformanceInterface() {
1059
_impl = NULL;
1060
}
1061
1062
bool CPUPerformanceInterface::initialize() {
1063
_impl = new CPUPerformanceInterface::CPUPerformance();
1064
return _impl != NULL && _impl->initialize();
1065
}
1066
1067
CPUPerformanceInterface::~CPUPerformanceInterface() {
1068
if (_impl != NULL) {
1069
delete _impl;
1070
}
1071
}
1072
1073
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
1074
return _impl->cpu_load(which_logical_cpu, cpu_load);
1075
}
1076
1077
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
1078
return _impl->context_switch_rate(rate);
1079
}
1080
1081
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
1082
return _impl->cpu_load_total_process(cpu_load);
1083
}
1084
1085
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
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
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
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
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
1204
SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
1205
_hProcessSnap = INVALID_HANDLE_VALUE;
1206
_valid = FALSE;
1207
_pe32.dwSize = sizeof(PROCESSENTRY32);
1208
}
1209
1210
bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
1211
return true;
1212
}
1213
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
1225
SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
1226
if (_hProcessSnap != INVALID_HANDLE_VALUE) {
1227
CloseHandle(_hProcessSnap);
1228
}
1229
}
1230
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
1252
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
1266
int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
1267
_valid = Process32Next(_hProcessSnap, &_pe32);
1268
return OS_OK;
1269
}
1270
1271
SystemProcessInterface::SystemProcesses::SystemProcesses() {
1272
_iterator = NULL;
1273
}
1274
1275
bool SystemProcessInterface::SystemProcesses::initialize() {
1276
_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
1277
return _iterator != NULL && _iterator->initialize();
1278
}
1279
1280
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
1281
if (_iterator != NULL) {
1282
delete _iterator;
1283
_iterator = NULL;
1284
}
1285
}
1286
1287
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
1321
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
1326
SystemProcessInterface::SystemProcessInterface() {
1327
_impl = NULL;
1328
}
1329
1330
bool SystemProcessInterface::initialize() {
1331
_impl = new SystemProcessInterface::SystemProcesses();
1332
return _impl != NULL && _impl->initialize();
1333
}
1334
1335
SystemProcessInterface::~SystemProcessInterface() {
1336
if (_impl != NULL) {
1337
delete _impl;
1338
}
1339
}
1340
1341
CPUInformationInterface::CPUInformationInterface() {
1342
_cpu_info = NULL;
1343
}
1344
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
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
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
1396
NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance()
1397
: _iphlp_attached(false) {
1398
}
1399
1400
bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
1401
_iphlp_attached = IphlpDll::IphlpAttach();
1402
return _iphlp_attached;
1403
}
1404
1405
NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
1406
if (_iphlp_attached) {
1407
IphlpDll::IphlpDetach();
1408
}
1409
}
1410
1411
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
1439
NetworkPerformanceInterface::NetworkPerformanceInterface() {
1440
_impl = NULL;
1441
}
1442
1443
NetworkPerformanceInterface::~NetworkPerformanceInterface() {
1444
if (_impl != NULL) {
1445
delete _impl;
1446
}
1447
}
1448
1449
bool NetworkPerformanceInterface::initialize() {
1450
_impl = new NetworkPerformanceInterface::NetworkPerformance();
1451
return _impl != NULL && _impl->initialize();
1452
}
1453
1454
int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
1455
return _impl->network_utilization(network_interfaces);
1456
}
1457
1458