CPU Temperature (windows.plugin) (#20992)
thiagoftsm committed
Oct 29, 2025 at 21:57 UTC
670ae4b3993e4e0444f61c31c4c47aad32cb44a3
8 files changed
+668
-2
CMakeLists.txt
+35
@@ -1931,6 +1931,7 @@ set(WINDOWS_PLUGIN_FILES
1931
src/collectors/windows.plugin/GetPowerSupply.c
1932
src/collectors/windows.plugin/GetServicesStatus.c
1933
src/collectors/windows.plugin/GetSensors.c
1934
+ src/collectors/windows.plugin/GetHardwareInfo.c
1935
src/collectors/windows.plugin/perflib-adcs.c
1936
src/collectors/windows.plugin/perflib-adfs.c
1937
src/collectors/windows.plugin/perflib-rrd.c
@@ -1953,6 +1954,11 @@ set(WINDOWS_PLUGIN_FILES
1954
src/collectors/windows.plugin/perflib-asp.c
1955
)
1956
1957
+set(WINDOWS_PLUGIN_DRIVER
1958
+ src/collectors/windows.plugin/netdata_win_driver.c
1959
+ src/collectors/windows.plugin/netdata_win_driver.h
1960
+)
1961
+
1962
set(PROC_PLUGIN_FILES
1963
src/collectors/proc.plugin/ipc.c
1964
src/collectors/proc.plugin/plugin_proc.c
@@ -3017,6 +3023,35 @@ if(OS_WINDOWS)
3023
add_executable(NetdataClaim ${CLAIM_WINDOWS_FILES} ${NETDATA_CLAIM_RES_FILES})
3024
target_link_libraries(NetdataClaim shell32 gdi32 msftedit)
3025
target_compile_options(NetdataClaim PUBLIC -mwindows)
3026
+
3027
+ set(NETDATA_DRIVER_FILE "${CMAKE_BINARY_DIR}/netdata_driver.sys")
3028
+
3029
+ add_library(netdata_driver SHARED ${WINDOWS_PLUGIN_DRIVER})
3030
+ set_target_properties(netdata_driver PROPERTIES LIBRARY_OUTPUT_NAME "netdata_driver")
3031
+ set_target_properties(netdata_driver PROPERTIES PREFIX "")
3032
+ set_target_properties(netdata_driver PROPERTIES SUFFIX ".sys")
3033
+ target_include_directories(netdata_driver PRIVATE BEFORE "/mingw64/include/ddk" "${CMAKE_SOURCE_DIR}/src/collectors/windows.plugin")
3034
+ target_compile_options(netdata_driver PRIVATE
3035
+ -Wall
3036
+ -Wextra
3037
+ -Werror
3038
+ -ffreestanding
3039
+ -fno-exceptions
3040
+ -fno-stack-protector
3041
+ -fshort-wchar
3042
+ -mno-red-zone
3043
+ )
3044
+ target_link_options(netdata_driver PRIVATE
3045
+ -Wl,--entry,DriverEntry@8
3046
+ -nostdlib
3047
+ -Wl,--subsystem,native
3048
+ -Wl,--image-base,0x10000
3049
+ )
3050
+ target_link_libraries(netdata_driver kernel32 ntoskrnl)
3051
+
3052
+ install(FILES "${NETDATA_DRIVER_FILE}"
3053
+ COMPONENT netdata_win_driver
3054
+ DESTINATION "${BINDIR}")
3055
endif()
3056
3057
target_compile_options(netdata PRIVATE
packaging/windows/netdata.wxs.in
+67
-2
@@ -26,6 +26,8 @@
26
<Property Id="GPLLICENSE" Value="0" />
27
<Property Id="CLOUDUILICENSE" Value="0" />
28
29
+ <Property Id="NDDRVINST" Secure="yes" />
30
+
31
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
32
33
<!-- Added to handle FilesInUse dialog -->
@@ -51,6 +53,7 @@
53
<ComponentRef Id="NetdataEtcPython" />
54
<ComponentRef Id="NetdataEtcStatsd" />
55
<ComponentGroupRef Id="WevtComponents" />
56
+ <FeatureGroupRef Id="NetdataDriver" />
57
<ComponentRef Id="NetdataService" />
58
</Feature>
59
@@ -128,9 +131,42 @@
131
Impersonate="no"
132
/>
133
134
+ <SetProperty
135
+ Id="NDStopDriverSrv"
136
+ Value=""[WindowsFolder]System32\sc.exe" stop "NetdataDriver""
137
+ Before="NDConfigureServiceRecovery"
138
+ Sequence="execute"
139
+ />
140
+ <CustomAction
141
+ Id="NDStopDriverSrv"
142
+ BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)"
143
+ DllEntry="WixQuietExec"
144
+ Execute="deferred"
145
+ Return="ignore"
146
+ Impersonate="no"
147
+ />
148
+
149
+ <SetProperty
150
+ Id="NDRemoveDriverSrv"
151
+ Value=""[WindowsFolder]System32\sc.exe" delete "NetdataDriver""
152
+ Before="NDConfigureServiceRecovery"
153
+ Sequence="execute"
154
+ />
155
+ <CustomAction
156
+ Id="NDRemoveDriverSrv"
157
+ BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)"
158
+ DllEntry="WixQuietExec"
159
+ Execute="deferred"
160
+ Return="ignore"
161
+ Impersonate="no"
162
+ />
163
+
164
<InstallExecuteSequence>
165
<Custom Action="NDConfigureServiceRecovery" After="InstallServices" Condition="NOT REMOVE" />
166
+
167
<Custom Action="NDKillProcess" Before="RemoveFiles" />
168
+ <Custom Action="NDStopDriverSrv" After="NDKillProcess" />
169
+ <Custom Action="NDRemoveDriverSrv" After="RemoveFiles" />
170
</InstallExecuteSequence>
171
</Package>
172
@@ -144,6 +180,7 @@
180
<Exclude Files="C:\msys64\opt\netdata\usr\bin\netdata.exe" />
181
<Exclude Files="C:\msys64\opt\netdata\usr\bin\wevt_netdata_manifest.xml" />
182
<Exclude Files="C:\msys64\opt\netdata\usr\bin\wevt_netdata.dll" />
183
+ <Exclude Files="C:\msys64\opt\netdata\usr\bin\netdata_driver.sys" />
184
</Files>
185
</ComponentGroup>
186
@@ -215,6 +252,12 @@
252
</File>
253
</ComponentGroup>
254
255
+ <!-- Install netdata driver file -->
256
+ <FeatureGroup Id="NetdataDriver">
257
+ <File Id="NetdataDrv" Name="netdata_driver.sys" Directory="System64Folder" Source="C:\msys64\opt\netdata\usr\bin\netdata_driver.sys" Condition="NDDRVINST=1">
258
+ </File>
259
+ </FeatureGroup>
260
+
261
<CustomAction Id="DllPermission" Directory="System64Folder" ExeCommand='[System64Folder]icacls.exe "[System64Folder]wevt_netdata.dll" /grant "NT SERVICE\EventLog":R' Execute="deferred" Return="ignore" Impersonate="no"/>
262
<InstallExecuteSequence>
263
<Custom Action="DllPermission" After="InstallFiles" />
@@ -284,7 +327,10 @@
327
<Publish Dialog="NDWarningDialog" Control="Next" Event="NewDialog" Value="ViewLicenseDlg" />
328
329
<Publish Dialog="ViewLicenseDlg" Control="Back" Event="NewDialog" Value="NDWarningDialog" />
287
- <Publish Dialog="ViewLicenseDlg" Control="Next" Event="NewDialog" Value="NDConfigDialog" />
330
+ <Publish Dialog="ViewLicenseDlg" Control="Next" Event="NewDialog" Value="NDComponentSelection" />
331
+
332
+ <Publish Dialog="NDComponentSelection" Control="Back" Event="NewDialog" Value="ViewLicenseDlg" />
333
+ <Publish Dialog="NDComponentSelection" Control="Next" Event="NewDialog" Value="NDConfigDialog" />
334
335
<!-- We are hidden for while the directory to install netdata and forcing a default, because it is still necessary adjusts to test claim.conf in different directories -->
336
@@ -294,7 +340,7 @@
340
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="10" />
341
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="20" / -->
342
297
- <Publish Dialog="NDConfigDialog" Control="Back" Event="NewDialog" Value="ViewLicenseDlg" />
343
+ <Publish Dialog="NDConfigDialog" Control="Back" Event="NewDialog" Value="NDComponentSelection" />
344
<Publish Dialog="NDConfigDialog" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" />
345
346
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="NDConfigDialog" Order="1" Condition="NOT Installed OR WixUI_InstallMode = "Change"" />
@@ -400,5 +446,24 @@
446
</Control>
447
</Dialog>
448
</UI>
449
+
450
+ <UI>
451
+ <Dialog Id="NDComponentSelection" Width="370" Height="270" Title="Netdata Feature">
452
+ <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.LicenseAgreementDlgBannerBitmap)" />
453
+ <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
454
+ <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
455
+ <Control Id="Description" Type="Text" X="25" Y="23" Width="340" Height="15" Transparent="yes" NoPrefix="yes" Text="Select additional features to install." />
456
+ <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Features" />
457
+
458
+ <Control Id="NDDriverCBX" Type="CheckBox" X="10" Y="60" Width="290" Height="15" Property="NDDRVINST" CheckBoxValue="1" Text="Netdata Driver: Hardware Metrics Collection." Disabled="no" />
459
+
460
+ <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
461
+ <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
462
+ <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
463
+ <Publish Event="SpawnDialog" Value="CancelDlg" />
464
+ </Control>
465
+ </Dialog>
466
+ </UI>
467
+
468
</Fragment>
469
</Wix>
src/collectors/windows.plugin/GetHardwareInfo.c
new
+320
@@ -0,0 +1,320 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows_plugin.h"
4
+#include "windows-internals.h"
5
+
6
+#include "netdata_win_driver.h"
7
+
8
+static const char *srv_name = "NetdataDriver";
9
+const char *drv_path = "%SystemRoot%\\system32\\netdata_driver.sys";
10
+
11
+struct cpu_data {
12
+ RRDDIM *rd_cpu_temp;
13
+
14
+ collected_number cpu_temp;
15
+};
16
+
17
+struct cpu_data *cpus = NULL;
18
+size_t ncpus = 0 ;
19
+static ND_THREAD *hardware_info_thread = NULL;
20
+static collected_number (*temperature_fcnt)(MSR_REQUEST *) = NULL;
21
+
22
+static void netdata_stop_driver()
23
+{
24
+ SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
25
+ if (scm == NULL) {
26
+ nd_log(
27
+ NDLS_COLLECTORS,
28
+ NDLP_ERR,
29
+ "Cannot open Service Manager. Error= %lu \n", GetLastError());
30
+ return;
31
+ }
32
+
33
+ SC_HANDLE service = OpenService(scm, srv_name, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
34
+ if (service == NULL) {
35
+ nd_log(
36
+ NDLS_COLLECTORS,
37
+ NDLP_ERR,
38
+ "Cannot open the service. Error= %lu \n", GetLastError());
39
+ CloseServiceHandle(scm);
40
+ return;
41
+ }
42
+
43
+ SERVICE_STATUS_PROCESS ss_status = {};
44
+ if (ControlService(service, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ss_status) == 0) {
45
+ if (GetLastError() != ERROR_SERVICE_NOT_ACTIVE) {
46
+ nd_log(
47
+ NDLS_COLLECTORS,
48
+ NDLP_ERR,
49
+ "Cannot stop the service. Error= %lu \n", GetLastError());
50
+ }
51
+ } else {
52
+ if (!DeleteService(service)) {
53
+ nd_log(
54
+ NDLS_COLLECTORS,
55
+ NDLP_ERR,
56
+ "Cannot delete service. Error= %lu \n", GetLastError());
57
+ }
58
+ }
59
+
60
+ CloseServiceHandle(service);
61
+ CloseServiceHandle(scm);
62
+}
63
+
64
+int netdata_install_driver()
65
+{
66
+ SC_HANDLE scm = OpenSCManager(
67
+ NULL,
68
+ NULL,
69
+ SC_MANAGER_CREATE_SERVICE
70
+ );
71
+
72
+ if (unlikely(!scm)) {
73
+ nd_log(
74
+ NDLS_COLLECTORS,
75
+ NDLP_ERR,
76
+ "Cannot open Service Manager. Error= %lu \n", GetLastError());
77
+ return -1;
78
+ }
79
+
80
+ // Create the service entry for the driver
81
+ SC_HANDLE service = CreateService(
82
+ scm,
83
+ srv_name,
84
+ srv_name,
85
+ SERVICE_START | SERVICE_STOP | DELETE,
86
+ SERVICE_KERNEL_DRIVER,
87
+ SERVICE_DEMAND_START,
88
+ SERVICE_ERROR_NORMAL,
89
+ drv_path,
90
+ NULL,
91
+ NULL,
92
+ NULL,
93
+ NULL,
94
+ NULL
95
+ );
96
+
97
+ if (unlikely(!service)) {
98
+ if (GetLastError() == ERROR_SERVICE_EXISTS) {
99
+ CloseServiceHandle(scm);
100
+ return 0;
101
+ }
102
+
103
+ nd_log(
104
+ NDLS_COLLECTORS,
105
+ NDLP_ERR,
106
+ "Cannot create Service. Error= %lu \n", GetLastError());
107
+ CloseServiceHandle(scm);
108
+ return -1;
109
+ }
110
+
111
+ CloseServiceHandle(service);
112
+ CloseServiceHandle(scm);
113
+
114
+ return 0;
115
+}
116
+
117
+int netdata_start_driver()
118
+{
119
+ SC_HANDLE scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
120
+ if (unlikely(!scm)) {
121
+ nd_log(
122
+ NDLS_COLLECTORS,
123
+ NDLP_ERR,
124
+ "Cannot open Service Manager. Error= %lu \n", GetLastError());
125
+ return -1;
126
+ }
127
+
128
+ SC_HANDLE service = OpenServiceA(scm, srv_name, SERVICE_START | SERVICE_QUERY_STATUS);
129
+ if (unlikely(!service)) {
130
+ CloseServiceHandle(scm);
131
+ nd_log(
132
+ NDLS_COLLECTORS,
133
+ NDLP_ERR,
134
+ "Cannot open Service. Error= %lu \n", GetLastError());
135
+ return -1;
136
+ }
137
+
138
+ int ret = 0;
139
+ if (!StartServiceA(service, 0, NULL)) {
140
+ DWORD err = GetLastError();
141
+ if (err != ERROR_SERVICE_EXISTS && err != ERROR_SERVICE_ALREADY_RUNNING) {
142
+ nd_log(
143
+ NDLS_COLLECTORS,
144
+ NDLP_ERR,
145
+ "Cannot start Service. Error= %lu \n", err);
146
+ ret = -1;
147
+ }
148
+ }
149
+
150
+ CloseServiceHandle(service);
151
+ CloseServiceHandle(scm);
152
+ return ret;
153
+}
154
+
155
+static inline HANDLE netdata_open_device()
156
+{
157
+ HANDLE msr_h = CreateFileA(MSR_USER_PATH, GENERIC_READ | GENERIC_WRITE, 0,
158
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
159
+ if (msr_h == INVALID_HANDLE_VALUE) {
160
+ nd_log(
161
+ NDLS_COLLECTORS,
162
+ NDLP_ERR,
163
+ "Cannot open device. GetLastError= %lu \n", GetLastError());
164
+ }
165
+ return msr_h;
166
+}
167
+
168
+static collected_number netdata_intel_cpu_temp(MSR_REQUEST *req)
169
+{
170
+ const ULONG TJMAX = 100;
171
+ ULONG digital_readout = (req->low >> 16) & 0x7F; // bits [22:16]
172
+ return (collected_number)(TJMAX - digital_readout);
173
+}
174
+
175
+static collected_number netdata_amd_cpu_temp(MSR_REQUEST *req)
176
+{
177
+ ULONG amd_temp = (req->low >> 21) & 0x7FF;
178
+ return (collected_number) amd_temp/8;
179
+}
180
+
181
+void netdata_collect_cpu_chart()
182
+{
183
+ HANDLE device = netdata_open_device();
184
+ if (device == INVALID_HANDLE_VALUE) {
185
+ return;
186
+ }
187
+
188
+ const uint32_t MSR_THERM_STATUS = 0x19C;
189
+
190
+ for (size_t cpu = 0; cpu < ncpus; cpu++) {
191
+ DWORD bytes = 0;
192
+ MSR_REQUEST req = { MSR_THERM_STATUS, (ULONG)cpu, 0, 0 };
193
+
194
+ if (DeviceIoControl(device, IOCTL_MSR_READ, &req, sizeof(req), &req, sizeof(req), &bytes, NULL)) {
195
+ cpus[cpu].cpu_temp = temperature_fcnt(&req);
196
+ }
197
+ }
198
+
199
+ CloseHandle(device);
200
+}
201
+
202
+static void get_hardware_info_thread(void *ptr __maybe_unused)
203
+{
204
+ heartbeat_t hb;
205
+ heartbeat_init(&hb, USEC_PER_SEC);
206
+
207
+ while (service_running(SERVICE_COLLECTORS)) {
208
+ (void)heartbeat_next(&hb);
209
+
210
+ netdata_collect_cpu_chart();
211
+ }
212
+}
213
+
214
+static void netdata_detect_cpu()
215
+{
216
+ SYSTEM_INFO sysInfo;
217
+ GetSystemInfo(&sysInfo);
218
+
219
+ WORD test = sysInfo.wProcessorArchitecture;
220
+ if (test != PROCESSOR_ARCHITECTURE_AMD64 && test != PROCESSOR_ARCHITECTURE_IA64) {
221
+ return;
222
+ }
223
+
224
+ int cpuInfo[4];
225
+ __cpuid(cpuInfo, 0);
226
+
227
+ char vendorID[13];
228
+ memcpy(vendorID, &cpuInfo[1], 4);
229
+ memcpy(&vendorID[4], &cpuInfo[3], 4);
230
+ memcpy(&vendorID[8], &cpuInfo[2], 4);
231
+ vendorID[12] = '\0';
232
+
233
+ if (!strcmp(vendorID, "GenuineIntel"))
234
+ temperature_fcnt = netdata_intel_cpu_temp;
235
+ else if (!strcmp(vendorID, "AuthenticAMD"))
236
+ temperature_fcnt = netdata_amd_cpu_temp;
237
+}
238
+
239
+static int initialize(int update_every)
240
+{
241
+ netdata_detect_cpu();
242
+ if (!temperature_fcnt) {
243
+ return -1;
244
+ }
245
+
246
+ if (netdata_install_driver()) {
247
+ return -1;
248
+ }
249
+
250
+ if (netdata_start_driver()) {
251
+ return -1;
252
+ }
253
+
254
+ ncpus = os_get_system_cpus();
255
+ cpus = callocz(ncpus, sizeof(struct cpu_data));
256
+
257
+ hardware_info_thread = nd_thread_create("hi_threads", NETDATA_THREAD_OPTION_DEFAULT, get_hardware_info_thread, &update_every);
258
+
259
+ return 0;
260
+}
261
+
262
+static RRDSET *netdata_publish_cpu_chart(int update_every)
263
+{
264
+ static RRDSET *st_cpu_temp = NULL;
265
+ if (!st_cpu_temp) {
266
+ st_cpu_temp = rrdset_create_localhost(
267
+ "cpu",
268
+ "temperature",
269
+ NULL,
270
+ "temperature",
271
+ "cpu.temperature",
272
+ "Core temperature",
273
+ "Celcius",
274
+ PLUGIN_WINDOWS_NAME,
275
+ "GetHardwareInfo",
276
+ NETDATA_CHART_PRIO_CPU_TEMPERATURE,
277
+ update_every,
278
+ RRDSET_TYPE_LINE);
279
+ }
280
+
281
+ return st_cpu_temp;
282
+}
283
+
284
+static void netdata_loop_cpu_chart(int update_every)
285
+{
286
+ RRDSET *chart = netdata_publish_cpu_chart(update_every);
287
+ for (size_t i = 0; i < ncpus; i++) {
288
+ struct cpu_data *lcpu = &cpus[i];
289
+ if (!lcpu->rd_cpu_temp) {
290
+ char id[RRD_ID_LENGTH_MAX + 1];
291
+ snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%lu.temp", i);
292
+ lcpu->rd_cpu_temp = rrddim_add(chart, id, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
293
+ }
294
+ rrddim_set_by_pointer(chart, lcpu->rd_cpu_temp, lcpu->cpu_temp);
295
+ }
296
+ rrdset_done(chart);
297
+}
298
+
299
+int do_GetHardwareInfo(int update_every, usec_t dt __maybe_unused)
300
+{
301
+ static bool initialized = false;
302
+ if (unlikely(!initialized)) {
303
+ initialized = true;
304
+ if (initialize(update_every)) {
305
+ return -1;
306
+ }
307
+ }
308
+
309
+ netdata_loop_cpu_chart(update_every);
310
+
311
+ return 0;
312
+}
313
+
314
+void do_GetHardwareInfo_cleanup()
315
+{
316
+ if (nd_thread_join(hardware_info_thread))
317
+ nd_log_daemon(NDLP_ERR, "Failed to join mssql queries thread");
318
+
319
+ netdata_stop_driver();
320
+}
src/collectors/windows.plugin/metadata.yaml
+82
@@ -903,6 +903,88 @@ modules:
903
chart_type: area
904
dimensions:
905
- name: semaphores
906
+ - meta:
907
+ plugin_name: windows.plugin
908
+ module_name: GetHardwareInfo
909
+ monitored_instance:
910
+ name: Hardware information collected from kernel ring.
911
+ link: "https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/"
912
+ categories:
913
+ - data-collection.windows-systems
914
+ icon_filename: "windows.svg"
915
+ related_resources:
916
+ integrations:
917
+ list: []
918
+ info_provided_to_referring_integrations:
919
+ description: ""
920
+ keywords:
921
+ - cpu
922
+ - temperature
923
+ most_popular: false
924
+ overview:
925
+ data_collection:
926
+ metrics_description: |
927
+ This collector monitors cpu temperature on Windows systems.
928
+ method_description: |
929
+ It reads `msr` register using netdata_driver.sys driver.
930
+ supported_platforms:
931
+ include: ["windows"]
932
+ exclude: []
933
+ multi_instance: false
934
+ additional_permissions:
935
+ description: ""
936
+ default_behavior:
937
+ auto_detection:
938
+ description: |
939
+ This optional feature requires the Netdata Driver (netdata_driver.sys) to be installed on the host.
940
+ limits:
941
+ description: ""
942
+ performance_impact:
943
+ description: ""
944
+ setup:
945
+ prerequisites:
946
+ list: []
947
+ configuration:
948
+ file:
949
+ name: "netdata.conf"
950
+ section_name: "[plugin:windows:GetHardwareInfo]"
951
+ description: "The Netdata main configuration file"
952
+ options:
953
+ description: ""
954
+ folding:
955
+ title: "Config option"
956
+ enabled: false
957
+ list:
958
+ - name: update every
959
+ description: Data collection frequency.
960
+ default_value: 1
961
+ required: false
962
+ examples:
963
+ folding:
964
+ enabled: true
965
+ title: ""
966
+ list: []
967
+ troubleshooting:
968
+ problems:
969
+ list: []
970
+ alerts: []
971
+ metrics:
972
+ folding:
973
+ title: Metrics
974
+ enabled: false
975
+ description: ""
976
+ availability: []
977
+ scopes:
978
+ - name: global
979
+ description: "This metric show latest CPU temperature."
980
+ labels: []
981
+ metrics:
982
+ - name: cpu.temperature
983
+ description: Core temperature
984
+ unit: "Celcius"
985
+ chart_type: line
986
+ dimensions:
987
+ - name: a dimension per core
988
- meta:
989
plugin_name: windows.plugin
990
module_name: PerflibThermalZone
src/collectors/windows.plugin/netdata_win_driver.c
new
+122
@@ -0,0 +1,122 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include <ddk/ntddk.h>
4
+#include <intrin.h>
5
+
6
+#define MSR_IA32_THERM_STATUS 0x19C
7
+#define MSR_DEVICE_NAME L"\\Device\\NDDrv"
8
+#define MSR_DOSLINK_NAME L"\\DosDevices\\NDDrv"
9
+
10
+#define IOCTL_MSR_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
11
+
12
+typedef struct _MSR_REQUEST {
13
+ ULONG msr;
14
+ ULONG cpu;
15
+ ULONG low;
16
+ ULONG high;
17
+} MSR_REQUEST, *PMSR_REQUEST;
18
+
19
+DRIVER_UNLOAD NetdataMsrUnload;
20
+DRIVER_DISPATCH NetdataMsrCreateClose;
21
+DRIVER_DISPATCH NetdataMsrDeviceControl;
22
+
23
+static UNICODE_STRING g_DeviceName = RTL_CONSTANT_STRING(MSR_DEVICE_NAME);
24
+static UNICODE_STRING g_DosLinkName = RTL_CONSTANT_STRING(MSR_DOSLINK_NAME);
25
+
26
+VOID NetdataMsrUnload(_In_ PDRIVER_OBJECT DriverObject)
27
+{
28
+ IoDeleteSymbolicLink(&g_DosLinkName);
29
+
30
+ if (DriverObject->DeviceObject) {
31
+ IoDeleteDevice(DriverObject->DeviceObject);
32
+ }
33
+}
34
+
35
+NTSTATUS NetdataMsrCreateClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
36
+{
37
+ UNREFERENCED_PARAMETER(DeviceObject);
38
+
39
+ Irp->IoStatus.Status = STATUS_SUCCESS;
40
+ Irp->IoStatus.Information = 0;
41
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
42
+ return STATUS_SUCCESS;
43
+}
44
+
45
+NTSTATUS NetdataMsrDeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
46
+{
47
+ UNREFERENCED_PARAMETER(DeviceObject);
48
+
49
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
50
+ NTSTATUS status = STATUS_SUCCESS;
51
+ ULONG information = 0;
52
+
53
+ if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_MSR_READ) {
54
+ if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(MSR_REQUEST) ||
55
+ irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MSR_REQUEST)) {
56
+ status = STATUS_BUFFER_TOO_SMALL;
57
+ } else {
58
+ PMSR_REQUEST req = (PMSR_REQUEST)Irp->AssociatedIrp.SystemBuffer;
59
+
60
+ ULONG maxCpus = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
61
+ if (req->cpu >= maxCpus) {
62
+ status = STATUS_INVALID_PARAMETER;
63
+ } else {
64
+ KAFFINITY cpuMask = 1ull << req->cpu;
65
+ KAFFINITY oldMask = KeSetSystemAffinityThreadEx(cpuMask);
66
+
67
+ ULONGLONG value = __readmsr(req->msr);
68
+ req->low = (ULONG)(value & 0xFFFFFFFF);
69
+ req->high = (ULONG)(value >> 32);
70
+ information = sizeof(MSR_REQUEST);
71
+
72
+ KeRevertToUserAffinityThreadEx(oldMask);
73
+ }
74
+ }
75
+ } else {
76
+ status = STATUS_INVALID_DEVICE_REQUEST;
77
+ }
78
+
79
+ Irp->IoStatus.Status = status;
80
+ Irp->IoStatus.Information = information;
81
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
82
+
83
+ return status;
84
+}
85
+
86
+NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
87
+{
88
+ UNREFERENCED_PARAMETER(RegistryPath);
89
+ NTSTATUS status;
90
+ PDEVICE_OBJECT deviceObject = NULL;
91
+
92
+ status = IoCreateDevice(
93
+ DriverObject,
94
+ 0,
95
+ &g_DeviceName,
96
+ FILE_DEVICE_UNKNOWN,
97
+ FILE_DEVICE_SECURE_OPEN,
98
+ FALSE,
99
+ &deviceObject
100
+ );
101
+
102
+ if (!NT_SUCCESS(status)) {
103
+ return status;
104
+ }
105
+
106
+ status = IoCreateSymbolicLink(&g_DosLinkName, &g_DeviceName);
107
+ if (!NT_SUCCESS(status)) {
108
+ IoDeleteDevice(deviceObject);
109
+ return status;
110
+ }
111
+
112
+ deviceObject->Flags |= DO_BUFFERED_IO;
113
+
114
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = NetdataMsrCreateClose;
115
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = NetdataMsrCreateClose;
116
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NetdataMsrDeviceControl;
117
+ DriverObject->DriverUnload = NetdataMsrUnload;
118
+
119
+ deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
120
+
121
+ return STATUS_SUCCESS;
122
+}
src/collectors/windows.plugin/netdata_win_driver.h
new
+32
@@ -0,0 +1,32 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_WIN_DRV_H
4
+#define NETDATA_WIN_DRV_H
5
+
6
+#if defined(OS_WINDOWS)
7
+
8
+#include <windows.h>
9
+#include <intrin.h>
10
+
11
+// Device + symbolic link names used by the driver
12
+#define MSR_USER_PATH "\\\\.\\NDDrv"
13
+
14
+// IOCTLs
15
+#define IOCTL_MSR_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
16
+
17
+typedef struct {
18
+ ULONG msr;
19
+ ULONG cpu;
20
+ ULONG low;
21
+ ULONG high;
22
+} MSR_REQUEST;
23
+
24
+enum netdata_cpu_detection {
25
+ NETDATA_CPU_WIN_UNKNOWN,
26
+ NETDATA_CPU_WIN_INTEL,
27
+ NETDATA_CPU_WIN_AMD
28
+};
29
+
30
+#endif // OS_WINDOWS
31
+
32
+#endif // NETDATA_WIN_DRV_H
src/collectors/windows.plugin/windows_plugin.c
+8
@@ -48,6 +48,14 @@ static struct proc_module {
48
.rd = NULL,
49
.thread = NULL,
50
.cleanup = do_Sensors_cleanup},
51
+ {.name = "GetHardwareInfo",
52
+ .dim = "GetHardwareInfo",
53
+ .enabled = CONFIG_BOOLEAN_NO,
54
+ .update_every = 10 * UPDATE_EVERY_MIN,
55
+ .func = do_GetHardwareInfo,
56
+ .rd = NULL,
57
+ .thread = NULL,
58
+ .cleanup = do_GetHardwareInfo_cleanup},
59
{.name = "PerflibServices",
60
.dim = "PerflibServices",
61
.enabled = CONFIG_BOOLEAN_YES,
src/collectors/windows.plugin/windows_plugin.h
+2
@@ -29,6 +29,7 @@ int do_GetSystemRAM(int update_every, usec_t dt);
29
int do_GetSystemCPU(int update_every, usec_t dt);
30
int do_GetPowerSupply(int update_every, usec_t dt);
31
int do_GetServicesStatus(int update_every, usec_t dt);
32
+int do_GetHardwareInfo(int update_every, usec_t dt);
33
int do_GetSensors(int update_every, usec_t dt);
34
35
// Perflib
@@ -52,6 +53,7 @@ int do_PerflibASP(int update_every, usec_t dt __maybe_unused);
53
54
// Cleanup
55
void do_PerflibMSSQL_cleanup();
56
+void do_GetHardwareInfo_cleanup();
57
void do_Sensors_cleanup();
58
59
enum PERFLIB_PRIO {