author | lkorinth |
Wed, 11 Sep 2019 14:16:30 +0200 | |
changeset 58084 | cddef3bde924 |
parent 58083 | 9046db64ca39 |
child 58282 | 03fce7b04b42 |
permissions | -rw-r--r-- |
50113 | 1 |
/* |
53882
ca682d9d8db5
8214777: Avoid some GCC 8.X strncpy() errors in HotSpot
mikael
parents:
50879
diff
changeset
|
2 |
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. |
50113 | 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" |
|
50879 | 26 |
#include "iphlp_interface.hpp" |
50113 | 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" |
|
50879 | 33 |
#include "utilities/macros.hpp" |
50113 | 34 |
#include "vm_version_ext_x86.hpp" |
35 |
#include <math.h> |
|
36 |
#include <psapi.h> |
|
37 |
#include <TlHelp32.h> |
|
38 |
||
39 |
/* |
|
40 |
* Windows provides a vast plethora of performance objects and counters, |
|
41 |
* consumption of which is assisted using the Performance Data Helper (PDH) interface. |
|
42 |
* We import a selected few api entry points from PDH, see pdh_interface.hpp. |
|
43 |
* |
|
44 |
* The code located in this file is to a large extent an abstraction over much of the |
|
45 |
* plumbing needed to start consuming an object and/or counter of choice. |
|
46 |
* |
|
47 |
*/ |
|
48 |
||
49 |
/* |
|
50 |
* How to use: |
|
51 |
* 1. Create query |
|
52 |
* 2. Add counters to the query |
|
53 |
* 3. Collect the performance data using the query |
|
54 |
* 4. Display the performance data using the counters associated with the query |
|
55 |
* 5. Destroy query (counter destruction implied) |
|
56 |
*/ |
|
57 |
||
58 |
/* |
|
59 |
* Every PDH artifact, like processor, process, thread, memory, and so forth are |
|
60 |
* identified with an index that is always the same irrespective |
|
61 |
* of the localized version of the operating system or service pack installed. |
|
62 |
* INFO: Using PDH APIs Correctly in a Localized Language (Q287159) |
|
63 |
* http://support.microsoft.com/default.aspx?scid=kb;EN-US;q287159 |
|
64 |
* |
|
65 |
* To find the correct index for an object or counter, inspect the registry key / value: |
|
66 |
* [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009\Counter] |
|
67 |
* |
|
68 |
* some common PDH indexes |
|
69 |
*/ |
|
70 |
static const DWORD PDH_PROCESSOR_IDX = 238; |
|
71 |
static const DWORD PDH_PROCESSOR_TIME_IDX = 6; |
|
72 |
static const DWORD PDH_PRIV_PROCESSOR_TIME_IDX = 144; |
|
73 |
static const DWORD PDH_PROCESS_IDX = 230; |
|
74 |
static const DWORD PDH_ID_PROCESS_IDX = 784; |
|
75 |
static const DWORD PDH_CONTEXT_SWITCH_RATE_IDX = 146; |
|
76 |
static const DWORD PDH_SYSTEM_IDX = 2; |
|
77 |
||
78 |
/* useful pdh fmt's */ |
|
79 |
static const char* const OBJECT_COUNTER_FMT = "\\%s\\%s"; |
|
80 |
static const size_t OBJECT_COUNTER_FMT_LEN = 2; |
|
81 |
static const char* const OBJECT_WITH_INSTANCES_COUNTER_FMT = "\\%s(%s)\\%s"; |
|
82 |
static const size_t OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN = 4; |
|
83 |
static const char* const PROCESS_OBJECT_INSTANCE_COUNTER_FMT = "\\%s(%s#%s)\\%s"; |
|
84 |
static const size_t PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN = 5; |
|
85 |
||
86 |
static const char* process_image_name = NULL; // for example, "java" but could have another image name |
|
87 |
static char* pdh_IDProcess_counter_fmt = NULL; // "\Process(java#%d)\ID Process" */ |
|
88 |
||
89 |
// Need to limit how often we update a query to minimize the heisenberg effect. |
|
90 |
// (PDH behaves erratically if the counters are queried too often, especially counters that |
|
91 |
// store and use values from two consecutive updates, like cpu load.) |
|
92 |
static const int min_update_interval_millis = 500; |
|
93 |
||
94 |
/* |
|
95 |
* Structs for PDH queries. |
|
96 |
*/ |
|
97 |
typedef struct { |
|
98 |
HQUERY query; |
|
99 |
s8 lastUpdate; // Last time query was updated (current millis). |
|
100 |
} UpdateQueryS, *UpdateQueryP; |
|
101 |
||
102 |
||
103 |
typedef struct { |
|
104 |
UpdateQueryS query; |
|
105 |
HCOUNTER counter; |
|
106 |
bool initialized; |
|
107 |
} CounterQueryS, *CounterQueryP; |
|
108 |
||
109 |
typedef struct { |
|
110 |
UpdateQueryS query; |
|
111 |
HCOUNTER* counters; |
|
112 |
int noOfCounters; |
|
113 |
bool initialized; |
|
114 |
} MultiCounterQueryS, *MultiCounterQueryP; |
|
115 |
||
116 |
typedef struct { |
|
117 |
MultiCounterQueryP queries; |
|
118 |
int size; |
|
119 |
bool initialized; |
|
120 |
} MultiCounterQuerySetS, *MultiCounterQuerySetP; |
|
121 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
122 |
typedef struct { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
123 |
MultiCounterQuerySetS set; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
124 |
int process_index; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
125 |
} ProcessQueryS, *ProcessQueryP; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
126 |
|
50113 | 127 |
static void pdh_cleanup(HQUERY* const query, HCOUNTER* const counter) { |
128 |
if (counter != NULL && *counter != NULL) { |
|
129 |
PdhDll::PdhRemoveCounter(*counter); |
|
130 |
*counter = NULL; |
|
131 |
} |
|
132 |
if (query != NULL && *query != NULL) { |
|
133 |
PdhDll::PdhCloseQuery(*query); |
|
134 |
*query = NULL; |
|
135 |
} |
|
136 |
} |
|
137 |
||
138 |
static CounterQueryP create_counter_query() { |
|
58083 | 139 |
CounterQueryP const query = NEW_C_HEAP_OBJ(CounterQueryS, mtInternal); |
50113 | 140 |
memset(query, 0, sizeof(CounterQueryS)); |
141 |
return query; |
|
142 |
} |
|
143 |
||
144 |
static void destroy_counter_query(CounterQueryP query) { |
|
145 |
assert(query != NULL, "invariant"); |
|
146 |
pdh_cleanup(&query->query.query, &query->counter); |
|
58083 | 147 |
FREE_C_HEAP_OBJ(query); |
50113 | 148 |
} |
149 |
||
150 |
static MultiCounterQueryP create_multi_counter_query() { |
|
151 |
MultiCounterQueryP const query = NEW_C_HEAP_ARRAY(MultiCounterQueryS, 1, mtInternal); |
|
152 |
memset(query, 0, sizeof(MultiCounterQueryS)); |
|
153 |
return query; |
|
154 |
} |
|
155 |
||
156 |
static void destroy_counter_query(MultiCounterQueryP counter_query) { |
|
157 |
if (counter_query != NULL) { |
|
158 |
for (int i = 0; i < counter_query->noOfCounters; ++i) { |
|
159 |
pdh_cleanup(NULL, &counter_query->counters[i]); |
|
160 |
} |
|
161 |
FREE_C_HEAP_ARRAY(char, counter_query->counters); |
|
162 |
pdh_cleanup(&counter_query->query.query, NULL); |
|
163 |
FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query); |
|
164 |
} |
|
165 |
} |
|
166 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
167 |
static void destroy_multi_counter_query(MultiCounterQuerySetP counter_query_set) { |
50113 | 168 |
for (int i = 0; i < counter_query_set->size; i++) { |
169 |
for (int j = 0; j < counter_query_set->queries[i].noOfCounters; ++j) { |
|
170 |
pdh_cleanup(NULL, &counter_query_set->queries[i].counters[j]); |
|
171 |
} |
|
172 |
FREE_C_HEAP_ARRAY(char, counter_query_set->queries[i].counters); |
|
173 |
pdh_cleanup(&counter_query_set->queries[i].query.query, NULL); |
|
174 |
} |
|
175 |
FREE_C_HEAP_ARRAY(MultiCounterQueryS, counter_query_set->queries); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
176 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
177 |
|
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
178 |
static void destroy_counter_query(MultiCounterQuerySetP counter_query_set) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
179 |
destroy_multi_counter_query(counter_query_set); |
50113 | 180 |
FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, counter_query_set); |
181 |
} |
|
182 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
183 |
static void destroy_counter_query(ProcessQueryP process_query) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
184 |
destroy_multi_counter_query(&process_query->set); |
58083 | 185 |
FREE_C_HEAP_OBJ(process_query); |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
186 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
187 |
|
50113 | 188 |
static int open_query(HQUERY* query) { |
189 |
return PdhDll::PdhOpenQuery(NULL, 0, query); |
|
190 |
} |
|
191 |
||
192 |
template <typename QueryP> |
|
193 |
static int open_query(QueryP query) { |
|
194 |
return open_query(&query->query); |
|
195 |
} |
|
196 |
||
197 |
static int allocate_counters(MultiCounterQueryP query, size_t nofCounters) { |
|
198 |
assert(query != NULL, "invariant"); |
|
199 |
assert(!query->initialized, "invariant"); |
|
200 |
assert(0 == query->noOfCounters, "invariant"); |
|
201 |
assert(query->counters == NULL, "invariant"); |
|
58083 | 202 |
query->counters = NEW_C_HEAP_ARRAY(HCOUNTER, nofCounters, mtInternal); |
50113 | 203 |
if (query->counters == NULL) { |
204 |
return OS_ERR; |
|
205 |
} |
|
206 |
memset(query->counters, 0, nofCounters * sizeof(HCOUNTER)); |
|
207 |
query->noOfCounters = (int)nofCounters; |
|
208 |
return OS_OK; |
|
209 |
} |
|
210 |
||
211 |
static int allocate_counters(MultiCounterQuerySetP query_set, size_t nofCounters) { |
|
212 |
assert(query_set != NULL, "invariant"); |
|
213 |
assert(!query_set->initialized, "invariant"); |
|
214 |
for (int i = 0; i < query_set->size; ++i) { |
|
215 |
if (allocate_counters(&query_set->queries[i], nofCounters) != OS_OK) { |
|
216 |
return OS_ERR; |
|
217 |
} |
|
218 |
} |
|
219 |
return OS_OK; |
|
220 |
} |
|
221 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
222 |
static int allocate_counters(ProcessQueryP process_query, size_t nofCounters) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
223 |
assert(process_query != NULL, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
224 |
return allocate_counters(&process_query->set, nofCounters); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
225 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
226 |
|
50113 | 227 |
static void deallocate_counters(MultiCounterQueryP query) { |
58084
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
228 |
FREE_C_HEAP_ARRAY(char, query->counters); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
229 |
query->counters = NULL; |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
230 |
query->noOfCounters = 0; |
50113 | 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). |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
346 |
* |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
347 |
* if unable to query, returns OS_ERR(-1) |
50113 | 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) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
354 |
return OS_ERR; |
50113 | 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); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
364 |
return OS_ERR; |
50113 | 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); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
369 |
return OS_ERR; |
50113 | 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); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
381 |
return OS_ERR; |
50113 | 382 |
} |
383 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
384 |
static ProcessQueryP create_process_query() { |
50113 | 385 |
const int current_process_idx = current_query_index_for_process(); |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
386 |
if (OS_ERR == current_process_idx) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
387 |
return NULL; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
388 |
} |
58083 | 389 |
ProcessQueryP const process_query = NEW_C_HEAP_OBJ(ProcessQueryS, mtInternal); |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
390 |
memset(process_query, 0, sizeof(ProcessQueryS)); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
391 |
process_query->set.queries = NEW_C_HEAP_ARRAY(MultiCounterQueryS, current_process_idx + 1, mtInternal); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
392 |
memset(process_query->set.queries, 0, sizeof(MultiCounterQueryS) * (current_process_idx + 1)); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
393 |
process_query->process_index = current_process_idx; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
394 |
process_query->set.size = current_process_idx + 1; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
395 |
assert(process_query->set.size > process_query->process_index, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
396 |
return process_query; |
50113 | 397 |
} |
398 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
399 |
static MultiCounterQueryP current_process_counter_query(ProcessQueryP process_query) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
400 |
assert(process_query != NULL, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
401 |
assert(process_query->process_index < process_query->set.size, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
402 |
return &process_query->set.queries[process_query->process_index]; |
50113 | 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); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
410 |
query->initialized = false; |
50113 | 411 |
} |
412 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
413 |
static int ensure_valid_process_query_index(ProcessQueryP process_query) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
414 |
assert(process_query != NULL, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
415 |
const int previous_process_idx = process_query->process_index; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
416 |
if (previous_process_idx == 0) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
417 |
return previous_process_idx; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
418 |
} |
50113 | 419 |
const int current_process_idx = current_query_index_for_process(); |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
420 |
if (current_process_idx == previous_process_idx || OS_ERR == current_process_idx || |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
421 |
current_process_idx >= process_query->set.size) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
422 |
return previous_process_idx; |
50113 | 423 |
} |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
424 |
|
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
425 |
assert(current_process_idx >= 0 && current_process_idx < process_query->set.size, "out of bounds!"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
426 |
while (current_process_idx < process_query->set.size - 1) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
427 |
const int new_size = --process_query->set.size; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
428 |
clear_multi_counter(&process_query->set.queries[new_size]); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
429 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
430 |
assert(current_process_idx < process_query->set.size, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
431 |
process_query->process_index = current_process_idx; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
432 |
return current_process_idx; |
50113 | 433 |
} |
434 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
435 |
static MultiCounterQueryP current_process_query(ProcessQueryP process_query) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
436 |
assert(process_query != NULL, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
437 |
const int current_process_idx = ensure_valid_process_query_index(process_query); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
438 |
assert(current_process_idx == process_query->process_index, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
439 |
assert(current_process_idx < process_query->set.size, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
440 |
return &process_query->set.queries[current_process_idx]; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
441 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
442 |
|
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
443 |
static int collect_process_query_data(ProcessQueryP process_query) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
444 |
assert(process_query != NULL, "invariant"); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
445 |
return collect_query_data(current_process_query(process_query)); |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
446 |
} |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
447 |
|
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
448 |
static int query_process_counter(ProcessQueryP process_query, int slot_index, DWORD format, PDH_FMT_COUNTERVALUE* const value) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
449 |
MultiCounterQueryP const current_query = current_process_counter_query(process_query); |
50113 | 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 |
log_warning(os)("Unable to resolve PDH index: (%ld)", index); |
|
555 |
log_warning(os)("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() { |
|
58084
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
660 |
FREE_C_HEAP_ARRAY(char, process_image_name); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
661 |
process_image_name = NULL; |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
662 |
FREE_C_HEAP_ARRAY(char, pdh_IDProcess_counter_fmt); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
663 |
pdh_IDProcess_counter_fmt = NULL; |
50113 | 664 |
} |
665 |
||
666 |
static int allocate_pdh_constants() { |
|
667 |
assert(process_image_name == NULL, "invariant"); |
|
668 |
const char* pdh_image_name = pdh_process_image_name(); |
|
669 |
if (pdh_image_name == NULL) { |
|
670 |
return OS_ERR; |
|
671 |
} |
|
672 |
process_image_name = copy_string_to_c_heap(pdh_image_name); |
|
673 |
||
674 |
const char* pdh_localized_process_object = pdh_localized_artifact(PDH_PROCESS_IDX); |
|
675 |
if (pdh_localized_process_object == NULL) { |
|
676 |
return OS_ERR; |
|
677 |
} |
|
678 |
||
679 |
const char* pdh_localized_IDProcess_counter = pdh_localized_artifact(PDH_ID_PROCESS_IDX); |
|
680 |
if (pdh_localized_IDProcess_counter == NULL) { |
|
681 |
return OS_ERR; |
|
682 |
} |
|
683 |
||
684 |
size_t pdh_IDProcess_counter_fmt_len = strlen(process_image_name); |
|
685 |
pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_process_object); |
|
686 |
pdh_IDProcess_counter_fmt_len += strlen(pdh_localized_IDProcess_counter); |
|
687 |
pdh_IDProcess_counter_fmt_len += PROCESS_OBJECT_INSTANCE_COUNTER_FMT_LEN; |
|
688 |
pdh_IDProcess_counter_fmt_len += 2; // "%d" |
|
689 |
||
690 |
assert(pdh_IDProcess_counter_fmt == NULL, "invariant"); |
|
691 |
pdh_IDProcess_counter_fmt = NEW_C_HEAP_ARRAY_RETURN_NULL(char, pdh_IDProcess_counter_fmt_len + 1, mtInternal); |
|
692 |
if (pdh_IDProcess_counter_fmt == NULL) { |
|
693 |
return OS_ERR; |
|
694 |
} |
|
695 |
||
696 |
/* "\Process(java#%d)\ID Process" */ |
|
697 |
const size_t len = jio_snprintf(pdh_IDProcess_counter_fmt, |
|
698 |
pdh_IDProcess_counter_fmt_len + 1, |
|
699 |
PROCESS_OBJECT_INSTANCE_COUNTER_FMT, |
|
700 |
pdh_localized_process_object, |
|
701 |
process_image_name, |
|
702 |
"%d", |
|
703 |
pdh_localized_IDProcess_counter); |
|
704 |
||
705 |
assert(pdh_IDProcess_counter_fmt != NULL, "invariant"); |
|
706 |
assert(len == pdh_IDProcess_counter_fmt_len, "invariant"); |
|
707 |
return OS_OK; |
|
708 |
} |
|
709 |
||
710 |
/* |
|
711 |
* Enuerate the Processor PDH object and returns a buffer containing the enumerated instances. |
|
712 |
* Caller needs ResourceMark; |
|
713 |
* |
|
714 |
* @return buffer if successful, NULL on failure. |
|
715 |
*/ |
|
716 |
static const char* enumerate_cpu_instances() { |
|
717 |
char* processor; //'Processor' == PDH_PROCESSOR_IDX |
|
718 |
if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { |
|
719 |
return NULL; |
|
720 |
} |
|
721 |
DWORD c_size = 0; |
|
722 |
DWORD i_size = 0; |
|
723 |
// enumerate all processors. |
|
724 |
PDH_STATUS pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved |
|
725 |
NULL, // local machine |
|
726 |
processor, // object to enumerate |
|
727 |
NULL, |
|
728 |
&c_size, |
|
729 |
NULL, // instance buffer is NULL and |
|
730 |
&i_size, // pass 0 length in order to get the required size |
|
731 |
PERF_DETAIL_WIZARD, // counter detail level |
|
732 |
0); |
|
733 |
if (PdhDll::PdhStatusFail((pdhStat))) { |
|
734 |
return NULL; |
|
735 |
} |
|
736 |
char* const instances = NEW_RESOURCE_ARRAY_RETURN_NULL(char, i_size); |
|
737 |
if (instances == NULL) { |
|
738 |
return NULL; |
|
739 |
} |
|
740 |
c_size = 0; |
|
741 |
pdhStat = PdhDll::PdhEnumObjectItems(NULL, // reserved |
|
742 |
NULL, // local machine |
|
743 |
processor, // object to enumerate |
|
744 |
NULL, |
|
745 |
&c_size, |
|
746 |
instances, // now instance buffer is allocated to be filled in |
|
747 |
&i_size, // and the required size is known |
|
748 |
PERF_DETAIL_WIZARD, // counter detail level |
|
749 |
0); |
|
750 |
if (PdhDll::PdhStatusFail((pdhStat))) { |
|
751 |
return NULL; |
|
752 |
} |
|
753 |
return instances; |
|
754 |
} |
|
755 |
||
756 |
static int count_logical_cpus(const char* instances) { |
|
757 |
assert(instances != NULL, "invariant"); |
|
758 |
// count logical instances. |
|
759 |
DWORD count; |
|
760 |
char* tmp; |
|
761 |
for (count = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], count++); |
|
762 |
// PDH reports an instance for each logical processor plus an instance for the total (_Total) |
|
763 |
assert(count == os::processor_count() + 1, "invalid enumeration!"); |
|
764 |
return count - 1; |
|
765 |
} |
|
766 |
||
767 |
static int number_of_logical_cpus() { |
|
768 |
static int numberOfCPUS = 0; |
|
769 |
if (numberOfCPUS == 0) { |
|
770 |
const char* instances = enumerate_cpu_instances(); |
|
771 |
if (instances == NULL) { |
|
772 |
return OS_ERR; |
|
773 |
} |
|
774 |
numberOfCPUS = count_logical_cpus(instances); |
|
775 |
} |
|
776 |
return numberOfCPUS; |
|
777 |
} |
|
778 |
||
779 |
static double cpu_factor() { |
|
780 |
static DWORD numCpus = 0; |
|
781 |
static double cpuFactor = .0; |
|
782 |
if (numCpus == 0) { |
|
783 |
numCpus = number_of_logical_cpus(); |
|
784 |
assert(os::processor_count() <= (int)numCpus, "invariant"); |
|
785 |
cpuFactor = numCpus * 100; |
|
786 |
} |
|
787 |
return cpuFactor; |
|
788 |
} |
|
789 |
||
790 |
static void log_error_message_on_no_PDH_artifact(const char* full_counter_name) { |
|
791 |
log_warning(os)("Unable to register PDH query for \"%s\"", full_counter_name); |
|
792 |
log_warning(os)("Please check the registry if this performance object/counter is disabled"); |
|
793 |
} |
|
794 |
||
795 |
static int initialize_cpu_query_counters(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) { |
|
796 |
assert(cpu_query != NULL, "invariant"); |
|
797 |
assert(cpu_query->counters != NULL, "invariant"); |
|
798 |
char* processor; //'Processor' == PDH_PROCESSOR_IDX |
|
799 |
if (lookup_name_by_index(PDH_PROCESSOR_IDX, &processor) != OS_OK) { |
|
800 |
return OS_ERR; |
|
801 |
} |
|
802 |
char* counter_name = NULL; |
|
803 |
if (lookup_name_by_index(pdh_counter_idx, &counter_name) != OS_OK) { |
|
804 |
return OS_ERR; |
|
805 |
} |
|
806 |
if (cpu_query->query.query == NULL) { |
|
807 |
if (open_query(cpu_query)) { |
|
808 |
return OS_ERR; |
|
809 |
} |
|
810 |
} |
|
811 |
assert(cpu_query->query.query != NULL, "invariant"); |
|
812 |
size_t counter_len = strlen(processor); |
|
813 |
counter_len += strlen(counter_name); |
|
814 |
counter_len += OBJECT_WITH_INSTANCES_COUNTER_FMT_LEN; // "\\%s(%s)\\%s" |
|
815 |
||
816 |
DWORD index; |
|
817 |
char* tmp; |
|
818 |
const char* instances = enumerate_cpu_instances(); |
|
819 |
for (index = 0, tmp = const_cast<char*>(instances); *tmp != '\0'; tmp = &tmp[strlen(tmp) + 1], index++) { |
|
820 |
const size_t tmp_len = strlen(tmp); |
|
821 |
char* counter_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, counter_len + tmp_len + 1); |
|
822 |
if (counter_path == NULL) { |
|
823 |
return OS_ERR; |
|
824 |
} |
|
825 |
const size_t jio_snprintf_result = jio_snprintf(counter_path, |
|
826 |
counter_len + tmp_len + 1, |
|
827 |
OBJECT_WITH_INSTANCES_COUNTER_FMT, |
|
828 |
processor, |
|
829 |
tmp, // instance "0", "1", .."_Total" |
|
830 |
counter_name); |
|
831 |
assert(counter_len + tmp_len == jio_snprintf_result, "invariant"); |
|
832 |
if (add_counter(cpu_query, &cpu_query->counters[index], counter_path, false) != OS_OK) { |
|
833 |
// performance counter is disabled in registry and not accessible via PerfLib |
|
834 |
log_error_message_on_no_PDH_artifact(counter_path); |
|
835 |
// return OS_OK to have the system continue to run without the missing counter |
|
836 |
return OS_OK; |
|
837 |
} |
|
838 |
} |
|
839 |
cpu_query->initialized = true; |
|
840 |
// Query once to initialize the counters which require at least two samples |
|
841 |
// (like the % CPU usage) to calculate correctly. |
|
842 |
collect_query_data(cpu_query); |
|
843 |
return OS_OK; |
|
844 |
} |
|
845 |
||
846 |
static int initialize_cpu_query(MultiCounterQueryP cpu_query, DWORD pdh_counter_idx) { |
|
847 |
assert(cpu_query != NULL, "invariant"); |
|
848 |
assert(!cpu_query->initialized, "invariant"); |
|
849 |
const int logical_cpu_count = number_of_logical_cpus(); |
|
850 |
assert(logical_cpu_count >= os::processor_count(), "invariant"); |
|
851 |
// we also add another counter for instance "_Total" |
|
852 |
if (allocate_counters(cpu_query, logical_cpu_count + 1) != OS_OK) { |
|
853 |
return OS_ERR; |
|
854 |
} |
|
855 |
assert(cpu_query->noOfCounters == logical_cpu_count + 1, "invariant"); |
|
856 |
return initialize_cpu_query_counters(cpu_query, pdh_counter_idx); |
|
857 |
} |
|
858 |
||
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
859 |
static int initialize_process_counter(ProcessQueryP process_query, int slot_index, DWORD pdh_counter_index) { |
50113 | 860 |
char* localized_process_object; |
861 |
if (lookup_name_by_index(PDH_PROCESS_IDX, &localized_process_object) != OS_OK) { |
|
862 |
return OS_ERR; |
|
863 |
} |
|
864 |
assert(localized_process_object != NULL, "invariant"); |
|
865 |
char* localized_counter_name; |
|
866 |
if (lookup_name_by_index(pdh_counter_index, &localized_counter_name) != OS_OK) { |
|
867 |
return OS_ERR; |
|
868 |
} |
|
869 |
assert(localized_counter_name != NULL, "invariant"); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
870 |
for (int i = 0; i < process_query->set.size; ++i) { |
50113 | 871 |
char instanceIndexBuffer[32]; |
872 |
const char* counter_path = make_fully_qualified_counter_path(localized_process_object, |
|
873 |
localized_counter_name, |
|
874 |
process_image_name, |
|
875 |
itoa(i, instanceIndexBuffer, 10)); |
|
876 |
if (counter_path == NULL) { |
|
877 |
return OS_ERR; |
|
878 |
} |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
879 |
MultiCounterQueryP const query = &process_query->set.queries[i]; |
50113 | 880 |
if (add_process_counter(query, slot_index, counter_path, true)) { |
881 |
return OS_ERR; |
|
882 |
} |
|
883 |
} |
|
884 |
return OS_OK; |
|
885 |
} |
|
886 |
||
887 |
static CounterQueryP create_counter_query(DWORD pdh_object_idx, DWORD pdh_counter_idx) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
888 |
if (!((is_valid_pdh_index(pdh_object_idx) && is_valid_pdh_index(pdh_counter_idx)))) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
889 |
return NULL; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
890 |
} |
50113 | 891 |
CounterQueryP const query = create_counter_query(); |
892 |
const char* object = pdh_localized_artifact(pdh_object_idx); |
|
893 |
assert(object != NULL, "invariant"); |
|
894 |
const char* counter = pdh_localized_artifact(pdh_counter_idx); |
|
895 |
assert(counter != NULL, "invariant"); |
|
896 |
const char* full_counter_path = make_fully_qualified_counter_path(object, counter); |
|
897 |
assert(full_counter_path != NULL, "invariant"); |
|
898 |
add_counter(query, full_counter_path, true); |
|
899 |
return query; |
|
900 |
} |
|
901 |
||
902 |
static void deallocate() { |
|
903 |
deallocate_pdh_constants(); |
|
904 |
PdhDll::PdhDetach(); |
|
905 |
} |
|
906 |
||
907 |
static LONG critical_section = 0; |
|
908 |
static LONG reference_count = 0; |
|
909 |
static bool pdh_initialized = false; |
|
910 |
||
911 |
static void on_initialization_failure() { |
|
912 |
// still holder of critical section |
|
913 |
deallocate(); |
|
914 |
InterlockedExchangeAdd(&reference_count, -1); |
|
915 |
} |
|
916 |
||
917 |
static OSReturn initialize() { |
|
918 |
ResourceMark rm; |
|
919 |
if (!PdhDll::PdhAttach()) { |
|
920 |
return OS_ERR; |
|
921 |
} |
|
922 |
if (allocate_pdh_constants() != OS_OK) { |
|
923 |
on_initialization_failure(); |
|
924 |
return OS_ERR; |
|
925 |
} |
|
926 |
return OS_OK; |
|
927 |
} |
|
928 |
||
929 |
/* |
|
930 |
* Helper to initialize the PDH library, function pointers, constants and counters. |
|
931 |
* |
|
932 |
* Reference counting allows for unloading of pdh.dll granted all sessions use the pair: |
|
933 |
* |
|
934 |
* pdh_acquire(); |
|
935 |
* pdh_release(); |
|
936 |
* |
|
937 |
* @return OS_OK if successful, OS_ERR on failure. |
|
938 |
*/ |
|
939 |
static bool pdh_acquire() { |
|
940 |
while (InterlockedCompareExchange(&critical_section, 1, 0) == 1); |
|
941 |
InterlockedExchangeAdd(&reference_count, 1); |
|
942 |
if (pdh_initialized) { |
|
943 |
return true; |
|
944 |
} |
|
945 |
const OSReturn ret = initialize(); |
|
946 |
if (OS_OK == ret) { |
|
947 |
pdh_initialized = true; |
|
948 |
} |
|
949 |
while (InterlockedCompareExchange(&critical_section, 0, 1) == 0); |
|
950 |
return ret == OS_OK; |
|
951 |
} |
|
952 |
||
953 |
static void pdh_release() { |
|
954 |
while (InterlockedCompareExchange(&critical_section, 1, 0) == 1); |
|
955 |
const LONG prev_ref_count = InterlockedExchangeAdd(&reference_count, -1); |
|
956 |
if (1 == prev_ref_count) { |
|
957 |
deallocate(); |
|
958 |
pdh_initialized = false; |
|
959 |
} |
|
960 |
while (InterlockedCompareExchange(&critical_section, 0, 1) == 0); |
|
961 |
} |
|
962 |
||
963 |
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> { |
|
964 |
friend class CPUPerformanceInterface; |
|
965 |
private: |
|
966 |
CounterQueryP _context_switches; |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
967 |
ProcessQueryP _process_cpu_load; |
50113 | 968 |
MultiCounterQueryP _machine_cpu_load; |
969 |
||
970 |
int cpu_load(int which_logical_cpu, double* cpu_load); |
|
971 |
int context_switch_rate(double* rate); |
|
972 |
int cpu_load_total_process(double* cpu_load); |
|
973 |
int cpu_loads_process(double* jvm_user_load, double* jvm_kernel_load, double* psystemTotalLoad); |
|
974 |
CPUPerformance(); |
|
975 |
~CPUPerformance(); |
|
976 |
bool initialize(); |
|
977 |
}; |
|
978 |
||
979 |
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> { |
|
980 |
friend class SystemProcessInterface; |
|
981 |
private: |
|
982 |
class ProcessIterator : public CHeapObj<mtInternal> { |
|
983 |
friend class SystemProcessInterface::SystemProcesses; |
|
984 |
private: |
|
985 |
HANDLE _hProcessSnap; |
|
986 |
PROCESSENTRY32 _pe32; |
|
987 |
BOOL _valid; |
|
988 |
char _exePath[MAX_PATH]; |
|
989 |
ProcessIterator(); |
|
990 |
~ProcessIterator(); |
|
991 |
bool initialize(); |
|
992 |
||
993 |
int current(SystemProcess* const process_info); |
|
994 |
int next_process(); |
|
995 |
bool is_valid() const { return _valid != FALSE; } |
|
996 |
char* allocate_string(const char* str) const; |
|
997 |
int snapshot(); |
|
998 |
}; |
|
999 |
||
1000 |
ProcessIterator* _iterator; |
|
1001 |
SystemProcesses(); |
|
1002 |
~SystemProcesses(); |
|
1003 |
bool initialize(); |
|
1004 |
||
1005 |
// information about system processes |
|
1006 |
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; |
|
1007 |
}; |
|
1008 |
||
1009 |
CPUPerformanceInterface::CPUPerformance::CPUPerformance() : _context_switches(NULL), _process_cpu_load(NULL), _machine_cpu_load(NULL) {} |
|
1010 |
||
1011 |
bool CPUPerformanceInterface::CPUPerformance::initialize() { |
|
1012 |
if (!pdh_acquire()) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1013 |
return true; |
50113 | 1014 |
} |
1015 |
_context_switches = create_counter_query(PDH_SYSTEM_IDX, PDH_CONTEXT_SWITCH_RATE_IDX); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1016 |
_process_cpu_load = create_process_query(); |
50113 | 1017 |
if (_process_cpu_load == NULL) { |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1018 |
return true; |
50113 | 1019 |
} |
1020 |
if (allocate_counters(_process_cpu_load, 2) != OS_OK) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1021 |
return true; |
50113 | 1022 |
} |
1023 |
if (initialize_process_counter(_process_cpu_load, 0, PDH_PROCESSOR_TIME_IDX) != OS_OK) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1024 |
return true; |
50113 | 1025 |
} |
1026 |
if (initialize_process_counter(_process_cpu_load, 1, PDH_PRIV_PROCESSOR_TIME_IDX) != OS_OK) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1027 |
return true; |
50113 | 1028 |
} |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1029 |
_process_cpu_load->set.initialized = true; |
50113 | 1030 |
_machine_cpu_load = create_multi_counter_query(); |
1031 |
if (_machine_cpu_load == NULL) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1032 |
return true; |
50113 | 1033 |
} |
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1034 |
initialize_cpu_query(_machine_cpu_load, PDH_PROCESSOR_TIME_IDX); |
50113 | 1035 |
return true; |
1036 |
} |
|
1037 |
||
1038 |
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { |
|
1039 |
if (_context_switches != NULL) { |
|
1040 |
destroy_counter_query(_context_switches); |
|
1041 |
_context_switches = NULL; |
|
1042 |
} |
|
1043 |
if (_process_cpu_load != NULL) { |
|
1044 |
destroy_counter_query(_process_cpu_load); |
|
1045 |
_process_cpu_load = NULL; |
|
1046 |
} |
|
1047 |
if (_machine_cpu_load != NULL) { |
|
1048 |
destroy_counter_query(_machine_cpu_load); |
|
1049 |
_machine_cpu_load = NULL; |
|
1050 |
} |
|
1051 |
pdh_release(); |
|
1052 |
} |
|
1053 |
||
1054 |
CPUPerformanceInterface::CPUPerformanceInterface() { |
|
1055 |
_impl = NULL; |
|
1056 |
} |
|
1057 |
||
1058 |
bool CPUPerformanceInterface::initialize() { |
|
1059 |
_impl = new CPUPerformanceInterface::CPUPerformance(); |
|
1060 |
return _impl != NULL && _impl->initialize(); |
|
1061 |
} |
|
1062 |
||
1063 |
CPUPerformanceInterface::~CPUPerformanceInterface() { |
|
1064 |
if (_impl != NULL) { |
|
1065 |
delete _impl; |
|
1066 |
} |
|
1067 |
} |
|
1068 |
||
1069 |
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { |
|
1070 |
return _impl->cpu_load(which_logical_cpu, cpu_load); |
|
1071 |
} |
|
1072 |
||
1073 |
int CPUPerformanceInterface::context_switch_rate(double* rate) const { |
|
1074 |
return _impl->context_switch_rate(rate); |
|
1075 |
} |
|
1076 |
||
1077 |
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { |
|
1078 |
return _impl->cpu_load_total_process(cpu_load); |
|
1079 |
} |
|
1080 |
||
1081 |
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, |
|
1082 |
double* pjvmKernelLoad, |
|
1083 |
double* psystemTotalLoad) const { |
|
1084 |
return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); |
|
1085 |
} |
|
1086 |
||
1087 |
int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1088 |
*cpu_load = .0; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1089 |
if (_machine_cpu_load == NULL || !_machine_cpu_load->initialized) { |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1090 |
return OS_ERR; |
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1091 |
} |
50113 | 1092 |
assert(_machine_cpu_load != NULL, "invariant"); |
1093 |
assert(which_logical_cpu < _machine_cpu_load->noOfCounters, "invariant"); |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1094 |
|
50113 | 1095 |
if (collect_query_data(_machine_cpu_load)) { |
1096 |
return OS_ERR; |
|
1097 |
} |
|
1098 |
// -1 is total (all cpus) |
|
1099 |
const int counter_idx = -1 == which_logical_cpu ? _machine_cpu_load->noOfCounters - 1 : which_logical_cpu; |
|
1100 |
PDH_FMT_COUNTERVALUE counter_value; |
|
1101 |
formatted_counter_value(_machine_cpu_load->counters[counter_idx], PDH_FMT_DOUBLE, &counter_value); |
|
1102 |
*cpu_load = counter_value.doubleValue / 100; |
|
1103 |
return OS_OK; |
|
1104 |
} |
|
1105 |
||
1106 |
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { |
|
1107 |
*cpu_load = .0; |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1108 |
if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) { |
50113 | 1109 |
return OS_ERR; |
1110 |
} |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1111 |
assert(_process_cpu_load != NULL, "invariant"); |
50113 | 1112 |
if (collect_process_query_data(_process_cpu_load)) { |
1113 |
return OS_ERR; |
|
1114 |
} |
|
1115 |
PDH_FMT_COUNTERVALUE counter_value; |
|
1116 |
if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) { |
|
1117 |
return OS_ERR; |
|
1118 |
} |
|
1119 |
double process_load = counter_value.doubleValue / cpu_factor(); |
|
1120 |
process_load = MIN2<double>(1, process_load); |
|
1121 |
process_load = MAX2<double>(0, process_load); |
|
1122 |
*cpu_load = process_load; |
|
1123 |
return OS_OK; |
|
1124 |
} |
|
1125 |
||
1126 |
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, |
|
1127 |
double* pjvmKernelLoad, |
|
1128 |
double* psystemTotalLoad) { |
|
1129 |
assert(pjvmUserLoad != NULL, "pjvmUserLoad is NULL!"); |
|
1130 |
assert(pjvmKernelLoad != NULL, "pjvmKernelLoad is NULL!"); |
|
1131 |
assert(psystemTotalLoad != NULL, "psystemTotalLoad is NULL!"); |
|
1132 |
*pjvmUserLoad = .0; |
|
1133 |
*pjvmKernelLoad = .0; |
|
1134 |
*psystemTotalLoad = .0; |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1135 |
|
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1136 |
if (_process_cpu_load == NULL || !_process_cpu_load->set.initialized) { |
50113 | 1137 |
return OS_ERR; |
1138 |
} |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1139 |
assert(_process_cpu_load != NULL, "invariant"); |
50113 | 1140 |
if (collect_process_query_data(_process_cpu_load)) { |
1141 |
return OS_ERR; |
|
1142 |
} |
|
1143 |
double process_load = .0; |
|
1144 |
PDH_FMT_COUNTERVALUE counter_value; |
|
1145 |
// Read PDH_PROCESSOR_TIME_IDX |
|
1146 |
if (query_process_counter(_process_cpu_load, 0, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) { |
|
1147 |
return OS_ERR; |
|
1148 |
} |
|
1149 |
process_load = counter_value.doubleValue / cpu_factor(); |
|
1150 |
process_load = MIN2<double>(1, process_load); |
|
1151 |
process_load = MAX2<double>(0, process_load); |
|
1152 |
// Read PDH_PRIV_PROCESSOR_TIME_IDX |
|
1153 |
if (query_process_counter(_process_cpu_load, 1, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &counter_value) != OS_OK) { |
|
1154 |
return OS_ERR; |
|
1155 |
} |
|
1156 |
double kernel_load = counter_value.doubleValue / cpu_factor(); |
|
1157 |
kernel_load = MIN2<double>(1, kernel_load); |
|
1158 |
kernel_load = MAX2<double>(0, kernel_load); |
|
1159 |
*pjvmKernelLoad = kernel_load; |
|
1160 |
||
1161 |
double user_load = process_load - kernel_load; |
|
1162 |
user_load = MIN2<double>(1, user_load); |
|
1163 |
user_load = MAX2<double>(0, user_load); |
|
1164 |
*pjvmUserLoad = user_load; |
|
1165 |
||
1166 |
if (collect_query_data(_machine_cpu_load)) { |
|
1167 |
return OS_ERR; |
|
1168 |
} |
|
1169 |
if (formatted_counter_value(_machine_cpu_load->counters[_machine_cpu_load->noOfCounters - 1], PDH_FMT_DOUBLE, &counter_value) != OS_OK) { |
|
1170 |
return OS_ERR; |
|
1171 |
} |
|
1172 |
double machine_load = counter_value.doubleValue / 100; |
|
1173 |
assert(machine_load >= 0, "machine_load is negative!"); |
|
1174 |
// clamp at user+system and 1.0 |
|
1175 |
if (*pjvmKernelLoad + *pjvmUserLoad > machine_load) { |
|
1176 |
machine_load = MIN2(*pjvmKernelLoad + *pjvmUserLoad, 1.0); |
|
1177 |
} |
|
1178 |
*psystemTotalLoad = machine_load; |
|
1179 |
return OS_OK; |
|
1180 |
} |
|
1181 |
||
1182 |
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { |
|
1183 |
assert(rate != NULL, "invariant"); |
|
1184 |
*rate = .0; |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1185 |
if (_context_switches == NULL || !_context_switches->initialized) { |
50113 | 1186 |
return OS_ERR; |
1187 |
} |
|
50321
b186322970f4
8203321: assert(current_query_index < process_query_set->size) failed: invariant
mgronlun
parents:
50113
diff
changeset
|
1188 |
assert(_context_switches != NULL, "invariant"); |
50113 | 1189 |
if (collect_query_data(_context_switches) != OS_OK) { |
1190 |
return OS_ERR; |
|
1191 |
} |
|
1192 |
PDH_FMT_COUNTERVALUE counter_value; |
|
1193 |
if (formatted_counter_value(_context_switches->counter, PDH_FMT_DOUBLE, &counter_value) != OS_OK) { |
|
1194 |
return OS_ERR; |
|
1195 |
} |
|
1196 |
*rate = counter_value.doubleValue; |
|
1197 |
return OS_OK; |
|
1198 |
} |
|
1199 |
||
1200 |
SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { |
|
1201 |
_hProcessSnap = INVALID_HANDLE_VALUE; |
|
1202 |
_valid = FALSE; |
|
1203 |
_pe32.dwSize = sizeof(PROCESSENTRY32); |
|
1204 |
} |
|
1205 |
||
1206 |
bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { |
|
1207 |
return true; |
|
1208 |
} |
|
1209 |
||
1210 |
int SystemProcessInterface::SystemProcesses::ProcessIterator::snapshot() { |
|
1211 |
// take snapshot of all process in the system |
|
1212 |
_hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
|
1213 |
if (_hProcessSnap == INVALID_HANDLE_VALUE) { |
|
1214 |
return OS_ERR; |
|
1215 |
} |
|
1216 |
// step to first process |
|
1217 |
_valid = Process32First(_hProcessSnap, &_pe32); |
|
1218 |
return is_valid() ? OS_OK : OS_ERR; |
|
1219 |
} |
|
1220 |
||
1221 |
SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { |
|
1222 |
if (_hProcessSnap != INVALID_HANDLE_VALUE) { |
|
1223 |
CloseHandle(_hProcessSnap); |
|
1224 |
} |
|
1225 |
} |
|
1226 |
||
1227 |
int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { |
|
1228 |
assert(is_valid(), "no current process to be fetched!"); |
|
1229 |
assert(process_info != NULL, "process_info is NULL!"); |
|
1230 |
char* exePath = NULL; |
|
1231 |
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, _pe32.th32ProcessID); |
|
1232 |
if (hProcess != NULL) { |
|
1233 |
HMODULE hMod; |
|
1234 |
DWORD cbNeeded; |
|
1235 |
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) != 0) { |
|
1236 |
if (GetModuleFileNameExA(hProcess, hMod, _exePath, sizeof(_exePath)) != 0) { |
|
1237 |
exePath = _exePath; |
|
1238 |
} |
|
1239 |
} |
|
1240 |
CloseHandle (hProcess); |
|
1241 |
} |
|
1242 |
process_info->set_pid((int)_pe32.th32ProcessID); |
|
1243 |
process_info->set_name(allocate_string(_pe32.szExeFile)); |
|
1244 |
process_info->set_path(allocate_string(exePath)); |
|
1245 |
return OS_OK; |
|
1246 |
} |
|
1247 |
||
1248 |
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { |
|
1249 |
if (str != NULL) { |
|
53882
ca682d9d8db5
8214777: Avoid some GCC 8.X strncpy() errors in HotSpot
mikael
parents:
50879
diff
changeset
|
1250 |
return os::strdup_check_oom(str, mtInternal); |
50113 | 1251 |
} |
1252 |
return NULL; |
|
1253 |
} |
|
1254 |
||
1255 |
int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { |
|
1256 |
_valid = Process32Next(_hProcessSnap, &_pe32); |
|
1257 |
return OS_OK; |
|
1258 |
} |
|
1259 |
||
1260 |
SystemProcessInterface::SystemProcesses::SystemProcesses() { |
|
1261 |
_iterator = NULL; |
|
1262 |
} |
|
1263 |
||
1264 |
bool SystemProcessInterface::SystemProcesses::initialize() { |
|
1265 |
_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); |
|
1266 |
return _iterator != NULL && _iterator->initialize(); |
|
1267 |
} |
|
1268 |
||
1269 |
SystemProcessInterface::SystemProcesses::~SystemProcesses() { |
|
1270 |
if (_iterator != NULL) { |
|
1271 |
delete _iterator; |
|
1272 |
_iterator = NULL; |
|
1273 |
} |
|
1274 |
} |
|
1275 |
||
1276 |
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, |
|
1277 |
int* no_of_sys_processes) const { |
|
1278 |
assert(system_processes != NULL, "system_processes pointer is NULL!"); |
|
1279 |
assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!"); |
|
1280 |
assert(_iterator != NULL, "iterator is NULL!"); |
|
1281 |
||
1282 |
// initialize pointers |
|
1283 |
*no_of_sys_processes = 0; |
|
1284 |
*system_processes = NULL; |
|
1285 |
||
1286 |
// take process snapshot |
|
1287 |
if (_iterator->snapshot() != OS_OK) { |
|
1288 |
return OS_ERR; |
|
1289 |
} |
|
1290 |
||
1291 |
while (_iterator->is_valid()) { |
|
1292 |
SystemProcess* tmp = new SystemProcess(); |
|
1293 |
_iterator->current(tmp); |
|
1294 |
||
1295 |
//if already existing head |
|
1296 |
if (*system_processes != NULL) { |
|
1297 |
//move "first to second" |
|
1298 |
tmp->set_next(*system_processes); |
|
1299 |
} |
|
1300 |
// new head |
|
1301 |
*system_processes = tmp; |
|
1302 |
// increment |
|
1303 |
(*no_of_sys_processes)++; |
|
1304 |
// step forward |
|
1305 |
_iterator->next_process(); |
|
1306 |
} |
|
1307 |
return OS_OK; |
|
1308 |
} |
|
1309 |
||
1310 |
int SystemProcessInterface::system_processes(SystemProcess** system_procs, |
|
1311 |
int* no_of_sys_processes) const { |
|
1312 |
return _impl->system_processes(system_procs, no_of_sys_processes); |
|
1313 |
} |
|
1314 |
||
1315 |
SystemProcessInterface::SystemProcessInterface() { |
|
1316 |
_impl = NULL; |
|
1317 |
} |
|
1318 |
||
1319 |
bool SystemProcessInterface::initialize() { |
|
1320 |
_impl = new SystemProcessInterface::SystemProcesses(); |
|
1321 |
return _impl != NULL && _impl->initialize(); |
|
1322 |
} |
|
1323 |
||
1324 |
SystemProcessInterface::~SystemProcessInterface() { |
|
1325 |
if (_impl != NULL) { |
|
1326 |
delete _impl; |
|
1327 |
} |
|
1328 |
} |
|
1329 |
||
1330 |
CPUInformationInterface::CPUInformationInterface() { |
|
1331 |
_cpu_info = NULL; |
|
1332 |
} |
|
1333 |
||
1334 |
bool CPUInformationInterface::initialize() { |
|
1335 |
_cpu_info = new CPUInformation(); |
|
1336 |
if (NULL == _cpu_info) { |
|
1337 |
return false; |
|
1338 |
} |
|
1339 |
_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); |
|
1340 |
_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); |
|
1341 |
_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); |
|
1342 |
_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); |
|
1343 |
_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); |
|
1344 |
return true; |
|
1345 |
} |
|
1346 |
||
1347 |
CPUInformationInterface::~CPUInformationInterface() { |
|
1348 |
if (_cpu_info != NULL) { |
|
58084
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
1349 |
FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_name()); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
1350 |
_cpu_info->set_cpu_name(NULL); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
1351 |
FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description()); |
cddef3bde924
8230398: Remove NULL checks before FREE_C_HEAP_ARRAY
lkorinth
parents:
58083
diff
changeset
|
1352 |
_cpu_info->set_cpu_description(NULL); |
50113 | 1353 |
delete _cpu_info; |
1354 |
_cpu_info = NULL; |
|
1355 |
} |
|
1356 |
} |
|
1357 |
||
1358 |
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { |
|
1359 |
if (NULL == _cpu_info) { |
|
1360 |
return OS_ERR; |
|
1361 |
} |
|
1362 |
cpu_info = *_cpu_info; // shallow copy assignment |
|
1363 |
return OS_OK; |
|
1364 |
} |
|
50879 | 1365 |
|
1366 |
class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> { |
|
1367 |
friend class NetworkPerformanceInterface; |
|
1368 |
private: |
|
1369 |
bool _iphlp_attached; |
|
1370 |
||
1371 |
NetworkPerformance(); |
|
1372 |
NetworkPerformance(const NetworkPerformance& rhs); // no impl |
|
1373 |
NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl |
|
1374 |
bool initialize(); |
|
1375 |
~NetworkPerformance(); |
|
1376 |
int network_utilization(NetworkInterface** network_interfaces) const; |
|
1377 |
}; |
|
1378 |
||
1379 |
NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() |
|
1380 |
: _iphlp_attached(false) { |
|
1381 |
} |
|
1382 |
||
1383 |
bool NetworkPerformanceInterface::NetworkPerformance::initialize() { |
|
1384 |
_iphlp_attached = IphlpDll::IphlpAttach(); |
|
1385 |
return _iphlp_attached; |
|
1386 |
} |
|
1387 |
||
1388 |
NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { |
|
1389 |
if (_iphlp_attached) { |
|
1390 |
IphlpDll::IphlpDetach(); |
|
1391 |
} |
|
1392 |
} |
|
1393 |
||
1394 |
int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { |
|
1395 |
MIB_IF_TABLE2* table; |
|
1396 |
||
1397 |
if (IphlpDll::GetIfTable2(&table) != NO_ERROR) { |
|
1398 |
return OS_ERR; |
|
1399 |
} |
|
1400 |
||
1401 |
NetworkInterface* ret = NULL; |
|
1402 |
for (ULONG i = 0; i < table->NumEntries; ++i) { |
|
1403 |
if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) { |
|
1404 |
continue; |
|
1405 |
} |
|
1406 |
||
1407 |
char buf[256]; |
|
1408 |
if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) { |
|
1409 |
continue; |
|
1410 |
} |
|
1411 |
||
1412 |
NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret); |
|
1413 |
ret = cur; |
|
1414 |
} |
|
1415 |
||
1416 |
IphlpDll::FreeMibTable(table); |
|
1417 |
*network_interfaces = ret; |
|
1418 |
||
1419 |
return OS_OK; |
|
1420 |
} |
|
1421 |
||
1422 |
NetworkPerformanceInterface::NetworkPerformanceInterface() { |
|
1423 |
_impl = NULL; |
|
1424 |
} |
|
1425 |
||
1426 |
NetworkPerformanceInterface::~NetworkPerformanceInterface() { |
|
1427 |
if (_impl != NULL) { |
|
1428 |
delete _impl; |
|
1429 |
} |
|
1430 |
} |
|
1431 |
||
1432 |
bool NetworkPerformanceInterface::initialize() { |
|
1433 |
_impl = new NetworkPerformanceInterface::NetworkPerformance(); |
|
1434 |
return _impl != NULL && _impl->initialize(); |
|
1435 |
} |
|
1436 |
||
1437 |
int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { |
|
1438 |
return _impl->network_utilization(network_interfaces); |
|
1439 |
} |