master
c 531 lines 23.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "perflib.h"
4
5 #if defined(OS_WINDOWS)
6 static const char *getCounterType(DWORD CounterType) {
7 switch (CounterType) {
8 case PERF_COUNTER_COUNTER:
9 return "PERF_COUNTER_COUNTER";
10
11 case PERF_COUNTER_TIMER:
12 return "PERF_COUNTER_TIMER";
13
14 case PERF_COUNTER_QUEUELEN_TYPE:
15 return "PERF_COUNTER_QUEUELEN_TYPE";
16
17 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
18 return "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
19
20 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
21 return "PERF_COUNTER_100NS_QUEUELEN_TYPE";
22
23 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
24 return "PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE";
25
26 case PERF_COUNTER_BULK_COUNT:
27 return "PERF_COUNTER_BULK_COUNT";
28
29 case PERF_COUNTER_TEXT:
30 return "PERF_COUNTER_TEXT";
31
32 case PERF_COUNTER_RAWCOUNT:
33 return "PERF_COUNTER_RAWCOUNT";
34
35 case PERF_COUNTER_LARGE_RAWCOUNT:
36 return "PERF_COUNTER_LARGE_RAWCOUNT";
37
38 case PERF_COUNTER_RAWCOUNT_HEX:
39 return "PERF_COUNTER_RAWCOUNT_HEX";
40
41 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
42 return "PERF_COUNTER_LARGE_RAWCOUNT_HEX";
43
44 case PERF_SAMPLE_FRACTION:
45 return "PERF_SAMPLE_FRACTION";
46
47 case PERF_SAMPLE_COUNTER:
48 return "PERF_SAMPLE_COUNTER";
49
50 case PERF_COUNTER_NODATA:
51 return "PERF_COUNTER_NODATA";
52
53 case PERF_COUNTER_TIMER_INV:
54 return "PERF_COUNTER_TIMER_INV";
55
56 case PERF_SAMPLE_BASE:
57 return "PERF_SAMPLE_BASE";
58
59 case PERF_AVERAGE_TIMER:
60 return "PERF_AVERAGE_TIMER";
61
62 case PERF_AVERAGE_BASE:
63 return "PERF_AVERAGE_BASE";
64
65 case PERF_AVERAGE_BULK:
66 return "PERF_AVERAGE_BULK";
67
68 case PERF_OBJ_TIME_TIMER:
69 return "PERF_OBJ_TIME_TIMER";
70
71 case PERF_100NSEC_TIMER:
72 return "PERF_100NSEC_TIMER";
73
74 case PERF_100NSEC_TIMER_INV:
75 return "PERF_100NSEC_TIMER_INV";
76
77 case PERF_COUNTER_MULTI_TIMER:
78 return "PERF_COUNTER_MULTI_TIMER";
79
80 case PERF_COUNTER_MULTI_TIMER_INV:
81 return "PERF_COUNTER_MULTI_TIMER_INV";
82
83 case PERF_COUNTER_MULTI_BASE:
84 return "PERF_COUNTER_MULTI_BASE";
85
86 case PERF_100NSEC_MULTI_TIMER:
87 return "PERF_100NSEC_MULTI_TIMER";
88
89 case PERF_100NSEC_MULTI_TIMER_INV:
90 return "PERF_100NSEC_MULTI_TIMER_INV";
91
92 case PERF_RAW_FRACTION:
93 return "PERF_RAW_FRACTION";
94
95 case PERF_LARGE_RAW_FRACTION:
96 return "PERF_LARGE_RAW_FRACTION";
97
98 case PERF_RAW_BASE:
99 return "PERF_RAW_BASE";
100
101 case PERF_LARGE_RAW_BASE:
102 return "PERF_LARGE_RAW_BASE";
103
104 case PERF_ELAPSED_TIME:
105 return "PERF_ELAPSED_TIME";
106
107 case PERF_COUNTER_HISTOGRAM_TYPE:
108 return "PERF_COUNTER_HISTOGRAM_TYPE";
109
110 case PERF_COUNTER_DELTA:
111 return "PERF_COUNTER_DELTA";
112
113 case PERF_COUNTER_LARGE_DELTA:
114 return "PERF_COUNTER_LARGE_DELTA";
115
116 case PERF_PRECISION_SYSTEM_TIMER:
117 return "PERF_PRECISION_SYSTEM_TIMER";
118
119 case PERF_PRECISION_100NS_TIMER:
120 return "PERF_PRECISION_100NS_TIMER";
121
122 case PERF_PRECISION_OBJECT_TIMER:
123 return "PERF_PRECISION_OBJECT_TIMER";
124
125 default:
126 return "UNKNOWN_COUNTER_TYPE";
127 }
128 }
129
130 static const char *getCounterDescription(DWORD CounterType) {
131 switch (CounterType) {
132 case PERF_COUNTER_COUNTER:
133 return "32-bit Counter. Divide delta by delta time. Display suffix: \"/sec\"";
134
135 case PERF_COUNTER_TIMER:
136 return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\"";
137
138 case PERF_COUNTER_QUEUELEN_TYPE:
139 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
140 return "Queue Length Space-Time Product. Divide delta by delta time. No Display Suffix";
141
142 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
143 return "Queue Length Space-Time Product using 100 Ns timebase. Divide delta by delta time. No Display Suffix";
144
145 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
146 return "Queue Length Space-Time Product using Object specific timebase. Divide delta by delta time. No Display Suffix.";
147
148 case PERF_COUNTER_BULK_COUNT:
149 return "64-bit Counter. Divide delta by delta time. Display Suffix: \"/sec\"";
150
151 case PERF_COUNTER_TEXT:
152 return "Unicode text Display as text.";
153
154 case PERF_COUNTER_RAWCOUNT:
155 case PERF_COUNTER_LARGE_RAWCOUNT:
156 return "A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
157
158 case PERF_COUNTER_RAWCOUNT_HEX:
159 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
160 return "Special case for RAWCOUNT which should be displayed in hex. A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
161
162 case PERF_SAMPLE_FRACTION:
163 return "A count which is either 1 or 0 on each sampling interrupt (% busy). Divide delta by delta base. Display Suffix: \"%\"";
164
165 case PERF_SAMPLE_COUNTER:
166 return "A count which is sampled on each sampling interrupt (queue length). Divide delta by delta time. No Display Suffix.";
167
168 case PERF_COUNTER_NODATA:
169 return "A label: no data is associated with this counter (it has 0 length). Do not display.";
170
171 case PERF_COUNTER_TIMER_INV:
172 return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
173
174 case PERF_SAMPLE_BASE:
175 return "The divisor for a sample, used with the previous counter to form a sampled %. You must check for >0 before dividing by this! This counter will directly follow the numerator counter. It should not be displayed to the user.";
176
177 case PERF_AVERAGE_TIMER:
178 return "A timer which, when divided by an average base, produces a time in seconds which is the average time of some operation. This timer times total operations, and the base is the number of operations. Display Suffix: \"sec\"";
179
180 case PERF_AVERAGE_BASE:
181 return "Used as the denominator in the computation of time or count averages. Must directly follow the numerator counter. Not displayed to the user.";
182
183 case PERF_AVERAGE_BULK:
184 return "A bulk count which, when divided (typically) by the number of operations, gives (typically) the number of bytes per operation. No Display Suffix.";
185
186 case PERF_OBJ_TIME_TIMER:
187 return "64-bit Timer in object specific units. Display delta divided by delta time as returned in the object type header structure. Display suffix: \"%\"";
188
189 case PERF_100NSEC_TIMER:
190 return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\"";
191
192 case PERF_100NSEC_TIMER_INV:
193 return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
194
195 case PERF_COUNTER_MULTI_TIMER:
196 return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\". Timer for multiple instances, so result can exceed 100%.";
197
198 case PERF_COUNTER_MULTI_TIMER_INV:
199 return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
200
201 case PERF_COUNTER_MULTI_BASE:
202 return "Number of instances to which the preceding _MULTI_..._INV counter applies. Used as a factor to get the percentage.";
203
204 case PERF_100NSEC_MULTI_TIMER:
205 return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%.";
206
207 case PERF_100NSEC_MULTI_TIMER_INV:
208 return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
209
210 case PERF_LARGE_RAW_FRACTION:
211 case PERF_RAW_FRACTION:
212 return "Indicates the data is a fraction of the following counter which should not be time averaged on display (such as free space over total space.) Display as is. Display the quotient as \"%\"";
213
214 case PERF_RAW_BASE:
215 case PERF_LARGE_RAW_BASE:
216 return "Indicates the data is a base for the preceding counter which should not be time averaged on display (such as free space over total space.)";
217
218 case PERF_ELAPSED_TIME:
219 return "The data collected in this counter is actually the start time of the item being measured. For display, this data is subtracted from the sample time to yield the elapsed time as the difference between the two. In the definition below, the PerfTime field of the Object contains the sample time as indicated by the PERF_OBJECT_TIMER bit and the difference is scaled by the PerfFreq of the Object to convert the time units into seconds.";
220
221 case PERF_COUNTER_HISTOGRAM_TYPE:
222 return "Counter type can be used with the preceding types to define a range of values to be displayed in a histogram.";
223
224 case PERF_COUNTER_DELTA:
225 case PERF_COUNTER_LARGE_DELTA:
226 return "This counter is used to display the difference from one sample to the next. The counter value is a constantly increasing number and the value displayed is the difference between the current value and the previous value. Negative numbers are not allowed which shouldn't be a problem as long as the counter value is increasing or unchanged.";
227
228 case PERF_PRECISION_SYSTEM_TIMER:
229 return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the System Performance Timer";
230
231 case PERF_PRECISION_100NS_TIMER:
232 return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the 100 NanoSecond Timer";
233
234 case PERF_PRECISION_OBJECT_TIMER:
235 return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used is of the frequency specified in the Object header's. PerfFreq field (PerfTime is ignored)";
236
237 default:
238 return "";
239 }
240 }
241
242 static const char *getCounterAlgorithm(DWORD CounterType) {
243 switch (CounterType)
244 {
245 case PERF_COUNTER_COUNTER:
246 case PERF_SAMPLE_COUNTER:
247 case PERF_COUNTER_BULK_COUNT:
248 return "(data1 - data0) / ((time1 - time0) / frequency)";
249
250 case PERF_COUNTER_QUEUELEN_TYPE:
251 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
252 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
253 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
254 case PERF_AVERAGE_BULK: // normally not displayed
255 return "(data1 - data0) / (time1 - time0)";
256
257 case PERF_OBJ_TIME_TIMER:
258 case PERF_COUNTER_TIMER:
259 case PERF_100NSEC_TIMER:
260 case PERF_PRECISION_SYSTEM_TIMER:
261 case PERF_PRECISION_100NS_TIMER:
262 case PERF_PRECISION_OBJECT_TIMER:
263 case PERF_SAMPLE_FRACTION:
264 return "100 * (data1 - data0) / (time1 - time0)";
265
266 case PERF_COUNTER_TIMER_INV:
267 return "100 * (1 - ((data1 - data0) / (time1 - time0)))";
268
269 case PERF_100NSEC_TIMER_INV:
270 return "100 * (1- (data1 - data0) / (time1 - time0))";
271
272 case PERF_COUNTER_MULTI_TIMER:
273 return "100 * ((data1 - data0) / ((time1 - time0) / frequency1)) / multi1";
274
275 case PERF_100NSEC_MULTI_TIMER:
276 return "100 * ((data1 - data0) / (time1 - time0)) / multi1";
277
278 case PERF_COUNTER_MULTI_TIMER_INV:
279 case PERF_100NSEC_MULTI_TIMER_INV:
280 return "100 * (multi1 - ((data1 - data0) / (time1 - time0)))";
281
282 case PERF_COUNTER_RAWCOUNT:
283 case PERF_COUNTER_LARGE_RAWCOUNT:
284 return "data0";
285
286 case PERF_COUNTER_RAWCOUNT_HEX:
287 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
288 return "hex(data0)";
289
290 case PERF_COUNTER_DELTA:
291 case PERF_COUNTER_LARGE_DELTA:
292 return "data1 - data0";
293
294 case PERF_RAW_FRACTION:
295 case PERF_LARGE_RAW_FRACTION:
296 return "100 * data0 / time0";
297
298 case PERF_AVERAGE_TIMER:
299 return "((data1 - data0) / frequency1) / (time1 - time0)";
300
301 case PERF_ELAPSED_TIME:
302 return "(time0 - data0) / frequency0";
303
304 case PERF_COUNTER_TEXT:
305 case PERF_SAMPLE_BASE:
306 case PERF_AVERAGE_BASE:
307 case PERF_COUNTER_MULTI_BASE:
308 case PERF_RAW_BASE:
309 case PERF_COUNTER_NODATA:
310 case PERF_PRECISION_TIMESTAMP:
311 default:
312 return "";
313 }
314 }
315
316 void dumpSystemTime(BUFFER *wb, SYSTEMTIME *st) {
317 buffer_json_member_add_uint64(wb, "Year", st->wYear);
318 buffer_json_member_add_uint64(wb, "Month", st->wMonth);
319 buffer_json_member_add_uint64(wb, "DayOfWeek", st->wDayOfWeek);
320 buffer_json_member_add_uint64(wb, "Day", st->wDay);
321 buffer_json_member_add_uint64(wb, "Hour", st->wHour);
322 buffer_json_member_add_uint64(wb, "Minute", st->wMinute);
323 buffer_json_member_add_uint64(wb, "Second", st->wSecond);
324 buffer_json_member_add_uint64(wb, "Milliseconds", st->wMilliseconds);
325 }
326
327 bool dumpDataCb(PERF_DATA_BLOCK *pDataBlock, void *data) {
328 char name[4096];
329 if(!getSystemName(pDataBlock, name, sizeof(name)))
330 strncpyz(name, "[failed]", sizeof(name) - 1);
331
332 BUFFER *wb = data;
333 buffer_json_member_add_string(wb, "SystemName", name);
334
335 // Number of types of objects being reported
336 // Type: DWORD
337 buffer_json_member_add_int64(wb, "NumObjectTypes", pDataBlock->NumObjectTypes);
338
339 buffer_json_member_add_int64(wb, "LittleEndian", pDataBlock->LittleEndian);
340
341 // Version and Revision of these data structures.
342 // Version starts at 1.
343 // Revision starts at 0 for each Version.
344 // Type: DWORD
345 buffer_json_member_add_int64(wb, "Version", pDataBlock->Version);
346 buffer_json_member_add_int64(wb, "Revision", pDataBlock->Revision);
347
348 // Object Title Index of default object to display when data from this system is retrieved
349 // (-1 = none, but this is not expected to be used)
350 // Type: LONG
351 buffer_json_member_add_int64(wb, "DefaultObject", pDataBlock->DefaultObject);
352
353 // Performance counter frequency at the system under measurement
354 // Type: LARGE_INTEGER
355 buffer_json_member_add_int64(wb, "PerfFreq", pDataBlock->PerfFreq.QuadPart);
356
357 // Performance counter value at the system under measurement
358 // Type: LARGE_INTEGER
359 buffer_json_member_add_int64(wb, "PerfTime", pDataBlock->PerfTime.QuadPart);
360
361 // Performance counter time in 100 nsec units at the system under measurement
362 // Type: LARGE_INTEGER
363 buffer_json_member_add_int64(wb, "PerfTime100nSec", pDataBlock->PerfTime100nSec.QuadPart);
364
365 // Time at the system under measurement in UTC
366 // Type: SYSTEMTIME
367 buffer_json_member_add_object(wb, "SystemTime");
368 dumpSystemTime(wb, &pDataBlock->SystemTime);
369 buffer_json_object_close(wb);
370
371 if(pDataBlock->NumObjectTypes)
372 buffer_json_member_add_array(wb, "Objects");
373
374 return true;
375 }
376
377 static const char *GetDetailLevel(DWORD num) {
378 switch (num) {
379 case 100:
380 return "Novice (100)";
381 case 200:
382 return "Advanced (200)";
383 case 300:
384 return "Expert (300)";
385 case 400:
386 return "Wizard (400)";
387
388 default:
389 return "Unknown";
390 }
391 }
392
393 bool dumpObjectCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, void *data) {
394 (void)pDataBlock;
395 BUFFER *wb = data;
396 if(!pObjectType) {
397 buffer_json_array_close(wb); // instances or counters
398 buffer_json_object_close(wb); // objectType
399 return true;
400 }
401
402 buffer_json_add_array_item_object(wb); // objectType
403 buffer_json_member_add_int64(wb, "NameId", pObjectType->ObjectNameTitleIndex);
404 buffer_json_member_add_string(wb, "Name", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
405 buffer_json_member_add_int64(wb, "HelpId", pObjectType->ObjectHelpTitleIndex);
406 buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pObjectType->ObjectHelpTitleIndex));
407 buffer_json_member_add_int64(wb, "NumInstances", pObjectType->NumInstances);
408 buffer_json_member_add_int64(wb, "NumCounters", pObjectType->NumCounters);
409 buffer_json_member_add_int64(wb, "PerfTime", pObjectType->PerfTime.QuadPart);
410 buffer_json_member_add_int64(wb, "PerfFreq", pObjectType->PerfFreq.QuadPart);
411 buffer_json_member_add_int64(wb, "CodePage", pObjectType->CodePage);
412 buffer_json_member_add_int64(wb, "DefaultCounter", pObjectType->DefaultCounter);
413 buffer_json_member_add_string(wb, "DetailLevel", GetDetailLevel(pObjectType->DetailLevel));
414
415 if(ObjectTypeHasInstances(pDataBlock, pObjectType))
416 buffer_json_member_add_array(wb, "Instances");
417 else
418 buffer_json_member_add_array(wb, "Counters");
419
420 return true;
421 }
422
423 bool dumpInstanceCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, void *data) {
424 (void)pDataBlock;
425 BUFFER *wb = data;
426 if(!pInstance) {
427 buffer_json_array_close(wb); // counters
428 buffer_json_object_close(wb); // instance
429 return true;
430 }
431
432 char name[4096];
433 if(!getInstanceName(pDataBlock, pObjectType, pInstance, name, sizeof(name)))
434 strncpyz(name, "[failed]", sizeof(name) - 1);
435
436 buffer_json_add_array_item_object(wb);
437 buffer_json_member_add_string(wb, "Instance", name);
438 buffer_json_member_add_int64(wb, "UniqueID", pInstance->UniqueID);
439 buffer_json_member_add_array(wb, "Labels");
440 {
441 buffer_json_add_array_item_object(wb);
442 {
443 buffer_json_member_add_string(wb, "key", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
444 buffer_json_member_add_string(wb, "value", name);
445 }
446 buffer_json_object_close(wb);
447
448 if(pInstance->ParentObjectTitleIndex) {
449 PERF_INSTANCE_DEFINITION *pi = pInstance;
450 while(pi->ParentObjectTitleIndex) {
451 PERF_OBJECT_TYPE *po = getObjectTypeByIndex(pDataBlock, pInstance->ParentObjectTitleIndex);
452 pi = getInstanceByPosition(pDataBlock, po, pi->ParentObjectInstance);
453
454 if(!getInstanceName(pDataBlock, po, pi, name, sizeof(name)))
455 strncpyz(name, "[failed]", sizeof(name) - 1);
456
457 buffer_json_add_array_item_object(wb);
458 {
459 buffer_json_member_add_string(wb, "key", RegistryFindNameByID(po->ObjectNameTitleIndex));
460 buffer_json_member_add_string(wb, "value", name);
461 }
462 buffer_json_object_close(wb);
463 }
464 }
465 }
466 buffer_json_array_close(wb); // rrdlabels
467
468 buffer_json_member_add_array(wb, "Counters");
469 return true;
470 }
471
472 void dumpSample(BUFFER *wb, RAW_DATA *d) {
473 buffer_json_member_add_object(wb, "Value");
474 buffer_json_member_add_uint64(wb, "data", d->Data);
475 buffer_json_member_add_int64(wb, "time", d->Time);
476 buffer_json_member_add_uint64(wb, "type", d->CounterType);
477 buffer_json_member_add_int64(wb, "multi", d->MultiCounterData);
478 buffer_json_member_add_int64(wb, "frequency", d->Frequency);
479 buffer_json_object_close(wb);
480 }
481
482 bool dumpCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
483 (void)pDataBlock;
484 (void)pObjectType;
485 BUFFER *wb = data;
486 buffer_json_add_array_item_object(wb);
487 buffer_json_member_add_string(wb, "Counter", RegistryFindNameByID(pCounter->CounterNameTitleIndex));
488 dumpSample(wb, sample);
489 buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pCounter->CounterHelpTitleIndex));
490 buffer_json_member_add_string(wb, "Type", getCounterType(pCounter->CounterType));
491 buffer_json_member_add_string(wb, "Algorithm", getCounterAlgorithm(pCounter->CounterType));
492 buffer_json_member_add_string(wb, "Description", getCounterDescription(pCounter->CounterType));
493 buffer_json_object_close(wb);
494 return true;
495 }
496
497 bool dumpInstanceCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
498 (void)pInstance;
499 return dumpCounterCb(pDataBlock, pObjectType, pCounter, sample, data);
500 }
501
502
503 int windows_perflib_dump(const char *key) {
504 if(key && !*key)
505 key = NULL;
506
507 PerflibNamesRegistryInitialize();
508
509 DWORD id = 0;
510 if(key) {
511 id = RegistryFindIDByName(key);
512 if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
513 fprintf(stderr, "Cannot find key '%s' in Windows Performance Counters Registry.\n", key);
514 exit(1);
515 }
516 }
517
518 CLEAN_BUFFER *wb = buffer_create(0, NULL);
519 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
520
521 perflibQueryAndTraverse(id, dumpDataCb, dumpObjectCb, dumpInstanceCb, dumpInstanceCounterCb, dumpCounterCb, wb);
522
523 buffer_json_finalize(wb);
524 printf("\n%s\n", buffer_tostring(wb));
525
526 perflibFreePerformanceData();
527
528 return 0;
529 }
530
531 #endif // OS_WINDOWS