@cryptotaxi247 / netdata-1 / commits / 5a80d3eb8

Windows.plugin (improvements and fixes) (#22039)

thiagoftsm committed Mar 25, 2026 at 22:30 UTC 5a80d3eb803acdd64091775238a5eef0d4eaed41
9 files changed +303 -70
src/collectors/windows.plugin/GetHardwareInfo.c
+18 -5
@@ -35,6 +35,22 @@ static const int IOCTL_RETRY_DELAY_MS = 10;
35 static const int THREAD_JOIN_FALLBACK_WAIT_MS = 2000;
36 #define INVALID_TEMP ((collected_number)(-1))
37
38 +static bool netdata_expand_driver_path(char *expanded_path, size_t expanded_path_size)
39 +{
40 + DWORD ret = ExpandEnvironmentStringsA(drv_path, expanded_path, (DWORD)expanded_path_size);
41 + if (ret == 0) {
42 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot expand environment strings. Error= %lu \n", GetLastError());
43 + return false;
44 + }
45 +
46 + if (ret > expanded_path_size) {
47 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Expanded driver path exceeds buffer size (%lu bytes needed)\n", ret);
48 + return false;
49 + }
50 +
51 + return true;
52 +}
53 +
54 static void netdata_stop_driver()
55 {
56 SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
@@ -79,8 +95,7 @@ int netdata_install_driver()
95 }
96
97 char expanded_path[MAX_PATH];
82 - if (ExpandEnvironmentStringsA(drv_path, expanded_path, sizeof(expanded_path)) == 0) {
83 - nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot expand environment strings. Error= %lu \n", GetLastError());
98 + if (!netdata_expand_driver_path(expanded_path, sizeof(expanded_path))) {
99 CloseServiceHandle(scm);
100 return -1;
101 }
@@ -390,9 +405,7 @@ static void netdata_detect_cpu()
405 static int initialize()
406 {
407 char expanded_path[MAX_PATH];
393 - if (ExpandEnvironmentStringsA(drv_path, expanded_path, sizeof(expanded_path)) == 0) {
394 - nd_log(
395 - NDLS_COLLECTORS, NDLP_ERR, "Cannot expand driver path environment strings. Error= %lu \n", GetLastError());
408 + if (!netdata_expand_driver_path(expanded_path, sizeof(expanded_path))) {
409 return -1;
410 }
411
src/collectors/windows.plugin/GetPowerSupply.c
+73 -36
@@ -15,17 +15,34 @@
15 #include <setupapi.h> // for SetupDi*
16 #include <batclass.h> // for BATTERY_*
17
18 -static struct power_supply *power_supply_root = NULL;
18 +struct win_battery {
19 + struct power_supply ps;
20 + struct simple_property voltage;
21 + bool seen; // true if discovered in the current collection pass
22 + struct win_battery *next;
23 +};
24
20 -static inline void netdata_allocate_power_supply(char *path)
25 +static struct win_battery *batteries_root = NULL;
26 +
27 +static struct win_battery *netdata_get_or_create_battery(const char *name)
28 {
22 - power_supply_root = callocz(1, sizeof(struct power_supply));
23 - power_supply_root->capacity = callocz(1, sizeof(struct simple_property));
29 + for (struct win_battery *battery = batteries_root; battery; battery = battery->next) {
30 + if (battery->ps.name && !strcmp(battery->ps.name, name))
31 + return battery;
32 + }
33 +
34 + struct win_battery *battery = callocz(1, sizeof(*battery));
35 + battery->ps.name = strdupz(name);
36 + battery->ps.capacity = callocz(1, sizeof(struct simple_property));
37 + battery->next = batteries_root;
38 + batteries_root = battery;
39 +
40 + return battery;
41 }
42
43 static inline void netdata_update_power_supply_values(
44 + struct win_battery *battery,
45 HANDLE hBattery,
28 - struct simple_property *voltage,
46 BATTERY_INFORMATION *bi,
47 BATTERY_QUERY_INFORMATION *bqi)
48 {
@@ -42,19 +59,18 @@ static inline void netdata_update_power_supply_values(
59 NETDATA_DOUBLE den = bi->FullChargedCapacity;
60 num = (den) ? num / den : 0;
61
45 - power_supply_root->capacity->value = (unsigned long long)(num * 100.0);
62 + battery->ps.capacity->value = (unsigned long long)(num * 100.0);
63 }
64
48 - if (bs.Voltage != BATTERY_UNKNOWN_VOLTAGE) {
49 - voltage->value = bs.Voltage;
50 - }
65 + if (bs.Voltage != BATTERY_UNKNOWN_VOLTAGE)
66 + battery->voltage.value = bs.Voltage;
67 }
68
53 -static void netdata_power_supply_plot(struct simple_property *voltage, int update_every)
69 +static void netdata_power_supply_plot(struct win_battery *battery, int update_every)
70 {
71 rrdset_create_simple_prop(
56 - power_supply_root,
57 - power_supply_root->capacity,
72 + &battery->ps,
73 + battery->ps.capacity,
74 "Battery capacity",
75 "capacity",
76 1,
@@ -63,8 +79,8 @@ static void netdata_power_supply_plot(struct simple_property *voltage, int updat
79 update_every);
80
81 rrdset_create_simple_prop(
66 - power_supply_root,
67 - voltage,
82 + &battery->ps,
83 + &battery->voltage,
84 "Power supply voltage",
85 "now",
86 1000,
@@ -73,9 +89,27 @@ static void netdata_power_supply_plot(struct simple_property *voltage, int updat
89 update_every);
90 }
91
92 +void do_GetPowerSupply_cleanup(void)
93 +{
94 + while (batteries_root) {
95 + struct win_battery *battery = batteries_root;
96 + batteries_root = battery->next;
97 +
98 + if (battery->ps.capacity && battery->ps.capacity->st)
99 + rrdset_is_obsolete___safe_from_collector_thread(battery->ps.capacity->st);
100 + if (battery->voltage.st)
101 + rrdset_is_obsolete___safe_from_collector_thread(battery->voltage.st);
102 +
103 + freez(battery->ps.name);
104 + freez(battery->ps.capacity);
105 + freez(battery);
106 + }
107 +}
108 +
109 int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
110 {
78 - static struct simple_property voltage = {0};
111 + for (struct win_battery *b = batteries_root; b; b = b->next)
112 + b->seen = false;
113
114 HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
115 if (hdev == INVALID_HANDLE_VALUE)
@@ -88,6 +122,7 @@ int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
122 DWORD cbRequired = 0;
123 PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = NULL;
124 HANDLE hBattery = NULL;
125 +
126 SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
127 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
128 goto endPowerSupply;
@@ -112,7 +147,6 @@ int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
147 goto endPowerSupply;
148
149 BATTERY_QUERY_INFORMATION bqi = {0};
115 -
150 DWORD dwWait = 0;
151 DWORD dwOut;
152
@@ -130,34 +164,19 @@ int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
164
165 BATTERY_INFORMATION bi = {0};
166 bqi.InformationLevel = BatteryInformation;
133 -
167 if (!DeviceIoControl(
168 hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi, sizeof(bi), &dwOut, NULL))
169 goto endPowerSupply;
170
138 - if (!power_supply_root)
139 - netdata_allocate_power_supply(pdidd->DevicePath);
140 -
171 char name[RRD_ID_LENGTH_MAX + 1];
172 snprintfz(name, sizeof(name), "BAT%d", i + 1);
173 + struct win_battery *battery = netdata_get_or_create_battery(name);
174 + battery->seen = true;
175 + netdata_update_power_supply_values(battery, hBattery, &bi, &bqi);
176 + netdata_power_supply_plot(battery, update_every);
177
144 - if (likely(power_supply_root->name))
145 - freez(power_supply_root->name);
146 - if (likely(power_supply_root->capacity->filename))
147 - freez(power_supply_root->capacity->filename);
148 - if (likely(voltage.filename))
149 - freez(voltage.filename);
150 -
151 - power_supply_root->name = power_supply_root->capacity->filename = voltage.filename = NULL;
152 - power_supply_root->name = strdupz(name);
153 - power_supply_root->capacity->filename = strdupz(power_supply_root->name);
154 - voltage.filename = strdupz(power_supply_root->name);
155 -
156 - netdata_update_power_supply_values(hBattery, &voltage, &bi, &bqi);
157 -
158 - netdata_power_supply_plot(&voltage, update_every);
178 endPowerSupply:
160 - if (hBattery)
179 + if (hBattery != NULL && hBattery != INVALID_HANDLE_VALUE)
180 CloseHandle(hBattery);
181
182 if (pdidd)
@@ -166,5 +185,23 @@ int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
185
186 SetupDiDestroyDeviceInfoList(hdev);
187
188 + // Retire batteries that were not seen in this discovery pass (e.g. physically removed).
189 + struct win_battery **pp = &batteries_root;
190 + while (*pp) {
191 + struct win_battery *b = *pp;
192 + if (!b->seen) {
193 + if (b->ps.capacity && b->ps.capacity->st)
194 + rrdset_is_obsolete___safe_from_collector_thread(b->ps.capacity->st);
195 + if (b->voltage.st)
196 + rrdset_is_obsolete___safe_from_collector_thread(b->voltage.st);
197 + *pp = b->next;
198 + freez(b->ps.name);
199 + freez(b->ps.capacity);
200 + freez(b);
201 + } else {
202 + pp = &b->next;
203 + }
204 + }
205 +
206 return 0;
207 }
src/collectors/windows.plugin/GetSensors.c
+42
@@ -346,6 +346,39 @@ struct sensor_data {
346
347 DICTIONARY *sensors;
348
349 +static void netdata_sensors_free_extra_values(struct netdata_sensors_extra_values *values)
350 +{
351 + while (values) {
352 + struct netdata_sensors_extra_values *next = values->next;
353 + freez(values);
354 + values = next;
355 + }
356 +}
357 +
358 +static void netdata_sensor_cleanup(struct sensor_data *sd)
359 +{
360 + if (sd->st_sensor_state)
361 + rrdset_is_obsolete___safe_from_collector_thread(sd->st_sensor_state);
362 + if (sd->st_sensor_data)
363 + rrdset_is_obsolete___safe_from_collector_thread(sd->st_sensor_data);
364 +
365 + freez((void *)sd->type);
366 + freez((void *)sd->category);
367 + freez((void *)sd->name);
368 + freez((void *)sd->manufacturer);
369 + freez((void *)sd->model);
370 + freez(sd->external_config);
371 + netdata_sensors_free_extra_values(sd->values);
372 +
373 + sd->type = NULL;
374 + sd->category = NULL;
375 + sd->name = NULL;
376 + sd->manufacturer = NULL;
377 + sd->model = NULL;
378 + sd->external_config = NULL;
379 + sd->values = NULL;
380 +}
381 +
382 // Microsoft appends additional data
383 #define ADDTIONAL_UUID_STR_LEN (UUID_STR_LEN + 17)
384
@@ -712,6 +745,12 @@ void dict_sensor_insert(const DICTIONARY_ITEM *item __maybe_unused, void *value,
745 sd->add_factor = 0.0;
746 }
747
748 +void dict_sensor_delete(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
749 +{
750 + struct sensor_data *sd = value;
751 + netdata_sensor_cleanup(sd);
752 +}
753 +
754 static int initialize(int update_every)
755 {
756 // Note: COM and Sensor API initialization is now done in the sensor thread
@@ -724,6 +763,7 @@ static int initialize(int update_every)
763 sensors = dictionary_create_advanced(
764 DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct sensor_data));
765 dictionary_register_insert_callback(sensors, dict_sensor_insert, NULL);
766 + dictionary_register_delete_callback(sensors, dict_sensor_delete, NULL);
767
768 sensors_thread_update =
769 nd_thread_create("sensors_upd", NETDATA_THREAD_OPTION_DEFAULT, netdata_sensors_monitor, &update_every);
@@ -906,9 +946,11 @@ void do_Sensors_cleanup()
946 // The thread handles its own COM cleanup (CoUninitialize) and pSensorManager release
947 if (nd_thread_join(sensors_thread_update))
948 nd_log_daemon(NDLP_ERR, "Failed to join sensors thread update");
949 + sensors_thread_update = NULL;
950
951 __netdata_mutex_destroy(&sensors_mutex);
952 dictionary_destroy(sensors);
953 + sensors = NULL;
954 // Note: pSensorManager is owned and cleaned up by the sensor thread itself
955 // No additional cleanup needed here since the thread has already released resources
956 }
src/collectors/windows.plugin/GetServicesStatus.c
+27
@@ -7,6 +7,7 @@
7 struct win_service {
8 char *service_name;
9 DWORD pid;
10 + bool present;
11
12 RRDSET *st_service_state;
13 RRDDIM *rd_service_state_running;
@@ -25,6 +26,8 @@ static DICTIONARY *win_services = NULL;
26
27 static void win_service_cleanup(struct win_service *s)
28 {
29 + if (s->st_service_state)
30 + rrdset_is_obsolete___safe_from_collector_thread(s->st_service_state);
31 freez(s->service_name);
32 s->service_name = NULL;
33 }
@@ -60,6 +63,16 @@ static void initialize(void)
63 dictionary_register_delete_callback(win_services, dict_win_service_delete_cb, NULL);
64 }
65
66 +static int dict_win_services_mark_missing_cb(
67 + const DICTIONARY_ITEM *item __maybe_unused,
68 + void *value,
69 + void *data __maybe_unused)
70 +{
71 + struct win_service *p = value;
72 + p->present = false;
73 + return 1;
74 +}
75 +
76 static BOOL fill_dictionary_with_content()
77 {
78 PVOID buffer = NULL;
@@ -86,6 +99,7 @@ static BOOL fill_dictionary_with_content()
99 NULL);
100
101 if (ret) {
102 + dictionary_walkthrough_write(win_services, dict_win_services_mark_missing_cb, NULL);
103 // This only happens if there are truly 0 services in the system (a valid edge case).
104 goto endServiceCollection;
105 }
@@ -117,6 +131,7 @@ static BOOL fill_dictionary_with_content()
131 goto endServiceCollection;
132 }
133
134 + dictionary_walkthrough_write(win_services, dict_win_services_mark_missing_cb, NULL);
135 services = (LPENUM_SERVICE_STATUS_PROCESS)buffer;
136
137 for (ULONG i = 0; i < total_services; i++) {
@@ -130,6 +145,7 @@ static BOOL fill_dictionary_with_content()
145
146 p->ServiceState.current.Data = service->ServiceStatusProcess.dwCurrentState;
147 p->pid = service->ServiceStatusProcess.dwProcessId;
148 + p->present = true;
149 }
150
151 ret = TRUE;
@@ -231,6 +247,16 @@ static int dict_win_services_charts_cb(const DICTIONARY_ITEM *item __maybe_unuse
247 return 1;
248 }
249
250 +static int dict_win_services_delete_missing_cb(const DICTIONARY_ITEM *item, void *value, void *data __maybe_unused)
251 +{
252 + struct win_service *p = value;
253 +
254 + if (!p->present)
255 + dictionary_del(win_services, dictionary_acquired_item_name(item));
256 +
257 + return 1;
258 +}
259 +
260 int do_GetServicesStatus(int update_every, usec_t dt __maybe_unused)
261 {
262 #define NETDATA_SERVICE_MAX_TRY (5)
@@ -255,6 +281,7 @@ int do_GetServicesStatus(int update_every, usec_t dt __maybe_unused)
281 }
282
283 limit = 0;
284 + dictionary_walkthrough_write(win_services, dict_win_services_delete_missing_cb, NULL);
285 dictionary_sorted_walkthrough_read(win_services, dict_win_services_charts_cb, &update_every);
286
287 return 0;
src/collectors/windows.plugin/perflib-netframework.c
+100 -11
@@ -16,6 +16,8 @@ enum netdata_netframework_metrics {
16 };
17
18 struct net_framework_instances {
19 + usec_t last_collected;
20 +
21 RRDSET *st_clrexception_thrown;
22 RRDDIM *rd_clrexception_thrown;
23
@@ -154,6 +156,9 @@ struct net_framework_instances {
156 COUNTER_DATA NETFrameworkCLRLocksAndThreadsContentions;
157 };
158
159 +static usec_t netframework_now_ut = 0;
160 +static DICTIONARY *processes = NULL;
161 +
162 static inline void initialize_net_framework_processes_keys(struct net_framework_instances *p)
163 {
164 p->NETFrameworkCLRExceptionFilters.key = "# of Filters / sec";
@@ -207,7 +212,65 @@ void dict_net_framework_processes_insert_cb(
212 initialize_net_framework_processes_keys(p);
213 }
214
210 -static DICTIONARY *processes = NULL;
215 +static void netframework_mark_chart_obsolete(RRDSET **st)
216 +{
217 + if (*st)
218 + rrdset_is_obsolete___safe_from_collector_thread(*st);
219 +
220 + *st = NULL;
221 +}
222 +
223 +static void netframework_process_cleanup(struct net_framework_instances *p)
224 +{
225 + netframework_mark_chart_obsolete(&p->st_clrexception_thrown);
226 + netframework_mark_chart_obsolete(&p->st_clrexception_filters);
227 + netframework_mark_chart_obsolete(&p->st_clrexception_finallys);
228 + netframework_mark_chart_obsolete(&p->st_clrexception_total_catch_depth);
229 + netframework_mark_chart_obsolete(&p->st_clrinterop_com_callable_wrappers);
230 + netframework_mark_chart_obsolete(&p->st_clrinterop_marshalling);
231 + netframework_mark_chart_obsolete(&p->st_clrinterop_interop_stubs_created);
232 + netframework_mark_chart_obsolete(&p->st_clrjit_methods);
233 + netframework_mark_chart_obsolete(&p->st_clrjit_time);
234 + netframework_mark_chart_obsolete(&p->st_clrjit_standard_failures);
235 + netframework_mark_chart_obsolete(&p->st_clrjit_il_bytes);
236 + netframework_mark_chart_obsolete(&p->st_clrloading_heap_size);
237 + netframework_mark_chart_obsolete(&p->st_clrloading_app_domains_loaded);
238 + netframework_mark_chart_obsolete(&p->st_clrloading_app_domains_unloaded);
239 + netframework_mark_chart_obsolete(&p->st_clrloading_assemblies_loaded);
240 + netframework_mark_chart_obsolete(&p->st_clrloading_classes_loaded);
241 + netframework_mark_chart_obsolete(&p->st_clrloading_class_load_failure);
242 + netframework_mark_chart_obsolete(&p->st_clrremoting_channels);
243 + netframework_mark_chart_obsolete(&p->st_clrremoting_context_bound_classes_loaded);
244 + netframework_mark_chart_obsolete(&p->st_clrremoting_context_bound_objects);
245 + netframework_mark_chart_obsolete(&p->st_clrremoting_context_proxies);
246 + netframework_mark_chart_obsolete(&p->st_clrremoting_contexts);
247 + netframework_mark_chart_obsolete(&p->st_clrremoting_remote_calls);
248 + netframework_mark_chart_obsolete(&p->st_clrsecurity_link_time_checks);
249 + netframework_mark_chart_obsolete(&p->st_clrsecurity_rt_checks_time);
250 + netframework_mark_chart_obsolete(&p->st_clrsecurity_stack_walk_depth);
251 + netframework_mark_chart_obsolete(&p->st_clrsecurity_run_time_checks);
252 + netframework_mark_chart_obsolete(&p->st_clrlocksandthreads_queue_length);
253 + netframework_mark_chart_obsolete(&p->st_clrlocksandthreads_current_logical_threads);
254 + netframework_mark_chart_obsolete(&p->st_clrlocksandthreads_current_physical_threads);
255 + netframework_mark_chart_obsolete(&p->st_clrlocksandthreads_recognized_threads);
256 + netframework_mark_chart_obsolete(&p->st_clrlocksandthreads_contentions);
257 +}
258 +
259 +static void dict_net_framework_processes_delete_cb(
260 + const DICTIONARY_ITEM *item __maybe_unused,
261 + void *value,
262 + void *data __maybe_unused)
263 +{
264 + struct net_framework_instances *p = value;
265 + netframework_process_cleanup(p);
266 +}
267 +
268 +static inline struct net_framework_instances *netframework_process_get(const char *name)
269 +{
270 + struct net_framework_instances *p = dictionary_set(processes, name, NULL, sizeof(*p));
271 + p->last_collected = netframework_now_ut;
272 + return p;
273 +}
274
275 static void initialize(void)
276 {
@@ -215,6 +278,7 @@ static void initialize(void)
278 DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct net_framework_instances));
279
280 dictionary_register_insert_callback(processes, dict_net_framework_processes_insert_cb, NULL);
281 + dictionary_register_delete_callback(processes, dict_net_framework_processes_delete_cb, NULL);
282 }
283
284 static void
@@ -233,7 +297,7 @@ netdata_framework_clr_exceptions(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *
297 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
298 continue;
299
236 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
300 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
301
302 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRExceptionThrown)) {
303 if (!p->st_clrexception_thrown) {
@@ -383,7 +447,7 @@ static void netdata_framework_clr_interop(PERF_DATA_BLOCK *pDataBlock, PERF_OBJE
447 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
448 continue;
449
386 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
450 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
451
452 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRInteropCOMCallableWrappers)) {
453 if (!p->st_clrinterop_com_callable_wrappers) {
@@ -509,7 +573,7 @@ static void netdata_framework_clr_jit(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_T
573 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
574 continue;
575
512 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
576 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
577
578 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRJITMethods)) {
579 if (!p->st_clrjit_methods) {
@@ -653,7 +717,7 @@ static void netdata_framework_clr_loading(PERF_DATA_BLOCK *pDataBlock, PERF_OBJE
717 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
718 continue;
719
656 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
720 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
721
722 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRLoadingHeapSize)) {
723 if (!p->st_clrloading_heap_size) {
@@ -867,12 +931,12 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
931 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
932 continue;
933
870 - netdata_fix_chart_name(windows_shared_buffer);
871 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
934 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
935
936 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingChannels)) {
937 if (!p->st_clrremoting_channels) {
938 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_channels", windows_shared_buffer);
939 + netdata_fix_chart_name(id);
940 p->st_clrremoting_channels = rrdset_create_localhost(
941 "netframework",
942 id,
@@ -904,6 +968,7 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
968 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingContextBoundClassesLoaded)) {
969 if (!p->st_clrremoting_context_bound_classes_loaded) {
970 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_context_bound_classes_loaded", windows_shared_buffer);
971 + netdata_fix_chart_name(id);
972 p->st_clrremoting_context_bound_classes_loaded = rrdset_create_localhost(
973 "netframework",
974 id,
@@ -938,6 +1003,7 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1003 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingContextBoundObjects)) {
1004 if (!p->st_clrremoting_context_bound_objects) {
1005 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_context_bound_objects", windows_shared_buffer);
1006 + netdata_fix_chart_name(id);
1007 p->st_clrremoting_context_bound_objects = rrdset_create_localhost(
1008 "netframework",
1009 id,
@@ -971,6 +1037,7 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1037 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingContextProxies)) {
1038 if (!p->st_clrremoting_context_proxies) {
1039 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_context_proxies", windows_shared_buffer);
1040 + netdata_fix_chart_name(id);
1041 p->st_clrremoting_context_proxies = rrdset_create_localhost(
1042 "netframework",
1043 id,
@@ -1002,6 +1069,7 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1069 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingContexts)) {
1070 if (!p->st_clrremoting_contexts) {
1071 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_contexts", windows_shared_buffer);
1072 + netdata_fix_chart_name(id);
1073 p->st_clrremoting_contexts = rrdset_create_localhost(
1074 "netframework",
1075 id,
@@ -1033,6 +1101,7 @@ static void netdata_framework_clr_remoting(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1101 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRRemotingRemoteCalls)) {
1102 if (!p->st_clrremoting_remote_calls) {
1103 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrremoting_calls", windows_shared_buffer);
1104 + netdata_fix_chart_name(id);
1105 p->st_clrremoting_remote_calls = rrdset_create_localhost(
1106 "netframework",
1107 id,
@@ -1078,12 +1147,12 @@ static void netdata_framework_clr_security(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1147 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
1148 continue;
1149
1081 - netdata_fix_chart_name(windows_shared_buffer);
1082 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
1150 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
1151
1152 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRSecurityLinkTimeChecks)) {
1153 if (!p->st_clrsecurity_link_time_checks) {
1154 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrsecurity_link_time_checks", windows_shared_buffer);
1155 + netdata_fix_chart_name(id);
1156 p->st_clrsecurity_link_time_checks = rrdset_create_localhost(
1157 "netframework",
1158 id,
@@ -1116,6 +1185,7 @@ static void netdata_framework_clr_security(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1185 perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRSecurityFrequency_PerfTime)) {
1186 if (!p->st_clrsecurity_rt_checks_time) {
1187 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrsecurity_checks_time", windows_shared_buffer);
1188 + netdata_fix_chart_name(id);
1189 p->st_clrsecurity_rt_checks_time = rrdset_create_localhost(
1190 "netframework",
1191 id,
@@ -1150,6 +1220,7 @@ static void netdata_framework_clr_security(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1220 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRSecurityStackWalkDepth)) {
1221 if (!p->st_clrsecurity_stack_walk_depth) {
1222 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrsecurity_stack_walk_depth", windows_shared_buffer);
1223 + netdata_fix_chart_name(id);
1224 p->st_clrsecurity_stack_walk_depth = rrdset_create_localhost(
1225 "netframework",
1226 id,
@@ -1181,6 +1252,7 @@ static void netdata_framework_clr_security(PERF_DATA_BLOCK *pDataBlock, PERF_OBJ
1252 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRSecurityRunTimeChecks)) {
1253 if (!p->st_clrsecurity_run_time_checks) {
1254 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrsecurity_runtime_checks", windows_shared_buffer);
1255 + netdata_fix_chart_name(id);
1256 p->st_clrsecurity_run_time_checks = rrdset_create_localhost(
1257 "netframework",
1258 id,
@@ -1227,12 +1299,12 @@ netdata_framework_clr_locks_and_threads(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT
1299 if (strcasecmp(windows_shared_buffer, "_Global_") == 0)
1300 continue;
1301
1230 - netdata_fix_chart_name(windows_shared_buffer);
1231 - struct net_framework_instances *p = dictionary_set(processes, windows_shared_buffer, NULL, sizeof(*p));
1302 + struct net_framework_instances *p = netframework_process_get(windows_shared_buffer);
1303
1304 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRLocksAndThreadsQueueLength)) {
1305 if (!p->st_clrlocksandthreads_queue_length) {
1306 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrlocksandthreads_queue_length", windows_shared_buffer);
1307 + netdata_fix_chart_name(id);
1308 p->st_clrlocksandthreads_queue_length = rrdset_create_localhost(
1309 "netframework",
1310 id,
@@ -1268,6 +1340,7 @@ netdata_framework_clr_locks_and_threads(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT
1340 if (!p->st_clrlocksandthreads_current_logical_threads) {
1341 snprintfz(
1342 id, RRD_ID_LENGTH_MAX, "%s_clrlocksandthreads_current_logical_threads", windows_shared_buffer);
1343 + netdata_fix_chart_name(id);
1344 p->st_clrlocksandthreads_current_logical_threads = rrdset_create_localhost(
1345 "netframework",
1346 id,
@@ -1303,6 +1376,7 @@ netdata_framework_clr_locks_and_threads(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT
1376 if (!p->st_clrlocksandthreads_current_physical_threads) {
1377 snprintfz(
1378 id, RRD_ID_LENGTH_MAX, "%s_clrlocksandthreads_current_physical_threads", windows_shared_buffer);
1379 + netdata_fix_chart_name(id);
1380 p->st_clrlocksandthreads_current_physical_threads = rrdset_create_localhost(
1381 "netframework",
1382 id,
@@ -1337,6 +1411,7 @@ netdata_framework_clr_locks_and_threads(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT
1411 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRLocksAndThreadsRecognizedThreads)) {
1412 if (!p->st_clrlocksandthreads_recognized_threads) {
1413 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrlocksandthreads_recognized_threads", windows_shared_buffer);
1414 + netdata_fix_chart_name(id);
1415 p->st_clrlocksandthreads_recognized_threads = rrdset_create_localhost(
1416 "netframework",
1417 id,
@@ -1371,6 +1446,7 @@ netdata_framework_clr_locks_and_threads(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT
1446 if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->NETFrameworkCLRLocksAndThreadsContentions)) {
1447 if (!p->st_clrlocksandthreads_contentions) {
1448 snprintfz(id, RRD_ID_LENGTH_MAX, "%s_clrlocksandthreads_contentions", windows_shared_buffer);
1449 + netdata_fix_chart_name(id);
1450 p->st_clrlocksandthreads_contentions = rrdset_create_localhost(
1451 "netframework",
1452 id,
@@ -1427,6 +1503,8 @@ int do_PerflibNetFramework(int update_every, usec_t dt __maybe_unused)
1503 initialized = true;
1504 }
1505
1506 + netframework_now_ut = now_monotonic_usec();
1507 +
1508 int i;
1509 for (i = 0; i < NETDATA_NETFRAMEWORK_END; i++) {
1510 DWORD id = RegistryFindIDByName(netframewrk_obj[i].object);
@@ -1444,5 +1522,16 @@ int do_PerflibNetFramework(int update_every, usec_t dt __maybe_unused)
1522 netframewrk_obj[i].fnct(pDataBlock, pObjectType, update_every);
1523 }
1524
1525 + {
1526 + struct net_framework_instances *p;
1527 + dfe_start_write(processes, p)
1528 + {
1529 + if (p->last_collected < netframework_now_ut)
1530 + dictionary_del(processes, p_dfe.name);
1531 + }
1532 + dfe_done(p);
1533 + dictionary_garbage_collect(processes);
1534 + }
1535 +
1536 return 0;
1537 }
src/collectors/windows.plugin/perflib-rrd.c
+5 -5
@@ -174,19 +174,19 @@ collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_D
174
175 case PERF_COUNTER_MULTI_TIMER:
176 // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
177 - if (!VALID_DELTA(cd))
177 + if (!VALID_DELTA(cd) || !cd->current.Frequency || !cd->current.MultiCounterData)
178 return 0;
179 numerator = cd->current.Data - cd->previous.Data;
180 denominator = cd->current.Time - cd->previous.Time;
181 - denominator /= cd->current.Frequency;
182 - doubleValue = 100.0 * ((double)numerator / (double)denominator) / cd->current.MultiCounterData;
181 + doubleValue = 100.0 * ((double)numerator / ((double)denominator / (double)cd->current.Frequency)) /
182 + (double)cd->current.MultiCounterData;
183 // printf("Display value is (multi-timer): %f%%\n", doubleValue);
184 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
185 break;
186
187 case PERF_100NSEC_MULTI_TIMER:
188 // 100 * ((N1 - N0) / (D1 - D0)) / B1
189 - if (!VALID_DELTA(cd))
189 + if (!VALID_DELTA(cd) || !cd->current.MultiCounterData)
190 return 0;
191 numerator = cd->current.Data - cd->previous.Data;
192 denominator = cd->current.Time - cd->previous.Time;
@@ -198,7 +198,7 @@ collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_D
198 case PERF_COUNTER_MULTI_TIMER_INV:
199 case PERF_100NSEC_MULTI_TIMER_INV:
200 // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
201 - if (!VALID_DELTA(cd))
201 + if (!VALID_DELTA(cd) || !cd->current.MultiCounterData)
202 return 0;
203 numerator = cd->current.Data - cd->previous.Data;
204 denominator = cd->current.Time - cd->previous.Time;
src/collectors/windows.plugin/perflib-storage.c
+32 -10
@@ -437,7 +437,7 @@ static inline double perflib_average_timer_ms(COUNTER_DATA *d)
437 LONGLONG freq1 = d->current.Frequency;
438
439 if (data1 >= data0 && time1 > time0 && time0 && freq1)
440 - return ((double)(data1 - data0) / (double)(freq1 / MSEC_PER_SEC)) / (double)(time1 - time0);
440 + return ((double)(data1 - data0) * (double)MSEC_PER_SEC) / ((double)freq1 * (double)(time1 - time0));
441
442 return 0;
443 }
@@ -482,6 +482,8 @@ static DiskDriveInfoWMI infos[MAX_WMI_DRIVES];
482 static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut)
483 {
484 DICTIONARY *dict = physicalDisks;
485 + size_t infoCount = 0;
486 + bool infos_loaded = false;
487
488 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "PhysicalDisk");
489 if (!pObjectType)
@@ -526,7 +528,11 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
528
529 if (!d->collected_metadata) {
530 if (!is_system && device_index != -1) {
529 - size_t infoCount = GetDiskDriveInfo(infos, _countof(infos));
531 + if (!infos_loaded) {
532 + infoCount = GetDiskDriveInfo(infos, _countof(infos));
533 + infos_loaded = true;
534 + }
535 +
536 for (size_t k = 0; k < infoCount; k++) {
537 if (infos[k].Index != device_index)
538 continue;
@@ -706,23 +712,39 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
712 int do_PerflibStorage(int update_every, usec_t dt __maybe_unused)
713 {
714 static bool initialized = false;
715 + DWORD logical_id, physical_id;
716
717 if (unlikely(!initialized)) {
718 initialize();
719 initialized = true;
720 }
721
715 - DWORD id = RegistryFindIDByName("LogicalDisk");
716 - if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
717 - return -1;
722 + logical_id = RegistryFindIDByName("LogicalDisk");
723 + physical_id = RegistryFindIDByName("PhysicalDisk");
724
719 - PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
720 - if (!pDataBlock)
725 + if (logical_id == PERFLIB_REGISTRY_NAME_NOT_FOUND && physical_id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
726 return -1;
727
728 + // Each perflibGetPerformanceData() call reuses the same internal buffer, so we must
729 + // query and consume each block before issuing the next call to avoid pointer aliasing.
730 usec_t now_ut = now_monotonic_usec();
724 - do_logical_disk(pDataBlock, update_every, now_ut);
725 - do_physical_disk(pDataBlock, update_every, now_ut);
731 + bool processed_any = false;
732
727 - return 0;
733 + if (logical_id != PERFLIB_REGISTRY_NAME_NOT_FOUND) {
734 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(logical_id);
735 + if (pDataBlock) {
736 + do_logical_disk(pDataBlock, update_every, now_ut);
737 + processed_any = true;
738 + }
739 + }
740 +
741 + if (physical_id != PERFLIB_REGISTRY_NAME_NOT_FOUND) {
742 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(physical_id);
743 + if (pDataBlock) {
744 + do_physical_disk(pDataBlock, update_every, now_ut);
745 + processed_any = true;
746 + }
747 + }
748 +
749 + return processed_any ? 0 : -1;
750 }
src/collectors/windows.plugin/windows_plugin.c
+5 -3
@@ -39,7 +39,7 @@ static struct proc_module {
39 .func = do_GetPowerSupply,
40 .rd = NULL,
41 .thread = NULL,
42 - .cleanup = NULL},
42 + .cleanup = do_GetPowerSupply_cleanup},
43 {.name = "GetSensors",
44 .dim = "GetSensors",
45 .enabled = CONFIG_BOOLEAN_YES,
@@ -326,11 +326,13 @@ void win_plugin_main(void *ptr)
326 // Join threads
327 for (i = 0; win_modules[i].name; i++) {
328 struct proc_module *pm = &win_modules[i];
329 - if (pm->cleanup)
330 - pm->cleanup();
329
330 if (pm->thread) {
331 nd_thread_join(pm->thread);
332 + pm->thread = NULL;
333 }
334 +
335 + if (pm->cleanup)
336 + pm->cleanup();
337 }
338 }
src/collectors/windows.plugin/windows_plugin.h
+1
@@ -55,6 +55,7 @@ void do_GetHardwareInfo_cleanup();
55 void do_Sensors_cleanup();
56 void do_GetServicesStatus_cleanup();
57 void do_GetSystemCPU_cleanup();
58 +void do_GetPowerSupply_cleanup();
59
60 enum PERFLIB_PRIO {
61 PRIO_WEBSITE_IIS_REQUESTS_RATE = 21000, // PRIO selected, because APPS is using 20YYY