C# - Open Hardware Monitor를 이용한 CPU 온도 정보
다음의 글에 보면, CPU 온도를 구할 수 있는 WMI 쿼리가 나옵니다.
CPU Temperature using C#
; https://www.codeproject.com/Questions/800905/CPU-Temperature-using-Csharp
using System;
using System.Management;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ManagementObjectSearcher mos = new ManagementObjectSearcher(@"root\WMI", "SELECT * FROM MSAcpi_ThermalZoneTemperature");
foreach (ManagementObject mo in mos.Get())
{
Double temp = Convert.ToDouble(mo["CurrentTemperature"].ToString());
temp = (temp - 2732) / 10.0;
Console.WriteLine("{0}, {1}", temp, mo["InstanceName"]);
}
}
}
}
실행은 반드시 "관리자 권한"으로 해야 하고, 제 경우에 다음과 같은 결과를 얻었습니다.
데스크톱
27.8, ACPI\ThermalZone\TZ00_0
29.8, ACPI\ThermalZone\TZ01_0
노트북
55, ACPI\ThermalZone\TZ00_0
29.8, ACPI\ThermalZone\TZ01_0
보는 바와 같이 "TZ" 접두사로 시작하는데 정작 문서를 보면,
ACPI-defined devices
; https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/acpi-defined-devices
- Identify the devices that are contained in the thermal zone:
* _TZD to list the non-processor devices in the thermal zone.
* _PSL to list the processors in the thermal zone.
"TZ"와 일치하는 것은 찾을 수 없고 그나마 "TZD" 정도만 보입니다. 게다가 그나마도 CPU 온도 정보라기보다는 "Non-processor devices"에 속하는 것으로 아마도 메인보드나 기타 컴퓨터의 구성 요소에 해당하는 온도인 듯합니다. 결정적인 문제가 하나 있다면? 데스크톱의 경우 실행할 때마다 온도가 전혀 바뀌지 않고 27.8, 29.8로 고정해서 나옵니다. ^^;
결국, MSAcpi_ThermalZoneTemperature WMI 쿼리는 그다지 믿을만한 정보가 아닙니다.
차선책으로 오픈 소스인 OpenHardwareMonitor 라이브러리를 고려해 볼 수 있습니다.
Open Hardware Monitor
; http://openhardwaremonitor.org/
; http://openhardwaremonitor.org/wordpress/wp-content/uploads/2011/04/OpenHardwareMonitor-WMI.pdf
OpenHardwareMonitorLib 라이브러리를 참조해 다음과 같이 코딩을 할 수 있고,
using OpenHardwareMonitor.Hardware;
using System;
using System.IO;
using System.Text;
using System.Threading;
namespace ConsoleApp2
{
class Program
{
static Computer _thisComputer;
static FileStream _fs;
static void Main(string[] args)
{
_thisComputer = new Computer() { CPUEnabled = true, GPUEnabled = true, MainboardEnabled = true, HDDEnabled = true };
_thisComputer.Open();
Console.CancelKeyPress += Console_CancelKeyPress;
DateTime now = DateTime.Now;
string fileStart = now.ToString("yyyyMMdd_HHmmss") + ".log";
_fs = new FileStream(fileStart, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
while (true)
{
StringBuilder sb = new StringBuilder();
StringBuilder log = new StringBuilder();
foreach (var hardwareItem in _thisComputer.Hardware)
{
switch (hardwareItem.HardwareType)
{
case HardwareType.CPU:
case HardwareType.GpuNvidia:
case HardwareType.HDD:
case HardwareType.Mainboard:
case HardwareType.RAM:
AddCpuInfo(sb, log, hardwareItem);
break;
}
}
log.AppendLine();
Console.WriteLine(sb.ToString());
byte[] buf = Encoding.ASCII.GetBytes(log.ToString());
_fs.Write(buf, 0, buf.Length);
_fs.Flush();
Thread.Sleep(1000);
}
}
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
_fs.Close();
_thisComputer.Close();
Console.WriteLine("End-of-profile");
}
private static void AddCpuInfo(StringBuilder sb, StringBuilder log, IHardware hardwareItem)
{
hardwareItem.Update();
foreach (IHardware subHardware in hardwareItem.SubHardware)
subHardware.Update();
string text;
foreach (var sensor in hardwareItem.Sensors)
{
string name = sensor.Name;
string value = sensor.Value.HasValue ? sensor.Value.Value.ToString() : "-1";
switch (sensor.SensorType)
{
case SensorType.Temperature:
text = $"{name} Temperature = {value}";
sb.AppendLine(text);
break;
case SensorType.Voltage:
text = $"{name} Voltage = {value}";
sb.AppendLine(text);
break;
case SensorType.Fan:
text = $"{name} RPM = {value}";
sb.AppendLine(text);
break;
case SensorType.Load:
text = $"{name} % = {value}";
sb.AppendLine(text);
break;
}
log.Append($"{value},");
}
}
}
}
제 컴퓨터에서 실행해 보면 아래의 결과를 얻을 수 있습니다. (이것도 관리자 권한으로 실행해야 합니다.)
CPU Core #1 % = 43.75
CPU Core #2 % = 17.1875
CPU Core #3 % = 13.84615
CPU Core #4 % = 26.5625
CPU Total % = 25.33654
CPU Core #1 Temperature = 57
CPU Core #2 Temperature = 52
CPU Core #3 Temperature = 49
CPU Core #4 Temperature = 50
CPU Package Temperature = 57
GPU Core Temperature = 47
GPU RPM = 0
GPU Core % = 1
GPU Memory Controller % = 8
GPU Video Engine % = 0
GPU Memory % = 6.49662
Temperature Temperature = 32
Used Space % = 90.22251
Temperature Temperature = 34
Used Space % = 27.86349
Temperature Temperature = 34
Used Space % = 68.66722
그런대로 CPU 쪽의 정보는 믿을만합니다. 반면 GPU의 경우 제 시스템에 Intel CPU의 내장 GPU와 NVIDIA GPU가 있는데 1개만 나온 걸로 봐서 딱히 어느 쪽의 정보인지 구별이 안 됩니다. 작업 관리자의 정보와도 잘 맞지 않고.
따라서 CPU 온도 정보만을 구하는 목적이라면 OpenHardwareMonitor가 그나마 적절한 해답이 될 수 있을 것입니다.
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
참고로, OpenHardwareMonitor는 OpenHardwareMonitorLib.sys를 사용하는데 이게 한번 올라가면 응용 프로그램 종료와 상관없이 늘 떠있게 됩니다.
C:\Windows\System32> sc query WinRing0_1_2_0
SERVICE_NAME: WinRing0_1_2_0
TYPE : 1 KERNEL_DRIVER
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
이름도 잘 유추가 되지 않은 "WinRing0_1_2_0"인데요, 어쨌든 명시적으로 다음의 명령을 실행해야만 메모리에서 내려옵니다.
C:\Windows\System32> net stop WinRing0_1_2_0
The WinRing0_1_2_0 service was stopped successfully.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]