@cryptotaxi247 / netdata / commits / 35b62d244

NUMA Windows (#20573)

thiagoftsm committed Jun 25, 2025 at 11:15 UTC 35b62d244436700e2ff06362603967135c29cec3
5 files changed +227 -4
CMakeLists.txt
+1
@@ -2064,6 +2064,7 @@ set(WINDOWS_PLUGIN_FILES
2064 src/collectors/windows.plugin/perflib-services.c
2065 src/collectors/windows.plugin/perflib-hyperv.c
2066 src/collectors/windows.plugin/perflib-exchange.c
2067 + src/collectors/windows.plugin/perflib-numa.c
2068 )
2069
2070 set(PROC_PLUGIN_FILES
src/collectors/windows.plugin/metadata.yaml
+87
@@ -3452,3 +3452,90 @@ modules:
3452 chart_type: line
3453 dimensions:
3454 - name: serviced
3455 + - meta:
3456 + plugin_name: windows.plugin
3457 + module_name: PerflibNUMA
3458 + monitored_instance:
3459 + name: NUMA Architecture
3460 + link: "https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support"
3461 + categories:
3462 + - data-collection.windows-systems
3463 + icon_filename: "windows.svg"
3464 + related_resources:
3465 + integrations:
3466 + list: []
3467 + info_provided_to_referring_integrations:
3468 + description: ""
3469 + keywords:
3470 + - windows
3471 + - NUMA
3472 + - processor
3473 + most_popular: false
3474 + overview:
3475 + data_collection:
3476 + metrics_description: |
3477 + This collector monitors NUMA Architecture on Windows.
3478 + method_description: |
3479 + It queries NUMA Node Memory from Perflib in order to gather the metrics.
3480 + supported_platforms:
3481 + include: ["windows"]
3482 + exclude: []
3483 + multi_instance: false
3484 + additional_permissions:
3485 + description: ""
3486 + default_behavior:
3487 + auto_detection:
3488 + description: |
3489 + The collector automatically detects all of the metrics, no further configuration is required.
3490 + limits:
3491 + description: ""
3492 + performance_impact:
3493 + description: ""
3494 + setup:
3495 + prerequisites:
3496 + list: []
3497 + configuration:
3498 + file:
3499 + name: "netdata.conf"
3500 + section_name: "[plugin:windows]"
3501 + description: "The Netdata main configuration file"
3502 + options:
3503 + description: ""
3504 + folding:
3505 + title: "Config option"
3506 + enabled: false
3507 + list:
3508 + - name: PerflibNUMA
3509 + description: An option to enable or disable the data collection.
3510 + default_value: yes
3511 + required: false
3512 + examples:
3513 + folding:
3514 + enabled: true
3515 + title: ""
3516 + list: []
3517 + troubleshooting:
3518 + problems:
3519 + list: []
3520 + alerts: []
3521 + metrics:
3522 + folding:
3523 + title: Metrics
3524 + enabled: false
3525 + description: ""
3526 + availability: []
3527 + scopes:
3528 + - name: NUMA
3529 + description: "These metrics refer to memory utilization on NUMA systems."
3530 + labels:
3531 + - name: node
3532 + description: The identifier of the CPU node.
3533 + metrics:
3534 + - name: mem.numa_node_mem_usage
3535 + description: NUMA Node Memory Usage
3536 + unit: bytes
3537 + chart_type: line
3538 + dimensions:
3539 + - name: free
3540 + - name: standby
3541 + - name: available
src/collectors/windows.plugin/perflib-numa.c new
+123
@@ -0,0 +1,123 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +struct netdata_numa {
7 + RRDSET *st_numa;
8 + RRDDIM *rd_standby;
9 + RRDDIM *rd_available;
10 + RRDDIM *rd_free_zero;
11 +
12 + COUNTER_DATA standby;
13 + COUNTER_DATA available;
14 + COUNTER_DATA free_zero;
15 +};
16 +
17 +static DICTIONARY *numa_dict = NULL;
18 +
19 +static void numa_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
20 +{
21 + struct netdata_numa *d = value;
22 +
23 + d->standby.key = "Standby List MBytes";
24 + d->available.key = "Available MBytes";
25 + d->free_zero.key = "Free & Zero Page List MBytes";
26 +}
27 +
28 +static void initialize(void)
29 +{
30 + numa_dict = dictionary_create_advanced(
31 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct netdata_numa));
32 +
33 + dictionary_register_insert_callback(numa_dict, numa_insert_cb, NULL);
34 +}
35 +
36 +static void netdata_numa_chart(struct netdata_numa *nn, int update_every)
37 +{
38 + if (unlikely(!nn->st_numa)) {
39 + char id[RRD_ID_LENGTH_MAX + 1];
40 + snprintfz(id, RRD_ID_LENGTH_MAX, "numae_node_%s_mem_usage", windows_shared_buffer);
41 +
42 + nn->st_numa = rrdset_create_localhost(
43 + "numa_node_mem_usage",
44 + id,
45 + NULL,
46 + "numa",
47 + "mem.numa_node_mem_usage",
48 + "NUMA Node Memory Usage",
49 + "bytes",
50 + PLUGIN_WINDOWS_NAME,
51 + "PerflibNUMA",
52 + NETDATA_CHART_PRIO_MEM_NUMA_NODES_MEMINFO,
53 + update_every,
54 + RRDSET_TYPE_LINE);
55 +
56 + rrdlabels_add(nn->st_numa->rrdlabels, "node", windows_shared_buffer, RRDLABEL_SRC_AUTO);
57 +
58 + nn->rd_free_zero = rrddim_add(nn->st_numa, "free", NULL, MEGA_FACTOR, 1, RRD_ALGORITHM_ABSOLUTE);
59 +
60 + nn->rd_standby = rrddim_add(nn->st_numa, "standby", NULL, MEGA_FACTOR, 1, RRD_ALGORITHM_ABSOLUTE);
61 +
62 + nn->rd_available = rrddim_add(nn->st_numa, "available", NULL, MEGA_FACTOR, 1, RRD_ALGORITHM_ABSOLUTE);
63 + }
64 +
65 + rrddim_set_by_pointer(nn->st_numa, nn->rd_free_zero, (collected_number)nn->free_zero.current.Data);
66 +
67 + rrddim_set_by_pointer(nn->st_numa, nn->rd_available, (collected_number)nn->available.current.Data);
68 +
69 + rrddim_set_by_pointer(nn->st_numa, nn->rd_standby, (collected_number)nn->standby.current.Data);
70 +
71 + rrdset_done(nn->st_numa);
72 +}
73 +
74 +static bool do_numa(PERF_DATA_BLOCK *pDataBlock, int update_every)
75 +{
76 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "NUMA Node Memory");
77 + if (!pObjectType)
78 + return false;
79 +
80 + PERF_INSTANCE_DEFINITION *pi = NULL;
81 + for (LONG i = 0; i < pObjectType->NumInstances; i++) {
82 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
83 + if (!pi)
84 + break;
85 +
86 + if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
87 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
88 +
89 + if (strcasecmp(windows_shared_buffer, "_Total") == 0)
90 + continue;
91 +
92 + struct netdata_numa *nn = dictionary_set(numa_dict, windows_shared_buffer, NULL, sizeof(*nn));
93 +
94 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &nn->standby) ||
95 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &nn->available) ||
96 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &nn->free_zero))
97 + netdata_numa_chart(nn, update_every);
98 + }
99 +
100 + return true;
101 +}
102 +
103 +int do_PerflibNUMA(int update_every, usec_t dt __maybe_unused)
104 +{
105 + static bool initialized = false;
106 +
107 + if (unlikely(!initialized)) {
108 + initialize();
109 + initialized = true;
110 + }
111 +
112 + DWORD id = RegistryFindIDByName("NUMA Node Memory");
113 + if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
114 + return -1;
115 +
116 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
117 + if (!pDataBlock)
118 + return -1;
119 +
120 + do_numa(pDataBlock, update_every);
121 +
122 + return 0;
123 +}
src/collectors/windows.plugin/windows_plugin.c
+11 -4
@@ -113,10 +113,17 @@ static struct proc_module {
113 .func = do_PerflibServices},
114
115 {.name = "PerflibExchange",
116 - .dim = "PerflibADFS",
117 - .enabled = CONFIG_BOOLEAN_YES,
118 - .update_every = UPDATE_EVERY_MIN,
119 - .func = do_PerflibExchange},
116 + .dim = "PerflibADFS",
117 + .enabled = CONFIG_BOOLEAN_YES,
118 + .update_every = UPDATE_EVERY_MIN,
119 + .func = do_PerflibExchange},
120 +
121 + {.name = "PerflibNUMA",
122 + .dim = "PerflibNUMA",
123 + .enabled = CONFIG_BOOLEAN_YES,
124 + .update_every = UPDATE_EVERY_MIN,
125 + .func = do_PerflibNUMA},
126 +
127 // the terminator of this array
128 {.name = NULL, .dim = NULL, .func = NULL}};
129
src/collectors/windows.plugin/windows_plugin.h
+5
@@ -11,6 +11,10 @@
11 // 2^24
12 #define WINDOWS_MAX_KERNEL_OBJECT 16777216
13
14 +#ifndef MEGA_FACTOR
15 +#define MEGA_FACTOR (1048576)
16 +#endif
17 +
18 void *win_plugin_main(void *ptr);
19
20 extern char windows_shared_buffer[8192];
@@ -38,6 +42,7 @@ int do_PerflibADFS(int update_every, usec_t dt);
42 int do_PerflibHyperV(int update_every, usec_t dt);
43 int do_PerflibServices(int update_every, usec_t dt);
44 int do_PerflibExchange(int update_every, usec_t dt __maybe_unused);
45 +int do_PerflibNUMA(int update_every, usec_t dt __maybe_unused);
46
47 enum PERFLIB_PRIO {
48 PRIO_WEBSITE_IIS_REQUESTS_RATE = 21000, // PRIO selected, because APPS is using 20YYY