2013-07-21 2 views
5

CPU에 관한 정보를 읽고이를 CPU-Z와 같이 사용자에게 표시하는 C# 소프트웨어를 만들려고합니다. 현재 문제는 CPU 빈도를 표시하는 방법을 찾지 못했기 때문입니다.CPU 주파수를 얻는 데 도움이 필요합니다.

처음에는 Win32_Processor 클래스을 사용하여 쉬운 방법을 시도했습니다. CPU가 오버 클럭 된 경우 (또는 언더 클럭 된 경우)를 제외하고는 매우 효율적입니다.

그럼, 내 레지스트리 HKLM \ 하드웨어 \ 설 \ 시스템에 포함 된 것을 발견 \ CentralProcessor 0 CPU의 "표준"시계 \ (심지어 경우는 오버 클럭). 문제는 최신 CPU의 경우 CPU가 최대 전력을 필요로하지 않을 때 코어 배율이 감소하므로 CPU 빈도도 변경되지만 레지스트리의 값은 동일하게 유지된다는 것입니다.

다음 단계에서 RdTSC을 사용하여 실제로 CPU 빈도를 계산하려고했습니다. 메서드가 작동하면 C# 프로젝트에 포함시킬 수 있으므로 C++을 사용했습니다. 나는 http://www.codeproject.com/Articles/7340/Get-the-Processor-Speed-in-two-simple-ways 에 다음 코드를 발견했으나 문제는 동일했다. 프로그램은 최대 빈도 (레지스트리 값 1-2 Mhz 차이와 같이) 만 제공하고 CPU를로드해야하는 것보다 더 많이 보인다. 나는 심지어 CPU 부하가 급증했다.)

#include "stdafx.h" 
#include <windows.h> 
#include <cstdlib> 
#include "intrin.h" 
#include <WinError.h> 
#include <winnt.h> 

float ProcSpeedCalc() { 

#define RdTSC __asm _emit 0x0f __asm _emit 0x31 

    // variables for the clock-cycles: 
    __int64 cyclesStart = 0, cyclesStop = 0; 
    // variables for the High-Res Preformance Counter: 
    unsigned __int64 nCtr = 0, nFreq = 0, nCtrStop = 0; 

    // retrieve performance-counter frequency per second: 
    if(!QueryPerformanceFrequency((LARGE_INTEGER *) &nFreq)) 
     return 0; 

    // retrieve the current value of the performance counter: 
    QueryPerformanceCounter((LARGE_INTEGER *) &nCtrStop); 

    // add the frequency to the counter-value: 
    nCtrStop += nFreq; 


    _asm 
    {// retrieve the clock-cycles for the start value: 
     RdTSC 
     mov DWORD PTR cyclesStart, eax 
     mov DWORD PTR [cyclesStart + 4], edx 
    } 

    do{ 
    // retrieve the value of the performance counter 
    // until 1 sec has gone by: 
     QueryPerformanceCounter((LARGE_INTEGER *) &nCtr); 
     }while (nCtr < nCtrStop); 

    _asm 
    {// retrieve again the clock-cycles after 1 sec. has gone by: 
     RdTSC 
     mov DWORD PTR cyclesStop, eax 
     mov DWORD PTR [cyclesStop + 4], edx 
    } 

    // stop-start is speed in Hz divided by 1,000,000 is speed in MHz 
    return ((float)cyclesStop-(float)cyclesStart)/1000000; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 

    while(true) 
    { 
     printf("CPU frequency = %f\n",ProcSpeedCalc()); 
     Sleep(1000); 
    } 

    return 0; 
} 

또한 저는 AMD CPU에서 마지막 방법을 테스트했음을 언급해야합니다. 또한 RdTSC 메서드에 대해 다른 코드를 시도했지만 제대로 작동하지 않습니다.

마지막으로이 프로그램을 만드는 데 사용 된 코드를 이해하려고 시도했지만 https://code.google.com/p/open-hardware-monitor/source/browse/이지만 너무 복잡했습니다.

그래서, 내 질문은 : 어떻게 C + + 또는 C#을 사용하여 실시간으로 (CPU가 오버 클럭 된 경우에도) CPU 주파수를 결정하는 것입니다? 나는이 질문이 많은 시간을 물었지만 아무도 실제로 내 질문에 답하지 않는다는 것을 안다.

+1

하이젠 베르크 (Heisenberg)는 87 년 전에 이것을 정확히 예측할 수 없다고 예측했습니다. 이 질문에 대한 답이 필요하지 않은지 확인하십시오. –

+1

@ 한스 : 원하는 정확도가 하이젠 베르크에서 문제를 일으키지 않을 것이라고 확신합니다. –

+0

나는 오버 클러킹 된 시스템에서도 C/C++로이를 수행하는 방법을 보여주는 답을 주었다. –

답변

8

