@cryptotaxi247 / netdata-1 / commits / 670ae4b39

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="&quot;[WindowsFolder]System32\sc.exe&quot; stop &quot;NetdataDriver&quot;"
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="&quot;[WindowsFolder]System32\sc.exe&quot; delete &quot;NetdataDriver&quot;"
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 &quot;[System64Folder]wevt_netdata.dll&quot; /grant &quot;NT SERVICE\EventLog&quot;: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 = &quot;Change&quot;" />
@@ -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 {