Microsoft MVP성태의 닷넷 이야기
.NET Framework: 833. C# - Open Hardware Monitor를 이용한 CPU 온도 정보 [링크 복사], [링크+제목 복사]
조회: 16220
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

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.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 3/9/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2021-06-12 08시48분
LibreHardwareMonitor/LibreHardwareMonitor
; https://github.com/LibreHardwareMonitor/LibreHardwareMonitor

Libre Hardware Monitor, home of the fork of Open Hardware Monitor
정성태

... 16  17  18  19  20  21  22  23  24  25  26  [27]  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
12946정성태1/28/20226025오류 유형: 792. .NET Core - 로컬 개발 중에 docker 호스팅으로 바꾸는 경우 SQL 서버 접근 방법
12945정성태1/28/20226263오류 유형: 791. SQL 서버 로그인 시 localhost는 되고, 127.0.0.1로는 안 되는 문제
12944정성태1/28/20228629.NET Framework: 1143. C# - Entity Framework Core 6 개요
12943정성태1/27/20227540.NET Framework: 1142. .NET 5+로 포팅 시 플랫폼 호환성 경고 메시지(SYSLIB0006, SYSLIB0011, CA1416)파일 다운로드1
12942정성태1/27/20227812.NET Framework: 1141. XmlSerializer와 Dictionary 타입파일 다운로드1
12941정성태1/26/20229216오류 유형: 790. AKS/k8s - pod 상태가 Pending으로 지속되는 경우
12940정성태1/26/20226637오류 유형: 789. AKS에서 hpa에 따른 autoscale 기능이 동작하지 않는다면?
12939정성태1/25/20227314.NET Framework: 1140. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 MP3 오디오 파일 인코딩/디코딩하는 예제파일 다운로드1
12938정성태1/24/20229586개발 환경 구성: 633. Docker Desktop + k8s 환경에서 local 이미지를 사용하는 방법
12937정성태1/24/20227424.NET Framework: 1139. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 오디오(mp2) 인코딩하는 예제(encode_audio.c) [2]파일 다운로드1
12936정성태1/22/20227381.NET Framework: 1138. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 멀티미디어 파일의 메타데이터를 보여주는 예제(metadata.c)파일 다운로드1
12935정성태1/22/20227560.NET Framework: 1137. ffmpeg의 파일 해시 예제(ffhash.c)를 C#으로 포팅파일 다운로드1
12934정성태1/22/20227117오류 유형: 788. Warning C6262 Function uses '65564' bytes of stack: exceeds /analyze:stacksize '16384'. Consider moving some data to heap. [2]
12933정성태1/21/20227666.NET Framework: 1136. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 MP2 오디오 파일 디코딩 예제(decode_audio.c)파일 다운로드1
12932정성태1/20/20228123.NET Framework: 1135. C# - ffmpeg(FFmpeg.AutoGen)로 하드웨어 가속기를 이용한 비디오 디코딩 예제(hw_decode.c) [2]파일 다운로드1
12931정성태1/20/20226283개발 환경 구성: 632. ASP.NET Core 프로젝트를 AKS/k8s에 올리는 과정
12930정성태1/19/20226889개발 환경 구성: 631. AKS/k8s의 Volume에 파일 복사하는 방법
12929정성태1/19/20226669개발 환경 구성: 630. AKS/k8s의 Pod에 Volume 연결하는 방법
12928정성태1/18/20226818개발 환경 구성: 629. AKS/Kubernetes에서 호스팅 중인 pod에 shell(/bin/bash)로 진입하는 방법
12927정성태1/18/20226556개발 환경 구성: 628. AKS 환경에 응용 프로그램 배포 방법
12926정성태1/17/20227040오류 유형: 787. AKS - pod 배포 시 ErrImagePull/ImagePullBackOff 오류
12925정성태1/17/20227154개발 환경 구성: 627. AKS의 준비 단계 - ACR(Azure Container Registry)에 docker 이미지 배포
12924정성태1/15/20228625.NET Framework: 1134. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) [2]파일 다운로드1
12923정성태1/15/20227588개발 환경 구성: 626. ffmpeg.exe를 사용해 비디오 파일을 MPEG1 포맷으로 변경하는 방법
12922정성태1/14/20226639개발 환경 구성: 625. AKS - Azure Kubernetes Service 생성 및 SLO/SLA 변경 방법
12921정성태1/14/20225626개발 환경 구성: 624. Docker Desktop에서 별도 서버에 설치한 docker registry에 이미지 올리는 방법
... 16  17  18  19  20  21  22  23  24  25  26  [27]  28  29  30  ...