예, 해당 코드가 1 초 동안 100 % 사용 중이므로 전체 초 동안 대기하고 통화 대기합니다. 1 초는 동적 클록 킹 알고리즘이 부하를 감지하고 절전 상태에서 CPU 주파수를 높이기에 충분한 시간입니다. 부스트가있는 프로세서가 실제로 사용자에게 표시된 주파수보다 높은 주파수를 표시하면 나는 놀라지 않을 것입니다.

그러나 개념은 나쁘지 않습니다. 당신이해야 할 일은 약 1 초 간격으로 수면입니다. 그런 다음 RDTSC 호출이 정확히 1 초 간격으로 수행되었다고 가정하는 대신 QueryPerformanceCounter으로 표시된 실제 시간으로 나눕니다.

또한, 나는 RDTSC 및 엉망 결과를 것 QueryPerformanceCounter 사이에 컨텍스트 스위치가 있었다 여부를 감지하기 위해, 이전과 QueryPerformanceCounter 호출 후 모두 RDTSC을 확인하는 것이 좋습니다.


불행히도 새 프로세서의 RDTSC은 실제로 CPU 클록주기를 계산하지 않습니다. 따라서 이것은 동적으로 변화하는 CPU 클록 속도를 반영하지 않습니다 (그렇다고해서 혼잡하지 않고 명목상의 속도를 측정하기 때문에 질문에 제공된 코드보다 큰 개선점입니다).당신이 결국 모델 별 레지스터를 액세스해야 할 것 같은 Bruce Dawson explained this in a blog post

  • 그래서 그것은 본다. 어느 can't be done from user-mode. The OpenHardwareMonitor project는 대부분의 컴파일러가 대신 __asm 블록의 tscBefore = __rdtsc();를 사용할 수있는 경우 고유 __rdtsc()를 제공하는 사용 된 할 수 있습니다 드라이버와 code for the frequency calculations


    float ProcSpeedCalc() 
    { 
        /* 
         RdTSC: 
          It's the Pentium instruction "ReaD Time Stamp Counter". It measures the 
          number of clock cycles that have passed since the processor was reset, as a 
          64-bit number. That's what the <CODE>_emit</CODE> lines do. 
        */ 
        // Microsoft inline assembler knows the rdtsc instruction. No need for emit. 
    
        // variables for the CPU cycle counter (unknown rate): 
        __int64 tscBefore, tscAfter, tscCheck; 
        // variables for the Performance Counter 9steady known rate): 
        LARGE_INTEGER hpetFreq, hpetBefore, hpetAfter; 
    
    
        // retrieve performance-counter frequency per second: 
        if (!QueryPerformanceFrequency(&hpetFreq)) return 0; 
    
        int retryLimit = 10;  
        do { 
         // read CPU cycle count 
         _asm 
         { 
          rdtsc 
          mov DWORD PTR tscBefore, eax 
          mov DWORD PTR [tscBefore + 4], edx 
         } 
    
         // retrieve the current value of the performance counter: 
         QueryPerformanceCounter(&hpetBefore); 
    
         // read CPU cycle count again, to detect context switch 
         _asm 
         { 
          rdtsc 
          mov DWORD PTR tscCheck, eax 
          mov DWORD PTR [tscCheck + 4], edx 
         } 
        } while ((tscCheck - tscBefore) > 800 && (--retryLimit) > 0); 
    
        Sleep(1000); 
    
        do { 
         // read CPU cycle count 
         _asm 
         { 
          rdtsc 
          mov DWORD PTR tscAfter, eax 
          mov DWORD PTR [tscAfter + 4], edx 
         } 
    
         // retrieve the current value of the performance counter: 
         QueryPerformanceCounter(&hpetAfter); 
    
         // read CPU cycle count again, to detect context switch 
         _asm 
         { 
          rdtsc 
          mov DWORD PTR tscCheck, eax 
          mov DWORD PTR [tscCheck + 4], edx 
         } 
        } while ((tscCheck - tscAfter) > 800 && (--retryLimit) > 0); 
    
        // stop-start is speed in Hz divided by 1,000,000 is speed in MHz 
        return (double)(tscAfter - tscBefore)/(double)(hpetAfter.QuadPart - hpetBefore.QuadPart) * (double)hpetFreq.QuadPart/1.0e6; 
    } 
    

    모두 있습니다. 플랫폼과 컴파일러에 따라 두 가지 방법이 있습니다.

+0

좀 도와 주실 수 있나요? 이 코드는 제 것이 아니며 QueryPerformanceCounter가 실제로 어떻게 작동하는지 알지 못합니다. – TheQuestioner

+0

