Add hyper-v metrics (#18697)
* Add hyper-v metrics * Address review comments Code cleanup * Cleanup adjust labels charts
Stelios Fragkakis committed
Nov 4, 2024 at 13:55 UTC
767229d296ecec5d2c14e7725c85de3dfaf87380
6 files changed
+1540
-2
CMakeLists.txt
+1
@@ -1526,6 +1526,7 @@ set(WINDOWS_PLUGIN_FILES
1526
src/collectors/windows.plugin/perflib-memory.c
1527
src/collectors/windows.plugin/perflib-processes.c
1528
src/collectors/windows.plugin/perflib-web-service.c
1529
+ src/collectors/windows.plugin/perflib-hyperv.c
1530
)
1531
1532
set(PROC_PLUGIN_FILES
src/collectors/all.h
+1
-1
@@ -56,7 +56,7 @@
56
#define NETDATA_CHART_PRIO_SYSTEM_PACKETS 7001 // freebsd only
57
#define NETDATA_CHART_PRIO_WINDOWS_THREADS 8001 // Windows only
58
#define NETDATA_CHART_PRIO_WINDOWS_THERMAL_ZONES 8002 // Windows only
59
-
59
+#define NETDATA_CHART_PRIO_WINDOWS_HYPERV 9000 // Windows only
60
61
// CPU per core
62
src/collectors/windows.plugin/perflib-hyperv.c
new
+1534
@@ -0,0 +1,1534 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows_plugin.h"
4
+#include "windows-internals.h"
5
+
6
+#define _COMMON_PLUGIN_NAME "windows.plugin"
7
+#define _COMMON_PLUGIN_MODULE_NAME "PerflibHyperV"
8
+#include "../common-contexts/common-contexts.h"
9
+
10
+#define HYPERV "hyperv"
11
+
12
+static long chart_priority = NETDATA_CHART_PRIO_WINDOWS_HYPERV;
13
+
14
+static void get_and_sanitize_instance_value(
15
+ PERF_DATA_BLOCK *pDataBlock,
16
+ PERF_OBJECT_TYPE *pObjectType,
17
+ PERF_INSTANCE_DEFINITION *pi,
18
+ char *buffer,
19
+ size_t buffer_size)
20
+{
21
+ // char wstr[8192];
22
+ if (!getInstanceName(pDataBlock, pObjectType, pi, buffer, sizeof(buffer_size))) {
23
+ strncpyz(buffer, "[unknown]", buffer_size - 1);
24
+ // return;
25
+ }
26
+ // rrdlabels_sanitize_value(buffer, wstr, buffer_size);
27
+}
28
+
29
+#define DICT_PERF_OPTION (DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE)
30
+
31
+#define DEFINE_RD(counter_name) RRDDIM *rd_##counter_name
32
+
33
+#define GET_INSTANCE_COUNTER(counter) \
34
+ do { \
35
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->counter); \
36
+ } while (0)
37
+
38
+#define GET_OBJECT_COUNTER(counter) \
39
+ do { \
40
+ perflibGetObjectCounter(pDataBlock, pObjectType, &p->counter); \
41
+ } while (0)
42
+
43
+#define SETP_DIM_VALUE(st, field) \
44
+ do { \
45
+ rrddim_set_by_pointer(p->st, p->rd_##field, (collected_number)p->field.current.Data); \
46
+ } while (0)
47
+
48
+typedef bool (*perf_func_collect)(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data);
49
+
50
+typedef struct {
51
+ const char *registry_name;
52
+ perf_func_collect function_collect;
53
+ dict_cb_insert_t dict_insert_cb;
54
+ size_t dict_size;
55
+ DICTIONARY *instance;
56
+} hyperv_perf_item;
57
+
58
+struct hypervisor_memory {
59
+ bool collected_metadata;
60
+ bool charts_created;
61
+
62
+ RRDSET *st_pressure;
63
+ RRDSET *st_vm_memory_physical;
64
+ RRDSET *st_vm_memory_physical_guest_visible;
65
+
66
+ DEFINE_RD(CurrentPressure);
67
+ DEFINE_RD(PhysicalMemory);
68
+ DEFINE_RD(GuestVisiblePhysicalMemory);
69
+ DEFINE_RD(GuestAvailableMemory);
70
+
71
+ COUNTER_DATA CurrentPressure;
72
+ COUNTER_DATA PhysicalMemory;
73
+ COUNTER_DATA GuestVisiblePhysicalMemory;
74
+ COUNTER_DATA GuestAvailableMemory;
75
+};
76
+
77
+void initialize_hyperv_memory_keys(struct hypervisor_memory *p) {
78
+ p->CurrentPressure.key = "Current Pressure";
79
+ p->PhysicalMemory.key = "Physical Memory";
80
+ p->GuestVisiblePhysicalMemory.key = "Guest Visible Physical Memory";
81
+ p->GuestAvailableMemory.key = "Guest Available Memory";
82
+}
83
+
84
+
85
+void dict_hyperv_memory_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
86
+ struct hypervisor_memory *p = value;
87
+ initialize_hyperv_memory_keys(p);
88
+}
89
+
90
+struct hypervisor_partition {
91
+ bool collected_metadata;
92
+ bool charts_created;
93
+
94
+ RRDSET *st_vm_vid_physical_pages_allocated;
95
+ RRDSET *st_vm_vid_remote_physical_pages;
96
+
97
+ DEFINE_RD(PhysicalPagesAllocated);
98
+ DEFINE_RD(RemotePhysicalPages);
99
+
100
+ COUNTER_DATA PhysicalPagesAllocated;
101
+ COUNTER_DATA RemotePhysicalPages;
102
+
103
+};
104
+
105
+void initialize_hyperv_partition_keys(struct hypervisor_partition *p)
106
+{
107
+ p->PhysicalPagesAllocated.key = "Physical Pages Allocated";
108
+ p->RemotePhysicalPages.key = "Remote Physical Pages";
109
+}
110
+
111
+void dict_hyperv_partition_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
112
+ struct hypervisor_partition *p = value;
113
+ initialize_hyperv_partition_keys(p);
114
+}
115
+
116
+static bool do_hyperv_memory(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
117
+{
118
+ hyperv_perf_item *item = data;
119
+
120
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
121
+ if (!pObjectType)
122
+ return false;
123
+
124
+ PERF_INSTANCE_DEFINITION *pi = NULL;
125
+ for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
126
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
127
+ if (!pi)
128
+ break;
129
+
130
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
131
+
132
+ struct hypervisor_memory *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
133
+
134
+ if(!p->collected_metadata) {
135
+ p->collected_metadata = true;
136
+ }
137
+
138
+ GET_INSTANCE_COUNTER(CurrentPressure);
139
+ GET_INSTANCE_COUNTER(PhysicalMemory);
140
+ GET_INSTANCE_COUNTER(GuestVisiblePhysicalMemory);
141
+ GET_INSTANCE_COUNTER(GuestAvailableMemory);
142
+
143
+ if (!p->charts_created) {
144
+ p->charts_created = true;
145
+ if(!p->st_vm_memory_physical) {
146
+ p->st_vm_memory_physical = rrdset_create_localhost(
147
+ "vm_memory_physical",
148
+ windows_shared_buffer,
149
+ NULL,
150
+ HYPERV,
151
+ HYPERV".vm_memory_physical",
152
+ "VM assigned memory",
153
+ "bytes",
154
+ _COMMON_PLUGIN_NAME,
155
+ _COMMON_PLUGIN_MODULE_NAME,
156
+ chart_priority++,
157
+ update_every,
158
+ RRDSET_TYPE_LINE);
159
+
160
+ p->st_vm_memory_physical_guest_visible = rrdset_create_localhost(
161
+ "vm_memory_physical_guest_visible",
162
+ windows_shared_buffer,
163
+ NULL,
164
+ HYPERV,
165
+ HYPERV".vm_memory_physical_guest_visible",
166
+ "VM guest visible memory",
167
+ "bytes",
168
+ _COMMON_PLUGIN_NAME,
169
+ _COMMON_PLUGIN_MODULE_NAME,
170
+ chart_priority++,
171
+ update_every,
172
+ RRDSET_TYPE_LINE);
173
+
174
+ p->st_pressure = rrdset_create_localhost(
175
+ "vm_memory_pressure_current",
176
+ windows_shared_buffer,
177
+ NULL,
178
+ HYPERV,
179
+ HYPERV".vm_memory_pressure_current",
180
+ "VM Memory Pressure",
181
+ "percentage",
182
+ _COMMON_PLUGIN_NAME,
183
+ _COMMON_PLUGIN_MODULE_NAME,
184
+ chart_priority++,
185
+ update_every,
186
+ RRDSET_TYPE_LINE);
187
+
188
+ p->rd_CurrentPressure = rrddim_add(p->st_pressure, "pressure", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
189
+ p->rd_PhysicalMemory = rrddim_add(p->st_vm_memory_physical, "assigned_memory", NULL, 1024 * 1024, 1, RRD_ALGORITHM_ABSOLUTE);
190
+ p->rd_GuestVisiblePhysicalMemory = rrddim_add(p->st_vm_memory_physical_guest_visible, "visible_memory", NULL, 1024 * 1024, 1, RRD_ALGORITHM_ABSOLUTE);
191
+ p->rd_GuestAvailableMemory = rrddim_add(p->st_vm_memory_physical_guest_visible, "available_memory", NULL, 1024 * 1024, 1, RRD_ALGORITHM_ABSOLUTE);
192
+
193
+ rrdlabels_add(p->st_vm_memory_physical->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
194
+ rrdlabels_add(p->st_pressure->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
195
+ rrdlabels_add(p->st_vm_memory_physical_guest_visible->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
196
+ }
197
+ }
198
+
199
+ SETP_DIM_VALUE(st_pressure, CurrentPressure);
200
+ SETP_DIM_VALUE(st_vm_memory_physical, PhysicalMemory);
201
+ SETP_DIM_VALUE(st_vm_memory_physical_guest_visible, GuestVisiblePhysicalMemory);
202
+ SETP_DIM_VALUE(st_vm_memory_physical_guest_visible, GuestAvailableMemory);
203
+
204
+ rrdset_done(p->st_pressure);
205
+ rrdset_done(p->st_vm_memory_physical);
206
+ rrdset_done(p->st_vm_memory_physical_guest_visible);
207
+ }
208
+
209
+ return true;
210
+}
211
+
212
+static bool do_hyperv_vid_partition(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
213
+{
214
+ hyperv_perf_item *item = data;
215
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
216
+ if (!pObjectType)
217
+ return false;
218
+
219
+ PERF_INSTANCE_DEFINITION *pi = NULL;
220
+ for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
221
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
222
+ if (!pi)
223
+ break;
224
+
225
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
226
+
227
+ struct hypervisor_partition *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
228
+
229
+ if(!p->collected_metadata) {
230
+
231
+ p->collected_metadata = true;
232
+ }
233
+
234
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
235
+ continue;
236
+
237
+ GET_INSTANCE_COUNTER(RemotePhysicalPages);
238
+ GET_INSTANCE_COUNTER(PhysicalPagesAllocated);
239
+
240
+ if (!p->charts_created) {
241
+ p->charts_created = true;
242
+
243
+ p->st_vm_vid_physical_pages_allocated = rrdset_create_localhost(
244
+ "vm_vid_physical_pages_allocated",
245
+ windows_shared_buffer,
246
+ NULL,
247
+ HYPERV,
248
+ HYPERV ".vm_vid_physical_pages_allocated",
249
+ "VM physical pages allocated",
250
+ "pages",
251
+ _COMMON_PLUGIN_NAME,
252
+ _COMMON_PLUGIN_MODULE_NAME,
253
+ chart_priority++,
254
+ update_every,
255
+ RRDSET_TYPE_LINE);
256
+
257
+ p->st_vm_vid_remote_physical_pages = rrdset_create_localhost(
258
+ "vm_vid_remote_physical_pages",
259
+ windows_shared_buffer,
260
+ NULL,
261
+ HYPERV,
262
+ HYPERV ".vm_vid_remote_physical_pages",
263
+ "VM physical pages not allocated from the preferred NUMA node",
264
+ "pages",
265
+ _COMMON_PLUGIN_NAME,
266
+ _COMMON_PLUGIN_MODULE_NAME,
267
+ chart_priority++,
268
+ update_every,
269
+ RRDSET_TYPE_LINE);
270
+
271
+ p->rd_PhysicalPagesAllocated = rrddim_add(p->st_vm_vid_physical_pages_allocated, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
272
+ p->rd_RemotePhysicalPages = rrddim_add(p->st_vm_vid_remote_physical_pages, "remote_physical", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
273
+
274
+ rrdlabels_add(p->st_vm_vid_physical_pages_allocated->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
275
+ rrdlabels_add(p->st_vm_vid_remote_physical_pages->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
276
+ }
277
+
278
+ SETP_DIM_VALUE(st_vm_vid_remote_physical_pages, RemotePhysicalPages);
279
+ SETP_DIM_VALUE(st_vm_vid_physical_pages_allocated, PhysicalPagesAllocated);
280
+
281
+ rrdset_done(p->st_vm_vid_physical_pages_allocated);
282
+ rrdset_done(p->st_vm_vid_remote_physical_pages);
283
+ }
284
+
285
+ return true;
286
+}
287
+
288
+// Define structure for Hyper-V Virtual Machine Health Summary
289
+static struct hypervisor_health_summary {
290
+ bool collected_metadata;
291
+ bool charts_created;
292
+
293
+ RRDSET *st_health;
294
+
295
+ DEFINE_RD(HealthCritical);
296
+ DEFINE_RD(HealthOk);
297
+
298
+ COUNTER_DATA HealthCritical;
299
+ COUNTER_DATA HealthOk;
300
+} health_summary = {
301
+ .collected_metadata = false,
302
+ .st_health = NULL,
303
+ .HealthCritical.key = "Health Critical",
304
+ .HealthOk.key = "Health Ok"};
305
+
306
+// Function to handle "Hyper-V Virtual Machine Health Summary"
307
+static bool do_hyperv_health_summary(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
308
+{
309
+ hyperv_perf_item *item = data;
310
+
311
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
312
+ if (!pObjectType)
313
+ return false;
314
+
315
+ struct hypervisor_health_summary *p = &health_summary;
316
+
317
+ GET_OBJECT_COUNTER(HealthCritical);
318
+ GET_OBJECT_COUNTER(HealthOk);
319
+
320
+ if (!p->charts_created) {
321
+ p->charts_created = true;
322
+ p->st_health = rrdset_create_localhost(
323
+ "vms_health",
324
+ windows_shared_buffer,
325
+ NULL,
326
+ HYPERV,
327
+ HYPERV ".vms_health",
328
+ "Virtual machines health status",
329
+ "vms",
330
+ _COMMON_PLUGIN_NAME,
331
+ _COMMON_PLUGIN_MODULE_NAME,
332
+ chart_priority++,
333
+ update_every,
334
+ RRDSET_TYPE_STACKED);
335
+
336
+ p->rd_HealthCritical = rrddim_add(p->st_health, "critical", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
337
+ p->rd_HealthOk = rrddim_add(p->st_health, "ok", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
338
+
339
+ rrdlabels_add(p->st_health->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
340
+ }
341
+
342
+ SETP_DIM_VALUE(st_health, HealthCritical);
343
+ SETP_DIM_VALUE(st_health, HealthOk);
344
+
345
+ rrdset_done(p->st_health);
346
+ return true;
347
+}
348
+
349
+// Define structure for Hyper-V Root Partition Metrics (Device and GPA Space Pages)
350
+struct hypervisor_root_partition {
351
+ bool collected_metadata;
352
+ bool charts_created;
353
+
354
+ RRDSET *st_device_space_pages;
355
+ RRDSET *st_gpa_space_pages;
356
+ RRDSET *st_gpa_space_modifications;
357
+ RRDSET *st_attached_devices;
358
+ RRDSET *st_deposited_pages;
359
+
360
+ RRDSET *st_DeviceDMAErrors;
361
+ RRDSET *st_DeviceInterruptErrors;
362
+ RRDSET *st_DeviceInterruptThrottleEvents;
363
+ RRDSET *st_IOΤLBFlushesSec;
364
+ RRDSET *st_AddressSpaces;
365
+ RRDSET *st_VirtualTLBPages;
366
+ RRDSET *st_VirtualTLBFlushEntiresSec;
367
+
368
+ DEFINE_RD(DeviceSpacePages4K);
369
+ DEFINE_RD(DeviceSpacePages2M);
370
+ DEFINE_RD(DeviceSpacePages1G);
371
+ DEFINE_RD(GPASpacePages4K);
372
+ DEFINE_RD(GPASpacePages2M);
373
+ DEFINE_RD(GPASpacePages1G);
374
+ DEFINE_RD(GPASpaceModifications);
375
+
376
+ DEFINE_RD(AttachedDevices);
377
+ DEFINE_RD(DepositedPages);
378
+
379
+ DEFINE_RD(DeviceDMAErrors);
380
+ DEFINE_RD(DeviceInterruptErrors);
381
+ DEFINE_RD(DeviceInterruptThrottleEvents);
382
+ DEFINE_RD(IOΤLBFlushesSec);
383
+ DEFINE_RD(AddressSpaces);
384
+ DEFINE_RD(VirtualTLBPages);
385
+ DEFINE_RD(VirtualTLBFlushEntiresSec);
386
+
387
+ COUNTER_DATA DeviceSpacePages4K;
388
+ COUNTER_DATA DeviceSpacePages2M;
389
+ COUNTER_DATA DeviceSpacePages1G;
390
+ COUNTER_DATA GPASpacePages4K;
391
+ COUNTER_DATA GPASpacePages2M;
392
+ COUNTER_DATA GPASpacePages1G;
393
+ COUNTER_DATA GPASpaceModifications;
394
+ COUNTER_DATA AttachedDevices;
395
+ COUNTER_DATA DepositedPages;
396
+ COUNTER_DATA DeviceDMAErrors;
397
+ COUNTER_DATA DeviceInterruptErrors;
398
+ COUNTER_DATA DeviceInterruptThrottleEvents;
399
+ COUNTER_DATA IOΤLBFlushesSec;
400
+ COUNTER_DATA AddressSpaces;
401
+ COUNTER_DATA VirtualTLBPages;
402
+ COUNTER_DATA VirtualTLBFlushEntiresSec;
403
+};
404
+
405
+// Initialize the keys for the root partition metrics
406
+void initialize_hyperv_root_partition_keys(struct hypervisor_root_partition *p) {
407
+ p->DeviceSpacePages4K.key = "4K device pages";
408
+ p->DeviceSpacePages2M.key = "2M device pages";
409
+ p->DeviceSpacePages1G.key = "1G device pages";
410
+
411
+ p->GPASpacePages4K.key = "4K GPA pages";
412
+ p->GPASpacePages2M.key = "2M GPA pages";
413
+ p->GPASpacePages1G.key = "1G GPA pages";
414
+
415
+ p->GPASpaceModifications.key = "GPA Space Modifications/sec";
416
+ p->AttachedDevices.key = "Attached Devices";
417
+ p->DepositedPages.key = "Deposited Pages";
418
+
419
+ p->DeviceDMAErrors.key = "Device DMA Errors";
420
+ p->DeviceInterruptErrors.key = "Device Interrupt Errors";
421
+ p->DeviceInterruptThrottleEvents.key = "Device Interrupt Throttle Events";
422
+ p->IOΤLBFlushesSec.key = "I/O TLB Flushes/sec";
423
+ p->AddressSpaces.key = "Address Spaces";
424
+ p->VirtualTLBPages.key = "Virtual TLB Pages";
425
+ p->VirtualTLBFlushEntiresSec.key = "Virtual TLB Flush Entires/sec";
426
+}
427
+
428
+// Callback function for inserting root partition metrics into the dictionary
429
+void dict_hyperv_root_partition_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
430
+ struct hypervisor_root_partition *p = value;
431
+ initialize_hyperv_root_partition_keys(p);
432
+}
433
+
434
+// Function to handle "Hyper-V Hypervisor Root Partition" metrics (Device Space and GPA Space)
435
+static bool do_hyperv_root_partition(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
436
+{
437
+ hyperv_perf_item *item = data;
438
+
439
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
440
+ if (!pObjectType)
441
+ return false;
442
+
443
+ PERF_INSTANCE_DEFINITION *pi = NULL;
444
+ for (LONG i = 0; i < pObjectType->NumInstances; i++) {
445
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
446
+ if (!pi)
447
+ break;
448
+
449
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
450
+
451
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
452
+ continue;
453
+
454
+ struct hypervisor_root_partition *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
455
+
456
+ if (!p->collected_metadata) {
457
+ p->collected_metadata = true;
458
+ }
459
+
460
+ // Fetch counters
461
+ GET_INSTANCE_COUNTER(DeviceSpacePages4K);
462
+ GET_INSTANCE_COUNTER(DeviceSpacePages2M);
463
+ GET_INSTANCE_COUNTER(DeviceSpacePages1G);
464
+ GET_INSTANCE_COUNTER(GPASpacePages4K);
465
+ GET_INSTANCE_COUNTER(GPASpacePages2M);
466
+ GET_INSTANCE_COUNTER(GPASpacePages1G);
467
+ GET_INSTANCE_COUNTER(GPASpaceModifications);
468
+ GET_INSTANCE_COUNTER(AttachedDevices);
469
+ GET_INSTANCE_COUNTER(DepositedPages);
470
+
471
+ GET_INSTANCE_COUNTER(DeviceDMAErrors);
472
+ GET_INSTANCE_COUNTER(DeviceInterruptErrors);
473
+ GET_INSTANCE_COUNTER(DeviceInterruptThrottleEvents);
474
+ GET_INSTANCE_COUNTER(IOΤLBFlushesSec);
475
+ GET_INSTANCE_COUNTER(AddressSpaces);
476
+ GET_INSTANCE_COUNTER(VirtualTLBPages);
477
+ GET_INSTANCE_COUNTER(VirtualTLBFlushEntiresSec);
478
+
479
+
480
+ // Create charts
481
+ if (!p->charts_created) {
482
+ p->charts_created = true;
483
+ p->st_device_space_pages = rrdset_create_localhost(
484
+ "root_partition_device_space_pages",
485
+ windows_shared_buffer,
486
+ NULL,
487
+ HYPERV,
488
+ HYPERV ".root_partition_device_space_pages",
489
+ "Root partition device space pages",
490
+ "pages",
491
+ _COMMON_PLUGIN_NAME,
492
+ _COMMON_PLUGIN_MODULE_NAME,
493
+ chart_priority++,
494
+ update_every,
495
+ RRDSET_TYPE_LINE);
496
+
497
+ p->rd_DeviceSpacePages4K = rrddim_add(p->st_device_space_pages, "4K", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
498
+ p->rd_DeviceSpacePages2M = rrddim_add(p->st_device_space_pages, "2M", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
499
+ p->rd_DeviceSpacePages1G = rrddim_add(p->st_device_space_pages, "1G", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
500
+ rrdlabels_add(p->st_device_space_pages->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
501
+
502
+ p->st_gpa_space_pages = rrdset_create_localhost(
503
+ "root_partition_gpa_space_pages",
504
+ windows_shared_buffer,
505
+ NULL,
506
+ HYPERV,
507
+ HYPERV ".root_partition_gpa_space_pages",
508
+ "Root partition GPA space pages",
509
+ "pages",
510
+ _COMMON_PLUGIN_NAME,
511
+ _COMMON_PLUGIN_MODULE_NAME,
512
+ chart_priority++,
513
+ update_every,
514
+ RRDSET_TYPE_LINE);
515
+
516
+ p->rd_GPASpacePages4K = rrddim_add(p->st_gpa_space_pages, "4K", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
517
+ p->rd_GPASpacePages2M = rrddim_add(p->st_gpa_space_pages, "2M", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
518
+ p->rd_GPASpacePages1G = rrddim_add(p->st_gpa_space_pages, "1G", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
519
+ rrdlabels_add(p->st_gpa_space_pages->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
520
+
521
+ p->st_gpa_space_modifications = rrdset_create_localhost(
522
+ "root_partition_gpa_space_modifications",
523
+ windows_shared_buffer,
524
+ NULL,
525
+ HYPERV,
526
+ HYPERV ".root_partition_gpa_space_modifications",
527
+ "Root partition GPA space modifications",
528
+ "modifications/s",
529
+ _COMMON_PLUGIN_NAME,
530
+ _COMMON_PLUGIN_MODULE_NAME,
531
+ chart_priority++,
532
+ update_every,
533
+ RRDSET_TYPE_LINE);
534
+
535
+ p->rd_GPASpaceModifications =
536
+ rrddim_add(p->st_gpa_space_modifications, "gpa", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
537
+ rrdlabels_add(p->st_gpa_space_modifications->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
538
+
539
+ p->st_attached_devices = rrdset_create_localhost(
540
+ "root_partition_attached_devices",
541
+ windows_shared_buffer,
542
+ NULL,
543
+ HYPERV,
544
+ HYPERV ".root_partition_attached_devices",
545
+ "Root partition attached devices",
546
+ "devices",
547
+ _COMMON_PLUGIN_NAME,
548
+ _COMMON_PLUGIN_MODULE_NAME,
549
+ chart_priority++,
550
+ update_every,
551
+ RRDSET_TYPE_LINE);
552
+
553
+ p->rd_AttachedDevices = rrddim_add(p->st_attached_devices, "attached", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
554
+ rrdlabels_add(p->st_attached_devices->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
555
+
556
+ p->st_deposited_pages = rrdset_create_localhost(
557
+ "root_partition_deposited_pages",
558
+ windows_shared_buffer,
559
+ NULL,
560
+ HYPERV,
561
+ HYPERV ".root_partition_deposited_pages",
562
+ "Root partition deposited pages",
563
+ "pages",
564
+ _COMMON_PLUGIN_NAME,
565
+ _COMMON_PLUGIN_MODULE_NAME,
566
+ chart_priority++,
567
+ update_every,
568
+ RRDSET_TYPE_LINE);
569
+
570
+ p->rd_DepositedPages = rrddim_add(p->st_deposited_pages, "gpa", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
571
+ rrdlabels_add(p->st_deposited_pages->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
572
+
573
+ p->st_DeviceDMAErrors = rrdset_create_localhost(
574
+ "root_partition_device_dma_errors",
575
+ windows_shared_buffer,
576
+ NULL,
577
+ HYPERV,
578
+ HYPERV ".root_partition_device_dma_errors",
579
+ "Root partition illegal DMA requests",
580
+ "requests",
581
+ _COMMON_PLUGIN_NAME,
582
+ _COMMON_PLUGIN_MODULE_NAME,
583
+ chart_priority++,
584
+ update_every,
585
+ RRDSET_TYPE_LINE);
586
+
587
+ p->rd_DeviceDMAErrors =
588
+ rrddim_add(p->st_DeviceDMAErrors, "illegal_dma", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
589
+ rrdlabels_add(p->st_DeviceDMAErrors->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
590
+
591
+ p->st_DeviceInterruptErrors = rrdset_create_localhost(
592
+ "root_partition_device_interrupt_errors",
593
+ windows_shared_buffer,
594
+ NULL,
595
+ HYPERV,
596
+ HYPERV ".root_partition_device_interrupt_errors",
597
+ "Root partition illegal interrupt requestss",
598
+ "requests",
599
+ _COMMON_PLUGIN_NAME,
600
+ _COMMON_PLUGIN_MODULE_NAME,
601
+ chart_priority++,
602
+ update_every,
603
+ RRDSET_TYPE_LINE);
604
+
605
+ p->rd_DeviceInterruptErrors =
606
+ rrddim_add(p->st_DeviceInterruptErrors, "illegal_interrupt", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
607
+ rrdlabels_add(p->st_DeviceInterruptErrors->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
608
+
609
+ p->st_DeviceInterruptThrottleEvents = rrdset_create_localhost(
610
+ "root_partition_device_interrupt_throttle_events",
611
+ windows_shared_buffer,
612
+ NULL,
613
+ HYPERV,
614
+ HYPERV ".root_partition_device_interrupt_throttle_events",
615
+ "Root partition throttled interrupts",
616
+ "events",
617
+ _COMMON_PLUGIN_NAME,
618
+ _COMMON_PLUGIN_MODULE_NAME,
619
+ chart_priority++,
620
+ update_every,
621
+ RRDSET_TYPE_LINE);
622
+
623
+ p->rd_DeviceInterruptThrottleEvents =
624
+ rrddim_add(p->st_DeviceInterruptThrottleEvents, "throttling", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
625
+ rrdlabels_add(
626
+ p->st_DeviceInterruptThrottleEvents->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
627
+
628
+ p->st_IOΤLBFlushesSec = rrdset_create_localhost(
629
+ "root_partition_io_tlb_flush",
630
+ windows_shared_buffer,
631
+ NULL,
632
+ HYPERV,
633
+ HYPERV ".root_partition_io_tlb_flush",
634
+ "Root partition flushes of I/O TLBs",
635
+ "flushes/s",
636
+ _COMMON_PLUGIN_NAME,
637
+ _COMMON_PLUGIN_MODULE_NAME,
638
+ chart_priority++,
639
+ update_every,
640
+ RRDSET_TYPE_LINE);
641
+
642
+ p->rd_IOΤLBFlushesSec = rrddim_add(p->st_IOΤLBFlushesSec, "gpa", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
643
+ rrdlabels_add(p->st_IOΤLBFlushesSec->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
644
+
645
+ p->st_AddressSpaces = rrdset_create_localhost(
646
+ "root_partition_address_space",
647
+ windows_shared_buffer,
648
+ NULL,
649
+ HYPERV,
650
+ HYPERV ".root_partition_address_space",
651
+ "Root partition address spaces in the virtual TLB",
652
+ "address spaces",
653
+ _COMMON_PLUGIN_NAME,
654
+ _COMMON_PLUGIN_MODULE_NAME,
655
+ chart_priority++,
656
+ update_every,
657
+ RRDSET_TYPE_LINE);
658
+
659
+ p->rd_AddressSpaces = rrddim_add(p->st_AddressSpaces, "address_spaces", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
660
+ rrdlabels_add(p->st_AddressSpaces->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
661
+
662
+ p->st_VirtualTLBPages = rrdset_create_localhost(
663
+ "root_partition_virtual_tlb_pages",
664
+ windows_shared_buffer,
665
+ NULL,
666
+ HYPERV,
667
+ HYPERV ".root_partition_virtual_tlb_pages",
668
+ "Root partition pages used by the virtual TLB",
669
+ "pages",
670
+ _COMMON_PLUGIN_NAME,
671
+ _COMMON_PLUGIN_MODULE_NAME,
672
+ chart_priority++,
673
+ update_every,
674
+ RRDSET_TYPE_LINE);
675
+
676
+ p->rd_VirtualTLBPages = rrddim_add(p->st_VirtualTLBPages, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
677
+ rrdlabels_add(p->st_VirtualTLBPages->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
678
+
679
+ p->st_VirtualTLBFlushEntiresSec = rrdset_create_localhost(
680
+ "root_partition_virtual_tlb_flush_entries",
681
+ windows_shared_buffer,
682
+ NULL,
683
+ HYPERV,
684
+ HYPERV ".root_partition_virtual_tlb_flush_entries",
685
+ "Root partition flushes of the entire virtual TLB",
686
+ "flushes/s",
687
+ _COMMON_PLUGIN_NAME,
688
+ _COMMON_PLUGIN_MODULE_NAME,
689
+ chart_priority++,
690
+ update_every,
691
+ RRDSET_TYPE_LINE);
692
+
693
+ p->rd_VirtualTLBFlushEntiresSec =
694
+ rrddim_add(p->st_VirtualTLBFlushEntiresSec, "flushes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
695
+ rrdlabels_add(p->st_VirtualTLBFlushEntiresSec->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
696
+ }
697
+
698
+ // Set the data for each dimension
699
+
700
+ SETP_DIM_VALUE(st_device_space_pages,DeviceSpacePages4K);
701
+ SETP_DIM_VALUE(st_device_space_pages,DeviceSpacePages2M);
702
+ SETP_DIM_VALUE(st_device_space_pages,DeviceSpacePages1G);
703
+
704
+ SETP_DIM_VALUE(st_gpa_space_pages, GPASpacePages4K);
705
+ SETP_DIM_VALUE(st_gpa_space_pages, GPASpacePages2M);
706
+ SETP_DIM_VALUE(st_gpa_space_pages, GPASpacePages1G);
707
+
708
+ SETP_DIM_VALUE(st_gpa_space_modifications, GPASpaceModifications);
709
+
710
+ SETP_DIM_VALUE(st_attached_devices, AttachedDevices);
711
+ SETP_DIM_VALUE(st_deposited_pages, DepositedPages);
712
+
713
+ SETP_DIM_VALUE(st_DeviceDMAErrors, DeviceDMAErrors);
714
+ SETP_DIM_VALUE(st_DeviceInterruptErrors, DeviceInterruptErrors);
715
+ SETP_DIM_VALUE(st_DeviceInterruptThrottleEvents, DeviceInterruptThrottleEvents);
716
+ SETP_DIM_VALUE(st_IOΤLBFlushesSec, IOΤLBFlushesSec);
717
+ SETP_DIM_VALUE(st_AddressSpaces, AddressSpaces);
718
+ SETP_DIM_VALUE(st_VirtualTLBPages, VirtualTLBPages);
719
+ SETP_DIM_VALUE(st_VirtualTLBFlushEntiresSec, VirtualTLBFlushEntiresSec);
720
+
721
+ // Mark the charts as done
722
+ rrdset_done(p->st_device_space_pages);
723
+ rrdset_done(p->st_gpa_space_pages);
724
+ rrdset_done(p->st_gpa_space_modifications);
725
+ rrdset_done(p->st_attached_devices);
726
+ rrdset_done(p->st_deposited_pages);
727
+ rrdset_done(p->st_DeviceInterruptErrors);
728
+ rrdset_done(p->st_DeviceInterruptThrottleEvents);
729
+ rrdset_done(p->st_IOΤLBFlushesSec);
730
+ rrdset_done(p->st_AddressSpaces);
731
+ rrdset_done(p->st_DeviceDMAErrors);
732
+ rrdset_done(p->st_VirtualTLBPages);
733
+ rrdset_done(p->st_VirtualTLBFlushEntiresSec);
734
+ }
735
+
736
+ return true;
737
+}
738
+
739
+// Storage DEVICE
740
+
741
+struct hypervisor_storage_device {
742
+ bool collected_metadata;
743
+ bool charts_created;
744
+
745
+ RRDSET *st_operations;
746
+ DEFINE_RD(ReadOperationsSec);
747
+ DEFINE_RD(WriteOperationsSec);
748
+
749
+ RRDSET *st_bytes;
750
+ DEFINE_RD(ReadBytesSec);
751
+ DEFINE_RD(WriteBytesSec);
752
+
753
+ RRDSET *st_errors;
754
+ DEFINE_RD(ErrorCount);
755
+
756
+ COUNTER_DATA ReadOperationsSec;
757
+ COUNTER_DATA WriteOperationsSec;
758
+
759
+ COUNTER_DATA ReadBytesSec;
760
+ COUNTER_DATA WriteBytesSec;
761
+ COUNTER_DATA ErrorCount;
762
+};
763
+
764
+
765
+// Initialize the keys for the root partition metrics
766
+void initialize_hyperv_storage_device_keys(struct hypervisor_storage_device *p) {
767
+ p->ReadOperationsSec.key = "Read Operations/Sec";
768
+ p->WriteOperationsSec.key = "Write Operations/Sec";
769
+
770
+ p->ReadBytesSec.key = "Read Bytes/sec";
771
+ p->WriteBytesSec.key = "Write Bytes/sec";
772
+ p->ErrorCount.key = "Error Count";
773
+}
774
+
775
+// Callback function for inserting root partition metrics into the dictionary
776
+void dict_hyperv_storage_device_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
777
+ struct hypervisor_storage_device *p = value;
778
+ initialize_hyperv_storage_device_keys(p);
779
+}
780
+
781
+static bool do_hyperv_storage_device(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
782
+{
783
+ hyperv_perf_item *item = data;
784
+
785
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
786
+ if (!pObjectType)
787
+ return false;
788
+
789
+
790
+ PERF_INSTANCE_DEFINITION *pi = NULL;
791
+ for (LONG i = 0; i < pObjectType->NumInstances; i++) {
792
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
793
+ if (!pi)
794
+ break;
795
+
796
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
797
+
798
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
799
+ continue;
800
+
801
+ struct hypervisor_storage_device *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
802
+
803
+ if (!p->collected_metadata) {
804
+ p->collected_metadata = true;
805
+ }
806
+
807
+ // Fetch counters
808
+ GET_INSTANCE_COUNTER(ReadOperationsSec);
809
+ GET_INSTANCE_COUNTER(WriteOperationsSec);
810
+
811
+ GET_INSTANCE_COUNTER(ReadBytesSec);
812
+ GET_INSTANCE_COUNTER(WriteBytesSec);
813
+ GET_INSTANCE_COUNTER(ErrorCount);
814
+
815
+ if (!p->charts_created) {
816
+ p->charts_created = true;
817
+ if (!p->st_operations) {
818
+ p->st_operations = rrdset_create_localhost(
819
+ "vm_storage_device_operations",
820
+ windows_shared_buffer,
821
+ NULL,
822
+ HYPERV,
823
+ HYPERV".vm_storage_device_operations",
824
+ "VM storage device IOPS",
825
+ "operations/sec",
826
+ _COMMON_PLUGIN_NAME,
827
+ _COMMON_PLUGIN_MODULE_NAME,
828
+ chart_priority++,
829
+ update_every,
830
+ RRDSET_TYPE_LINE);
831
+
832
+ p->rd_ReadOperationsSec = rrddim_add(p->st_operations, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
833
+ p->rd_WriteOperationsSec = rrddim_add(p->st_operations, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
834
+
835
+ rrdlabels_add(p->st_operations->rrdlabels, "vm_storage_device", windows_shared_buffer, RRDLABEL_SRC_AUTO);
836
+ }
837
+
838
+ if (!p->st_bytes) {
839
+ p->st_bytes = rrdset_create_localhost(
840
+ "vm_storage_device_bytes",
841
+ windows_shared_buffer,
842
+ NULL,
843
+ HYPERV,
844
+ HYPERV".vm_storage_device_bytes",
845
+ "VM storage device IO",
846
+ "bytes/sec",
847
+ _COMMON_PLUGIN_NAME,
848
+ _COMMON_PLUGIN_MODULE_NAME,
849
+ chart_priority++,
850
+ update_every,
851
+ RRDSET_TYPE_AREA);
852
+
853
+ p->rd_ReadBytesSec = rrddim_add(p->st_bytes, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
854
+ p->rd_WriteBytesSec = rrddim_add(p->st_bytes, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
855
+
856
+ rrdlabels_add(p->st_bytes->rrdlabels, "vm_storage_device", windows_shared_buffer, RRDLABEL_SRC_AUTO);
857
+ }
858
+
859
+ if (!p->st_errors) {
860
+ p->st_errors = rrdset_create_localhost(
861
+ "vm_storage_device_errors",
862
+ windows_shared_buffer,
863
+ NULL,
864
+ HYPERV,
865
+ HYPERV".vm_storage_device_errors",
866
+ "VM storage device errors",
867
+ "errors/sec",
868
+ _COMMON_PLUGIN_NAME,
869
+ _COMMON_PLUGIN_MODULE_NAME,
870
+ chart_priority++,
871
+ update_every,
872
+ RRDSET_TYPE_LINE);
873
+
874
+ p->rd_ErrorCount = rrddim_add(p->st_errors, "errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
875
+
876
+ rrdlabels_add(p->st_errors->rrdlabels, "vm_storage_device", windows_shared_buffer, RRDLABEL_SRC_AUTO);
877
+ }
878
+ }
879
+
880
+ SETP_DIM_VALUE(st_operations,ReadOperationsSec);
881
+ SETP_DIM_VALUE(st_operations,WriteOperationsSec);
882
+
883
+ SETP_DIM_VALUE(st_bytes,ReadBytesSec);
884
+ SETP_DIM_VALUE(st_bytes,WriteBytesSec);
885
+
886
+ SETP_DIM_VALUE(st_errors,ErrorCount);
887
+
888
+ // Mark the charts as done
889
+ rrdset_done(p->st_operations);
890
+ rrdset_done(p->st_bytes);
891
+ rrdset_done(p->st_errors);
892
+ }
893
+
894
+ return true;
895
+}
896
+
897
+struct hypervisor_switch {
898
+ bool collected_metadata;
899
+ bool charts_created;
900
+
901
+ RRDSET *st_bytes;
902
+ DEFINE_RD(BytesSentSec);
903
+ DEFINE_RD(BytesReceivedSec);
904
+
905
+ RRDSET *st_packets;
906
+ DEFINE_RD(PacketsSentSec);
907
+ DEFINE_RD(PacketsReceivedSec);
908
+
909
+ RRDSET *st_directed_packets;
910
+ DEFINE_RD(DirectedPacketsSentSec);
911
+ DEFINE_RD(DirectedPacketsReceivedSec);
912
+
913
+ RRDSET *st_broadcast_packets;
914
+ DEFINE_RD(BroadcastPacketsSentSec);
915
+ DEFINE_RD(BroadcastPacketsReceivedSec);
916
+
917
+ RRDSET *st_multicast_packets;
918
+ DEFINE_RD(MulticastPacketsSentSec);
919
+ DEFINE_RD(MulticastPacketsReceivedSec);
920
+
921
+ RRDSET *st_dropped_packets;
922
+ DEFINE_RD(DroppedPacketsOutgoingSec);
923
+ DEFINE_RD(DroppedPacketsIncomingSec);
924
+
925
+ RRDSET *st_ext_dropped_packets;
926
+ DEFINE_RD(ExtensionsDroppedPacketsOutgoingSec);
927
+ DEFINE_RD(ExtensionsDroppedPacketsIncomingSec);
928
+
929
+ RRDSET *st_flooded;
930
+ DEFINE_RD(PacketsFlooded);
931
+
932
+ RRDSET *st_learned_mac;
933
+ DEFINE_RD(LearnedMacAddresses);
934
+
935
+ RRDSET *st_purged_mac;
936
+ DEFINE_RD(PurgedMacAddresses);
937
+
938
+ COUNTER_DATA BytesSentSec;
939
+ COUNTER_DATA BytesReceivedSec;
940
+
941
+ COUNTER_DATA PacketsSentSec;
942
+ COUNTER_DATA PacketsReceivedSec;
943
+
944
+ COUNTER_DATA DirectedPacketsSentSec;
945
+ COUNTER_DATA DirectedPacketsReceivedSec;
946
+
947
+ COUNTER_DATA BroadcastPacketsSentSec;
948
+ COUNTER_DATA BroadcastPacketsReceivedSec;
949
+
950
+ COUNTER_DATA MulticastPacketsSentSec;
951
+ COUNTER_DATA MulticastPacketsReceivedSec;
952
+
953
+ COUNTER_DATA DroppedPacketsOutgoingSec;
954
+ COUNTER_DATA DroppedPacketsIncomingSec;
955
+
956
+ COUNTER_DATA ExtensionsDroppedPacketsOutgoingSec;
957
+ COUNTER_DATA ExtensionsDroppedPacketsIncomingSec;
958
+
959
+ COUNTER_DATA PacketsFlooded;
960
+
961
+ COUNTER_DATA LearnedMacAddresses;
962
+
963
+ COUNTER_DATA PurgedMacAddresses;
964
+};
965
+
966
+// Initialize the keys for the root partition metrics
967
+void initialize_hyperv_switch_keys(struct hypervisor_switch *p)
968
+{
969
+ p->BytesSentSec.key = "Bytes Sent/sec";
970
+ p->BytesReceivedSec.key = "Bytes Received/sec";
971
+ p->PacketsSentSec.key = "Packets Sent/sec";
972
+ p->PacketsReceivedSec.key = "Packets Received/sec";
973
+
974
+ p->DirectedPacketsSentSec.key = "Directed Packets Sent/sec";
975
+ p->DirectedPacketsReceivedSec.key = "Directed Packets Received/sec";
976
+ p->BroadcastPacketsSentSec.key = "Broadcast Packets Sent/sec";
977
+ p->BroadcastPacketsReceivedSec.key = "Broadcast Packets Received/sec";
978
+ p->MulticastPacketsSentSec.key = "Multicast Packets Sent/sec";
979
+ p->MulticastPacketsReceivedSec.key = "Multicast Packets Received/sec";
980
+ p->DroppedPacketsOutgoingSec.key = "Dropped Packets Outgoing/sec";
981
+ p->DroppedPacketsIncomingSec.key = "Dropped Packets Incoming/sec";
982
+ p->ExtensionsDroppedPacketsOutgoingSec.key = "Extensions Dropped Packets Outgoing/sec";
983
+ p->ExtensionsDroppedPacketsIncomingSec.key = "Extensions Dropped Packets Incoming/sec";
984
+ p->PacketsFlooded.key = "Packets Flooded";
985
+ p->LearnedMacAddresses.key = "Learned Mac Addresses";
986
+ p->PurgedMacAddresses.key = "Purged Mac Addresses";
987
+}
988
+
989
+void dict_hyperv_switch_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
990
+{
991
+ struct hypervisor_switch *p = value;
992
+ initialize_hyperv_switch_keys(p);
993
+}
994
+
995
+static bool do_hyperv_switch(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
996
+{
997
+ hyperv_perf_item *item = data;
998
+
999
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
1000
+ if (!pObjectType)
1001
+ return false;
1002
+
1003
+ PERF_INSTANCE_DEFINITION *pi = NULL;
1004
+ for (LONG i = 0; i < pObjectType->NumInstances; i++) {
1005
+ static bool charts_created = false;
1006
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
1007
+ if (!pi)
1008
+ break;
1009
+
1010
+ get_and_sanitize_instance_value(
1011
+ pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
1012
+
1013
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
1014
+ continue;
1015
+
1016
+ struct hypervisor_switch *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
1017
+
1018
+ if (!p->collected_metadata) {
1019
+ p->collected_metadata = true;
1020
+ }
1021
+
1022
+ GET_INSTANCE_COUNTER(BytesReceivedSec);
1023
+ GET_INSTANCE_COUNTER(BytesSentSec);
1024
+
1025
+ GET_INSTANCE_COUNTER(PacketsReceivedSec);
1026
+ GET_INSTANCE_COUNTER(PacketsSentSec);
1027
+
1028
+ GET_INSTANCE_COUNTER(DirectedPacketsSentSec);
1029
+ GET_INSTANCE_COUNTER(DirectedPacketsReceivedSec);
1030
+
1031
+ GET_INSTANCE_COUNTER(BroadcastPacketsSentSec);
1032
+ GET_INSTANCE_COUNTER(BroadcastPacketsReceivedSec);
1033
+
1034
+ GET_INSTANCE_COUNTER(MulticastPacketsSentSec);
1035
+ GET_INSTANCE_COUNTER(MulticastPacketsReceivedSec);
1036
+
1037
+ GET_INSTANCE_COUNTER(DroppedPacketsOutgoingSec);
1038
+ GET_INSTANCE_COUNTER(DroppedPacketsIncomingSec);
1039
+
1040
+ GET_INSTANCE_COUNTER(ExtensionsDroppedPacketsOutgoingSec);
1041
+ GET_INSTANCE_COUNTER(ExtensionsDroppedPacketsIncomingSec);
1042
+
1043
+ GET_INSTANCE_COUNTER(PacketsFlooded);
1044
+
1045
+ GET_INSTANCE_COUNTER(LearnedMacAddresses);
1046
+
1047
+ GET_INSTANCE_COUNTER(PurgedMacAddresses);
1048
+
1049
+ if (!p->charts_created) {
1050
+ p->charts_created = true;
1051
+
1052
+ p->st_bytes = rrdset_create_localhost(
1053
+ "vswitch_bytes",
1054
+ windows_shared_buffer,
1055
+ NULL,
1056
+ HYPERV,
1057
+ HYPERV ".vswitch_bytes",
1058
+ "Virtual switch traffic",
1059
+ "bytes/sec",
1060
+ _COMMON_PLUGIN_NAME,
1061
+ _COMMON_PLUGIN_MODULE_NAME,
1062
+ chart_priority++,
1063
+ update_every,
1064
+ RRDSET_TYPE_LINE);
1065
+
1066
+ p->rd_BytesReceivedSec = rrddim_add(p->st_bytes, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1067
+ p->rd_BytesSentSec = rrddim_add(p->st_bytes, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1068
+ rrdlabels_add(p->st_bytes->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1069
+
1070
+ p->st_packets = rrdset_create_localhost(
1071
+ "vswitch_packets",
1072
+ windows_shared_buffer,
1073
+ NULL,
1074
+ HYPERV,
1075
+ HYPERV ".vswitch_packets",
1076
+ "Virtual switch packets",
1077
+ "packets/sec",
1078
+ _COMMON_PLUGIN_NAME,
1079
+ _COMMON_PLUGIN_MODULE_NAME,
1080
+ chart_priority++,
1081
+ update_every,
1082
+ RRDSET_TYPE_LINE);
1083
+
1084
+ p->rd_PacketsReceivedSec = rrddim_add(p->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1085
+ p->rd_PacketsSentSec = rrddim_add(p->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1086
+ rrdlabels_add(p->st_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1087
+
1088
+ p->st_directed_packets = rrdset_create_localhost(
1089
+ "vswitch_directed_packets",
1090
+ windows_shared_buffer,
1091
+ NULL,
1092
+ HYPERV,
1093
+ HYPERV ".vswitch_directed_packets",
1094
+ "Virtual switch directed packets",
1095
+ "packets/sec",
1096
+ _COMMON_PLUGIN_NAME,
1097
+ _COMMON_PLUGIN_MODULE_NAME,
1098
+ chart_priority++,
1099
+ update_every,
1100
+ RRDSET_TYPE_LINE);
1101
+
1102
+ p->rd_DirectedPacketsReceivedSec =
1103
+ rrddim_add(p->st_directed_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1104
+ p->rd_DirectedPacketsSentSec =
1105
+ rrddim_add(p->st_directed_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1106
+ rrdlabels_add(p->st_directed_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1107
+
1108
+ p->st_broadcast_packets = rrdset_create_localhost(
1109
+ "vswitch_broadcast_packets",
1110
+ windows_shared_buffer,
1111
+ NULL,
1112
+ HYPERV,
1113
+ HYPERV ".vswitch_broadcast_packets",
1114
+ "Virtual switch broadcast packets",
1115
+ "packets/sec",
1116
+ _COMMON_PLUGIN_NAME,
1117
+ _COMMON_PLUGIN_MODULE_NAME,
1118
+ chart_priority++,
1119
+ update_every,
1120
+ RRDSET_TYPE_LINE);
1121
+
1122
+ p->rd_BroadcastPacketsReceivedSec =
1123
+ rrddim_add(p->st_broadcast_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1124
+ p->rd_BroadcastPacketsSentSec =
1125
+ rrddim_add(p->st_broadcast_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1126
+ rrdlabels_add(p->st_broadcast_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1127
+
1128
+ p->st_multicast_packets = rrdset_create_localhost(
1129
+ "vswitch_multicast_packets",
1130
+ windows_shared_buffer,
1131
+ NULL,
1132
+ HYPERV,
1133
+ HYPERV ".vswitch_multicast_packets",
1134
+ "Virtual switch multicast packets",
1135
+ "packets/sec",
1136
+ _COMMON_PLUGIN_NAME,
1137
+ _COMMON_PLUGIN_MODULE_NAME,
1138
+ chart_priority++,
1139
+ update_every,
1140
+ RRDSET_TYPE_LINE);
1141
+
1142
+ p->rd_MulticastPacketsReceivedSec =
1143
+ rrddim_add(p->st_multicast_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1144
+ p->rd_MulticastPacketsSentSec =
1145
+ rrddim_add(p->st_multicast_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1146
+ rrdlabels_add(p->st_multicast_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1147
+
1148
+ p->st_dropped_packets = rrdset_create_localhost(
1149
+ "vswitch_dropped_packets",
1150
+ windows_shared_buffer,
1151
+ NULL,
1152
+ HYPERV,
1153
+ HYPERV ".vswitch_dropped_packets",
1154
+ "Virtual switch dropped packets",
1155
+ "drops/sec",
1156
+ _COMMON_PLUGIN_NAME,
1157
+ _COMMON_PLUGIN_MODULE_NAME,
1158
+ chart_priority++,
1159
+ update_every,
1160
+ RRDSET_TYPE_LINE);
1161
+
1162
+ p->rd_DroppedPacketsIncomingSec =
1163
+ rrddim_add(p->st_dropped_packets, "incoming", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1164
+ p->rd_DroppedPacketsOutgoingSec =
1165
+ rrddim_add(p->st_dropped_packets, "outgoing", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1166
+ rrdlabels_add(p->st_dropped_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1167
+
1168
+ p->st_ext_dropped_packets = rrdset_create_localhost(
1169
+ "vswitch_extensions_dropped_packets",
1170
+ windows_shared_buffer,
1171
+ NULL,
1172
+ HYPERV,
1173
+ HYPERV ".vswitch_extensions_dropped_packets",
1174
+ "Virtual switch extensions dropped packets",
1175
+ "drops/sec",
1176
+ _COMMON_PLUGIN_NAME,
1177
+ _COMMON_PLUGIN_MODULE_NAME,
1178
+ chart_priority++,
1179
+ update_every,
1180
+ RRDSET_TYPE_LINE);
1181
+
1182
+ p->rd_ExtensionsDroppedPacketsIncomingSec =
1183
+ rrddim_add(p->st_ext_dropped_packets, "incoming", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1184
+ p->rd_ExtensionsDroppedPacketsOutgoingSec =
1185
+ rrddim_add(p->st_ext_dropped_packets, "outgoing", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1186
+ rrdlabels_add(p->st_ext_dropped_packets->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1187
+
1188
+ p->st_flooded = rrdset_create_localhost(
1189
+ "vswitch_packets_flooded",
1190
+ windows_shared_buffer,
1191
+ NULL,
1192
+ HYPERV,
1193
+ HYPERV ".vswitch_packets_flooded",
1194
+ "Virtual switch flooded packets",
1195
+ "packets/sec",
1196
+ _COMMON_PLUGIN_NAME,
1197
+ _COMMON_PLUGIN_MODULE_NAME,
1198
+ chart_priority++,
1199
+ update_every,
1200
+ RRDSET_TYPE_LINE);
1201
+
1202
+ p->rd_PacketsFlooded = rrddim_add(p->st_flooded, "flooded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1203
+ rrdlabels_add(p->st_flooded->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1204
+
1205
+ p->st_learned_mac = rrdset_create_localhost(
1206
+ "vswitch_learned_mac_addresses",
1207
+ windows_shared_buffer,
1208
+ NULL,
1209
+ HYPERV,
1210
+ HYPERV ".vswitch_learned_mac_addresses",
1211
+ "Virtual switch learned MAC addresses",
1212
+ "mac addresses/sec",
1213
+ _COMMON_PLUGIN_NAME,
1214
+ _COMMON_PLUGIN_MODULE_NAME,
1215
+ chart_priority++,
1216
+ update_every,
1217
+ RRDSET_TYPE_LINE);
1218
+
1219
+ p->rd_LearnedMacAddresses = rrddim_add(p->st_learned_mac, "learned", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1220
+ rrdlabels_add(p->st_learned_mac->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1221
+
1222
+ p->st_purged_mac = rrdset_create_localhost(
1223
+ "vswitch_purged_mac_addresses",
1224
+ windows_shared_buffer,
1225
+ NULL,
1226
+ HYPERV,
1227
+ HYPERV ".vswitch_purged_mac_addresses",
1228
+ "Virtual switch purged MAC addresses",
1229
+ "mac addresses/sec",
1230
+ _COMMON_PLUGIN_NAME,
1231
+ _COMMON_PLUGIN_MODULE_NAME,
1232
+ chart_priority++,
1233
+ update_every,
1234
+ RRDSET_TYPE_LINE);
1235
+
1236
+ p->rd_PurgedMacAddresses = rrddim_add(p->st_purged_mac, "purged", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1237
+ rrdlabels_add(p->st_purged_mac->rrdlabels, "vswitch", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1238
+ }
1239
+
1240
+ SETP_DIM_VALUE(st_packets, PacketsReceivedSec);
1241
+ SETP_DIM_VALUE(st_packets, PacketsSentSec);
1242
+
1243
+ SETP_DIM_VALUE(st_bytes, BytesReceivedSec);
1244
+ SETP_DIM_VALUE(st_bytes, BytesSentSec);
1245
+
1246
+ SETP_DIM_VALUE(st_directed_packets, DirectedPacketsSentSec);
1247
+ SETP_DIM_VALUE(st_directed_packets, DirectedPacketsReceivedSec);
1248
+
1249
+ SETP_DIM_VALUE(st_broadcast_packets, BroadcastPacketsSentSec);
1250
+ SETP_DIM_VALUE(st_broadcast_packets, BroadcastPacketsReceivedSec);
1251
+
1252
+ SETP_DIM_VALUE(st_multicast_packets, MulticastPacketsSentSec);
1253
+ SETP_DIM_VALUE(st_multicast_packets, MulticastPacketsReceivedSec);
1254
+
1255
+ SETP_DIM_VALUE(st_dropped_packets, DroppedPacketsOutgoingSec);
1256
+ SETP_DIM_VALUE(st_dropped_packets, DroppedPacketsIncomingSec);
1257
+
1258
+ SETP_DIM_VALUE(st_ext_dropped_packets, ExtensionsDroppedPacketsOutgoingSec);
1259
+ SETP_DIM_VALUE(st_ext_dropped_packets, ExtensionsDroppedPacketsIncomingSec);
1260
+
1261
+ SETP_DIM_VALUE(st_flooded, PacketsFlooded);
1262
+ SETP_DIM_VALUE(st_learned_mac, LearnedMacAddresses);
1263
+ SETP_DIM_VALUE(st_purged_mac, PurgedMacAddresses);
1264
+
1265
+ // Mark the charts as done
1266
+ rrdset_done(p->st_packets);
1267
+ rrdset_done(p->st_bytes);
1268
+
1269
+ rrdset_done(p->st_directed_packets);
1270
+ rrdset_done(p->st_broadcast_packets);
1271
+ rrdset_done(p->st_multicast_packets);
1272
+ rrdset_done(p->st_dropped_packets);
1273
+ rrdset_done(p->st_ext_dropped_packets);
1274
+ rrdset_done(p->st_flooded);
1275
+ rrdset_done(p->st_learned_mac);
1276
+ rrdset_done(p->st_purged_mac);
1277
+
1278
+ }
1279
+ return true;
1280
+}
1281
+
1282
+
1283
+struct hypervisor_network_adapter {
1284
+ bool collected_metadata;
1285
+ bool charts_created;
1286
+
1287
+ RRDSET *st_packets;
1288
+ DEFINE_RD(DroppedPacketsOutgoingSec);
1289
+ DEFINE_RD(DroppedPacketsIncomingSec);
1290
+
1291
+ COUNTER_DATA DroppedPacketsOutgoingSec;
1292
+ COUNTER_DATA DroppedPacketsIncomingSec;
1293
+};
1294
+
1295
+// Initialize the keys for the root partition metrics
1296
+void initialize_hyperv_network_adapter_keys(struct hypervisor_network_adapter *p)
1297
+{
1298
+ p->DroppedPacketsOutgoingSec.key = "Dropped Packets Outgoing/sec";
1299
+ p->DroppedPacketsIncomingSec.key = "Dropped Packets Incoming/sec";
1300
+}
1301
+
1302
+void dict_hyperv_network_adapter_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1303
+{
1304
+ struct hypervisor_network_adapter *p = value;
1305
+ initialize_hyperv_network_adapter_keys(p);
1306
+}
1307
+
1308
+static bool do_hyperv_network_adapter(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
1309
+{
1310
+ hyperv_perf_item *item = data;
1311
+
1312
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
1313
+ if (!pObjectType)
1314
+ return false;
1315
+
1316
+ PERF_INSTANCE_DEFINITION *pi = NULL;
1317
+ for (LONG i = 0; i < pObjectType->NumInstances; i++) {
1318
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
1319
+ if (!pi)
1320
+ break;
1321
+
1322
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
1323
+
1324
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
1325
+ continue;
1326
+
1327
+ struct hypervisor_network_adapter *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
1328
+
1329
+ if (!p->collected_metadata) {
1330
+ p->collected_metadata = true;
1331
+ }
1332
+
1333
+ GET_INSTANCE_COUNTER(DroppedPacketsIncomingSec);
1334
+ GET_INSTANCE_COUNTER(DroppedPacketsOutgoingSec);
1335
+
1336
+ if (!p->charts_created) {
1337
+ p->charts_created = true;
1338
+ p->st_packets = rrdset_create_localhost(
1339
+ "vm_net_interface_packets_dropped",
1340
+ windows_shared_buffer,
1341
+ NULL,
1342
+ HYPERV,
1343
+ HYPERV".vm_net_interface_packets_dropped",
1344
+ "VM interface packets dropped",
1345
+ "drops/sec",
1346
+ _COMMON_PLUGIN_NAME,
1347
+ _COMMON_PLUGIN_MODULE_NAME,
1348
+ chart_priority++,
1349
+ update_every,
1350
+ RRDSET_TYPE_LINE);
1351
+
1352
+ p->rd_DroppedPacketsIncomingSec = rrddim_add(p->st_packets, "incoming", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1353
+ p->rd_DroppedPacketsOutgoingSec = rrddim_add(p->st_packets, "outgoing", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1354
+
1355
+ rrdlabels_add(p->st_packets->rrdlabels, "vm_net_interface", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1356
+ }
1357
+
1358
+ SETP_DIM_VALUE(st_packets, DroppedPacketsIncomingSec);
1359
+ SETP_DIM_VALUE(st_packets, DroppedPacketsOutgoingSec);
1360
+
1361
+ rrdset_done(p->st_packets);
1362
+ }
1363
+ return true;
1364
+}
1365
+
1366
+
1367
+// Hypervisor Virtual Processor
1368
+struct hypervisor_processor {
1369
+ bool collected_metadata;
1370
+ bool charts_created;
1371
+
1372
+ RRDSET *st_HypervisorProcessor;
1373
+
1374
+ DEFINE_RD(GuestRunTime);
1375
+ DEFINE_RD(HypervisorRunTime);
1376
+ DEFINE_RD(RemoteRunTime);
1377
+
1378
+ COUNTER_DATA GuestRunTime;
1379
+ COUNTER_DATA HypervisorRunTime;
1380
+ COUNTER_DATA RemoteRunTime;
1381
+};
1382
+
1383
+
1384
+void initialize_hyperv_processor_keys(struct hypervisor_processor *p)
1385
+{
1386
+ p->GuestRunTime.key = "% Guest Run Time";
1387
+ p->HypervisorRunTime.key = "% Hypervisor Run Time";
1388
+ p->RemoteRunTime.key = "% Remote Run Time";
1389
+}
1390
+
1391
+void dict_hyperv_processor_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1392
+{
1393
+ struct hypervisor_processor *p = value;
1394
+ initialize_hyperv_processor_keys(p);
1395
+}
1396
+
1397
+static bool do_hyperv_processor(PERF_DATA_BLOCK *pDataBlock, int update_every, void *data)
1398
+{
1399
+ hyperv_perf_item *item = data;
1400
+
1401
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, item->registry_name);
1402
+ if (!pObjectType)
1403
+ return false;
1404
+
1405
+ PERF_INSTANCE_DEFINITION *pi = NULL;
1406
+ for (LONG i = 0; i < pObjectType->NumInstances; i++) {
1407
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
1408
+ if (!pi)
1409
+ break;
1410
+
1411
+ get_and_sanitize_instance_value(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer));
1412
+
1413
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
1414
+ continue;
1415
+
1416
+ struct hypervisor_processor *p = dictionary_set(item->instance, windows_shared_buffer, NULL, sizeof(*p));
1417
+
1418
+ if (!p->collected_metadata) {
1419
+ p->collected_metadata = true;
1420
+ }
1421
+
1422
+ GET_INSTANCE_COUNTER(GuestRunTime);
1423
+ GET_INSTANCE_COUNTER(HypervisorRunTime);
1424
+ GET_INSTANCE_COUNTER(RemoteRunTime);
1425
+
1426
+ if (!p->charts_created) {
1427
+ p->charts_created = true;
1428
+ p->st_HypervisorProcessor = rrdset_create_localhost(
1429
+ "vm_cpu_usage",
1430
+ windows_shared_buffer,
1431
+ NULL,
1432
+ HYPERV,
1433
+ HYPERV ".vm_cpu_usage",
1434
+ "VM CPU usage (100% = 1 core)",
1435
+ "percentage",
1436
+ _COMMON_PLUGIN_NAME,
1437
+ _COMMON_PLUGIN_MODULE_NAME,
1438
+ chart_priority++,
1439
+ update_every,
1440
+ RRDSET_TYPE_STACKED);
1441
+
1442
+ p->rd_GuestRunTime =
1443
+ rrddim_add(p->st_HypervisorProcessor, "guest", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
1444
+ p->rd_HypervisorRunTime =
1445
+ rrddim_add(p->st_HypervisorProcessor, "hypervisor", NULL, -1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
1446
+ p->rd_RemoteRunTime =
1447
+ rrddim_add(p->st_HypervisorProcessor, "remote", NULL, -1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
1448
+
1449
+ rrdlabels_add(p->st_HypervisorProcessor->rrdlabels, "vm_name", windows_shared_buffer, RRDLABEL_SRC_AUTO);
1450
+ }
1451
+
1452
+ SETP_DIM_VALUE(st_HypervisorProcessor, GuestRunTime);
1453
+ SETP_DIM_VALUE(st_HypervisorProcessor, HypervisorRunTime);
1454
+ SETP_DIM_VALUE(st_HypervisorProcessor, RemoteRunTime);
1455
+
1456
+ rrdset_done(p->st_HypervisorProcessor);
1457
+ }
1458
+ return true;
1459
+}
1460
+
1461
+hyperv_perf_item hyperv_perf_list[] = {
1462
+ {.registry_name = "Hyper-V Dynamic Memory VM",
1463
+ .function_collect = do_hyperv_memory,
1464
+ .dict_insert_cb = dict_hyperv_memory_insert_cb,
1465
+ .dict_size = sizeof(struct hypervisor_memory)},
1466
+
1467
+ {.registry_name = "Hyper-V VM Vid Partition",
1468
+ .function_collect = do_hyperv_vid_partition,
1469
+ .dict_insert_cb = dict_hyperv_partition_insert_cb,
1470
+ .dict_size = sizeof(struct hypervisor_partition)},
1471
+
1472
+ {
1473
+ .registry_name = "Hyper-V Virtual Machine Health Summary",
1474
+ .function_collect = do_hyperv_health_summary,
1475
+ },
1476
+
1477
+ {
1478
+ .registry_name = "Hyper-V Hypervisor Root Partition",
1479
+ .function_collect = do_hyperv_root_partition,
1480
+ .dict_insert_cb = dict_hyperv_root_partition_insert_cb,
1481
+ .dict_size = sizeof(struct hypervisor_root_partition),
1482
+ },
1483
+
1484
+ {.registry_name = "Hyper-V Virtual Storage Device",
1485
+ .function_collect = do_hyperv_storage_device,
1486
+ .dict_insert_cb = dict_hyperv_storage_device_insert_cb,
1487
+ .dict_size = sizeof(struct hypervisor_storage_device)},
1488
+
1489
+ {.registry_name = "Hyper-V Virtual Switch",
1490
+ .function_collect = do_hyperv_switch,
1491
+ .dict_insert_cb = dict_hyperv_switch_insert_cb,
1492
+ .dict_size = sizeof(struct hypervisor_switch)},
1493
+
1494
+ {.registry_name = "Hyper-V Virtual Network Adapter",
1495
+ .function_collect = do_hyperv_network_adapter,
1496
+ .dict_insert_cb = dict_hyperv_network_adapter_insert_cb,
1497
+ .dict_size = sizeof(struct hypervisor_network_adapter)},
1498
+
1499
+ {.registry_name = "Hyper-V Hypervisor Virtual Processor",
1500
+ .function_collect = do_hyperv_processor,
1501
+ .dict_insert_cb = dict_hyperv_processor_insert_cb,
1502
+ .dict_size = sizeof(struct hypervisor_processor)},
1503
+
1504
+ {.registry_name = NULL, .function_collect = NULL}};
1505
+
1506
+int do_PerflibHyperV(int update_every, usec_t dt __maybe_unused) {
1507
+ static bool initialized = false;
1508
+
1509
+ if (unlikely(!initialized)) {
1510
+ for (int i = 0; hyperv_perf_list[i].registry_name != NULL; i++) {
1511
+ hyperv_perf_item *item = &hyperv_perf_list[i];
1512
+ if (item->dict_insert_cb) {
1513
+ item->instance = dictionary_create_advanced(DICT_PERF_OPTION, NULL, item->dict_size);
1514
+ dictionary_register_insert_callback(item->instance, item->dict_insert_cb, NULL);
1515
+ }
1516
+ }
1517
+ initialized = true;
1518
+ }
1519
+
1520
+ for (int i = 0; hyperv_perf_list[i].registry_name != NULL; i++) {
1521
+ // Find the registry ID using the registry name
1522
+ DWORD id = RegistryFindIDByName(hyperv_perf_list[i].registry_name);
1523
+ if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
1524
+ continue;
1525
+
1526
+ // Get the performance data using the registry ID
1527
+ PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
1528
+ if (!pDataBlock)
1529
+ continue;
1530
+
1531
+ hyperv_perf_list[i].function_collect(pDataBlock, update_every, &hyperv_perf_list[i]);
1532
+ }
1533
+ return 0;
1534
+}
src/collectors/windows.plugin/windows_plugin.c
+1
@@ -25,6 +25,7 @@ static struct proc_module {
25
{.name = "PerflibStorage", .dim = "PerflibStorage", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibStorage},
26
{.name = "PerflibNetwork", .dim = "PerflibNetwork", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibNetwork},
27
{.name = "PerflibObjects", .dim = "PerflibObjects", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibObjects},
28
+ {.name = "PerflibHyperV", .dim = "PerflibHyperV", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibHyperV},
29
30
{.name = "PerflibThermalZone", .dim = "PerflibThermalZone", .enabled = CONFIG_BOOLEAN_NO, .func = do_PerflibThermalZone},
31
src/collectors/windows.plugin/windows_plugin.h
+2
-1
@@ -99,5 +99,6 @@ enum PERFLIB_PRIO {
99
PRIO_NETFRAMEWORK_CLR_LOADING_CLASS_LOAD_FAILURE
100
};
101
102
-#endif //NETDATA_WINDOWS_PLUGIN_H
102
+int do_PerflibHyperV(int update_every, usec_t dt);
103
104
+#endif //NETDATA_WINDOWS_PLUGIN_H
src/database/rrdlabels.h
+1
@@ -75,6 +75,7 @@ pattern_array_add_key_simple_pattern(struct pattern_array *pa, const char *key,
75
void pattern_array_free(struct pattern_array *pa);
76
77
int rrdlabels_unittest(void);
78
+size_t rrdlabels_sanitize_name(char *dst, const char *src, size_t dst_size);
79
80
// unfortunately this break when defined in exporting_engine.h
81
bool exporting_labels_filter_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data);