Microsoft MVP성태의 닷넷 이야기
닷넷: 2334. C# - cpuid 명령어를 이용한 CPU 제조사 문자열 가져오기 [링크 복사], [링크+제목 복사],
조회: 1823
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일

(시리즈 글이 6개 있습니다.)
.NET Framework: 314. C++의 inline asm 사용을 .NET으로 포팅하는 방법
; https://www.sysnet.pe.kr/2/0/1267

개발 환경 구성: 240. Visual C++ / x64 환경에서 inline-assembly를 매크로 어셈블리로 대체하는 방법
; https://www.sysnet.pe.kr/2/0/1759

.NET Framework: 543. C++의 inline asm 사용을 .NET으로 포팅하는 방법 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/10889

VS.NET IDE: 127. Visual C++ / x64 환경에서 inline-assembly를 매크로 어셈블리로 대체하는 방법 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/11691

C/C++: 188. C++의 32비트 + Release 어셈블리 코드를 .NET으로 포팅할 때 주의할 점
; https://www.sysnet.pe.kr/2/0/13940

닷넷: 2334. C# - cpuid 명령어를 이용한 CPU 제조사 문자열 가져오기
; https://www.sysnet.pe.kr/2/0/13941




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_brand_1.png

사용자에 따라서는 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(&regs[0], 0x80000000);

    if (regs[0] < 0x80000004)
        return 1;

    getCpuId(&regs[0], 0x80000002);
    getCpuId(&regs[4], 0x80000003);
    getCpuId(&regs[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% 신뢰할 수 없습니다.




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







[최초 등록일: ]
[최종 수정일: 6/3/2025]

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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13750정성태10/1/20246591C/C++: 175. C++ - WinMain/wWinMain 호출 전의 CRT 초기화 단계
13749정성태9/30/20246676닷넷: 2302. C# - ssh-keygen으로 생성한 Private Key와 Public Key 연동파일 다운로드1
13748정성태9/29/20247298닷넷: 2301. C# - BigInteger 타입이 byte 배열로 직렬화하는 방식
13747정성태9/28/20248208닷넷: 2300. C# - OpenSSH의 공개키 파일에 대한 "BEGIN OPENSSH PUBLIC KEY" / "END OPENSSH PUBLIC KEY" PEM 포맷파일 다운로드1
13746정성태9/28/20247001오류 유형: 924. Python - LocalProtocolError("Illegal header value ...")
13745정성태9/28/20246950Linux: 80. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (lldb)
13744정성태9/27/20247681닷넷: 2299. C# - Windows Hello 사용자 인증 다이얼로그 표시하기파일 다운로드1
13743정성태9/26/20248284닷넷: 2298. C# - Console 프로젝트에서의 await 대상으로 Main 스레드 활용하는 방법 [1]
13742정성태9/26/20248264닷넷: 2297. C# - ssh-keygen으로 생성한 ecdsa 유형의 Public Key 파일 해석 [1]파일 다운로드1
13741정성태9/25/20247854디버깅 기술: 202. windbg - ASP.NET MVC Web Application (.NET Framework) 응용 프로그램의 덤프 분석 시 요령
13740정성태9/24/20247283기타: 86. RSA 공개키 등의 modulus 값에 0x00 선행 바이트가 있는 이유(ASN.1 인코딩)
13739정성태9/24/20247533닷넷: 2297. C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성 [1]파일 다운로드1
13738정성태9/22/20247138C/C++: 174. C/C++ - 윈도우 운영체제에서의 file descriptor, FILE*파일 다운로드1
13737정성태9/21/20247774개발 환경 구성: 727. Visual C++ - 리눅스 프로젝트를 위한 빌드 서버의 msbuild 구성
13736정성태9/20/20247953오류 유형: 923. Visual Studio Code - Could not establish connection to "...": Port forwarding is disabled.
13735정성태9/20/20247298개발 환경 구성: 726. ARM 플랫폼용 Visual C++ 리눅스 프로젝트 빌드
13734정성태9/19/20246867개발 환경 구성: 725. ssh를 이용한 원격 docker 서비스 사용
13733정성태9/19/20247678VS.NET IDE: 194. Visual Studio - Cross Platform / "Authentication Type: Private Key"로 접속하는 방법
13732정성태9/17/20248011개발 환경 구성: 724. ARM + docker 환경에서 .NET 8 설치
13731정성태9/15/20248350개발 환경 구성: 723. C# / Visual C++ - Control Flow Guard (CFG) 활성화 [1]파일 다운로드2
13730정성태9/10/20249037오류 유형: 922. docker - RULE_APPEND failed (No such file or directory): rule in chain DOCKER
13729정성태9/9/20249791C/C++: 173. Windows / C++ - AllocConsole로 할당한 콘솔과 CRT 함수 연동 [1]파일 다운로드1
13728정성태9/7/20249340C/C++: 172. Windows - C 런타임에서 STARTUPINFO의 cbReserved2, lpReserved2 멤버를 사용하는 이유파일 다운로드1
13727정성태9/6/202410167개발 환경 구성: 722. ARM 플랫폼 빌드를 위한 미니 PC(?) - Khadas VIM4 [1]
13726정성태9/5/20248755C/C++: 171. C/C++ - 윈도우 운영체제에서의 file descriptor와 HANDLE파일 다운로드1
13725정성태9/4/20247284디버깅 기술: 201. WinDbg - sos threads 명령어 실행 시 "Failed to request ThreadStore"
1  2  3  4  5  6  7  8  9  [10]  11  12  13  14  15  ...