C# - cpuid 명령어를 이용한 CPU 제조사 문자열 가져오기
아래와 같은 글이 있군요. ^^
Why does Windows report my processor speed twice, with slightly different values?
; https://devblogs.microsoft.com/oldnewthing/20250520-00/?p=111201
Settings / System / About 패널의 "Processor" 정보가, 제 경우에는 다음과 같이 나오는데요,
사용자에 따라서는 CPU 속도 정보가 두 번 나오는 경우도 있다고 합니다.
Processor
Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
3.71GHz
위의 두 번째 열에 나오는 3.60GHz 정보는 CPU 자체에서 제공하는 브랜드 문자열인 반면, 세 번째 열에 나오는 3.71GHz 정보는 Windows가 CPU의 동작 속도를 대략적으로 측정하여 표시한 값이라고 합니다. (아마도... 예전에 소개했던
rdtsc를 이용한 계산과 비슷한 방법으로 구하지 않았을까 싶습니다. ^^)
결국 세 번째 열의 정보가 실제 수치이고, 따라서 이를 감안하면 3% 정도의 오버클럭을 해서 나온 수치일 거라고!
그럼 C# 코드로도 CPU 제조사 문자열을 가져와 볼까요? ^^ 이를 위해 우선, C++ 소스 코드를 구해야 하는데요,
EAX=8000'0002h,8000'0003h,8000'0004h: Processor Brand String
; https://en.wikipedia.org/wiki/CPUID#EAX=8000'0002h,8000'0003h,8000'0004h:_Processor_Brand_String
Visual C++로는 이렇게 포팅할 수 있고,
#include <stdio.h>
#include <string.h>
#include <intrin.h>
void getCpuId(int bits[], int functionId)
{
__cpuid(bits, functionId);
}
int main()
{
int regs[12];
char str[sizeof(regs) + 1];
getCpuId(®s[0], 0x80000000);
if (regs[0] < 0x80000004)
return 1;
getCpuId(®s[0], 0x80000002);
getCpuId(®s[4], 0x80000003);
getCpuId(®s[8], 0x80000004);
memcpy(str, regs, sizeof(regs));
str[sizeof(regs)] = '\0';
printf("%s\n", str);
return 0;
}
실행해 보면, 제 컴퓨터에서 "12th Gen Intel(R) Core(TM) i9-12900K" 문자열이 나옵니다. 자, 그럼 이것을 C#으로 포팅해야 하는데요, 이미 이전 글에서 다뤘기 때문에,
C++의 inline asm 사용을 .NET으로 포팅하는 방법
; https://www.sysnet.pe.kr/2/0/1267
C++의 32비트 + Release 어셈블리 코드를 .NET으로 포팅할 때 주의할 점
; https://www.sysnet.pe.kr/2/0/13940
저 소스 코드를 이용해 유사하게 구현할 수 있습니다.
namespace ConsoleApplication1;
partial class Program
{
static void Main(string[] args)
{
using (SystemInfo sysInfo = new SystemInfo())
{
byte[] cpuIdBytes = new byte[4 * 12]; // 48bytes
Span<byte> buffer = cpuIdBytes.AsSpan();
sysInfo.GetCpuId(buffer[0..4], 0x80000000);
if (BitConverter.ToUInt32(cpuIdBytes, 0) < 0x80000000)
{
Console.WriteLine("CPUID function 0x80000000 is not supported.");
return;
}
sysInfo.GetCpuId(buffer[0..16], 0x80000002);
sysInfo.GetCpuId(buffer[16..32], 0x80000003);
sysInfo.GetCpuId(buffer[32..48], 0x80000004);
buffer[47] = 0; // Ensure null termination for string conversion
string cpuName = System.Text.Encoding.ASCII.GetString(cpuIdBytes).TrimEnd('\0');
Console.WriteLine(cpuName); // 출력 예) "12th Gen Intel(R) Core(TM) i9-12900K"
}
}
}
참고로, 위와 같이 복잡하게 구현할 필요 없이 WMI를 이용하면 더 간단하게, 하지만 WMI의 초기화 특성상 다소 느린 속도로 구할 수 있습니다.
// Install-Package System.Management
try
{
ManagementObjectSearcher? searcher = new ("SELECT * FROM Win32_Processor");
ManagementObjectCollection? results = searcher?.Get();
if (results == null || results.Count == 0)
{
Console.WriteLine("No Processor information found.");
return;
}
foreach (ManagementObject obj in results)
{
Console.WriteLine("CPU Brand: " + obj["Name"]?.ToString()); // 출력 예) "CPU Brand: 12th Gen Intel(R) Core(TM) i9-12900K"
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
"
Why does Windows report my processor speed twice, with slightly different values?" 글의 내용 중에 마지막으로 흥미로운 부분은, CPU Brand 문자열이 쓰기가 가능하다는 점입니다.
Why you can’t trust CPUID
; https://chipsandcheese.com/p/why-you-cant-trust-cpuid
비록
MSR 레지스터를 사용하므로 Ring 0에서만 가능하지만, 어쨌든 그런 동작을 수행하는 device driver가 얼마든지 있을 수 있으므로 100% 신뢰할 수 없습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]