@TheQuestioner : 컴퓨터에는 HPET라고하는 고정밀 이벤트 타이머가 있습니다. 주파수는 CPU 주파수보다 낮지 만 전원을 절약하기 위해 변경되지 않습니다 (HPET가 멈출 수있는 실제 절전 모드이지만 Cool'n'Quiet/SpeedStep/TurboBoost 효과는 걱정됩니까?). 'QueryPerformanceCounter'는 HPET에서 카운트를 읽고,'QueryPerformanceFrequency'는 빈도를 알려줍니다. –

+0

그래서 CPU 주파수와 HPET 주파수의 비율을 알아 내고 HPET 주파수를 곱하십시오. 또는 HPET를 사용하여 경과 시간을 계산하고이를 사용하여 CPU 빈도를 계산하십시오. 같은 문제를 보는 방법은 여러 가지가 있습니다. –

0

귀하의 질문에 근본적으로 대답 할 수 없습니다. CPU 주파수는 계속 변합니다. 때로는 OS가 변경 사항을 알고 있고 알려줄 수도 있지만 가끔은 그렇지 않습니다. CPU가 스스로 오버 클러킹 (TurboBoost)하거나 스스로 과열 (overheating) 할 수 있습니다. 일부 프로세서는 동일한 속도로 클럭을 실행하여 용융을 피하기 위해 전력을 줄이지 만 일부주기에서는 작동하지만 클록 주파수의 전체 개념은 의미가 없습니다.

이 게시물에서는 Windows가 눈치 채지 않고 CPU가 열적으로 조절되는 곳을 분석 한 상당한 수의 기계에 대해 이야기합니다.

http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/

매우 프로세서가이를 감지 할 특정 일부 지저분한 코드를 작성하는 것이 가능하지만, 관리자 권한이 필요합니다.

요점은 당신이 답할 수없는 질문을하고 있으며, 대부분의 경우 질문해야하는 질문이 아니라는 것입니다. 레지스트리의 값을 사용하거나 Windows에서 CPU가 실행중인 빈도를 물어보십시오 (PROCESSOR_POWER_INFORMATION 참고).

+3

CPU-Z와 동일한 데이터를 표시하는 것은 근본적으로 응답 할 수 없습니다. CPU-Z는 이것이 가능하다는 증거입니다. 그리고 전체 블로그 기사는 유용하다는 증거입니다. –

+0

답변을 받으실 때가되면 구식입니다. 그것은 하나의 문제입니다. 그리고 많은 인텔 CPU에서 열 조절은 대부분의 틱에서 아무 것도 수행되지 않도록 듀티 사이클을 변경하여 처리됩니다. 즉, CPU-Z는 CPU가 2.0 GHz에서 작동하는 것을 보여줄 수 있지만 과열시 듀티 사이클은 0.5 GHz 일 수 있습니다. CPU-Z는 숫자를 표시하지만 항상 의미있는 것은 아닙니다. 주파수와 듀티 사이클을 모니터링하여 답을 얻을 수는 있지만 어느 시점에서는 약간의 차이가 있습니다. 나는 완전히 의존적 인 정수 덧셈에 의해 빈도를 측정하지만, 꽤 잘 작동하지만, 끔찍한 해킹이다. –

+0

그래, 알아 내고 싶었던 CPU-Z 의미없는 번호 였어. 주파수를 보여줄 수있는 CPU-Z와 같은 프로그램도 많이 있습니다. 따라서 제 질문은 "근본적으로 답할 수 없습니다". 그러나 어쨌든, 저는 거의 1 년 전에이 프로젝트를 포기했습니다. – TheQuestioner

1

답변은 정말로 알고 싶은 것에 달려 있습니다.

현재 실행중인 특정 응용 프로그램의 작동 빈도를 찾는 것이 목표라면 모델 별 레지스터에 액세스하려면 관리자/루트 권한이 필요하며 BIOS에 액세스 할 수도있는 어려운 문제입니다. Windows에서는 CPU-Z로, Linux에서는 powertop으로이 작업을 수행 할 수 있습니다.

그러나 피크 플럽을 계산할 수 있도록로드 된 하나 이상의 스레드에 대한 프로세서의 작동 빈도를 알고 싶다면 (이것이 내가이 점을 염려하는 이유입니다) 그러면 다음을 수행 할 수 있습니다 관리자 권한이 필요없는 일반적인 코드.

나는 브루스 도슨 (Bruce Dawson)의 코드에서 http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/으로 아이디어를 얻었다. 주로 OpenMP를 사용하여 여러 스레드에서 작동하도록 코드를 확장했습니다.

Linux, Windows에서 Nahalem, Ivy Bridge 및 Haswell을 포함하여 최대 4 개의 소켓 (40 개 스레드)이있는 소켓에서 테스트했습니다. 결과는 모두 정답에서 0.5 % 미만으로 벗어났습니다.

여기서 주파수를 결정하는 방법을 설명 했으므로 how-can-i-programmatically-find-the-cpu-frequency-with-c 모든 세부 정보는 반복하지 않습니다.

관련 문제