2013-07-21 11 views
5

私は、CPUに関する情報を読んでそれらを(CPU-Zのように)ユーザに表示するC#ソフトウェアを作ろうとしています。 私の現在の問題は、CPU周波数を表示する方法を見つけられなかったことです。CPUの周波数を得るための助けが必要です

まず、Win32_Processorクラスを使用して簡単な方法を試しました。 CPUがオーバークロック(またはアンダークロック)されている場合を除いて、非常に効率的でした。

はその後、私はシステム\ CentralProcessorは、CPUの "標準" クロック(オーバークロックしても)\ 0 \私のレジストリはHKLM \ HARDWAREの\説明に含まれていることを発見しました。問題は、現代のCPUでは、CPUがフルパワーを必要としないときにコア・マルチプライヤーが減少しているため、CPUの頻度も変化しますが、レジストリの値は変わりません。

次のステップでは、RdTSCを使用して実際にCPU周波数を計算しようとしていました。私はC++を使っていました。なぜなら、メソッドが動作していれば、C#プロジェクトに埋め込むことができるからです。私はhttp://www.codeproject.com/Articles/7340/Get-the-Processor-Speed-in-two-simple-ways に次のコードを見つけましたが、問題は同じでした:プログラムは私に最高の頻度(レジストリ値のように、1-2Mhzの差異)しか与えません。私はさらに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メソッドのいくつかのコードを試しましたが、正しく動作していません。

最後に、私はこのプログラムを作成するために使用されたコードを理解しようとしましたが、それはあまりにも複雑すぎました。

私の質問は、C + +やC#を使用して(CPUがオーバークロックされている場合でも)リアルタイムでCPU周波数を決定する方法ですか?私はこの質問が何度も尋ねられたことを知っていますが、実際に私の質問に答えている人はいません。

+1

ハイゼンベルグは87年前にこの正確さを得ることができないと予測しました。この質問に対する答えが必要でないことを確認してください。 –

+1

@ハンス:私はHeisenbergに問題を起こさないように希望の精度があると確信しています。 –

+0

私は、オーバークロックされているシステムであってもC/C++でこれを行う方法を示す答えを出しました。 –

答えて

8

はい、そのコードは1秒間100%ビジー状態になり、1秒間ビジー待機します。 1秒は、ダイナミッククロッキングアルゴリズムが負荷を検出し、省電力状態からCPU周波数を上げるのに十分な時間以上です。私はブースト付きのプロセッサが実際にあなたに表示された周波数よりも高い周波数を表示しても驚かないでしょう。

しかし、コンセプトは悪くありません。あなたがしなければならないのは、の睡眠です。約1秒間隔です。次に、RDTSC呼び出しがちょうど1秒離れていると仮定するのではなく、QueryPerformanceCounterで示される実際の時間で割ります。

はまた、私は台無しにあなたの結果をだろうRDTSCQueryPerformanceCounter間のコンテキストスイッチがあったかどうかを検出するために、QueryPerformanceCounter呼び出しの前と後の両方RDTSCをお調べします。


残念ながら、新しいプロセッサ上RDTSCは、実際にはCPUのクロックサイクルをカウントしません。これは動的に変化するCPUクロックレートを反映していません(ただし、ビジー待機なしで公称レートを測定するため、質問に記載されているコードよりも大幅に改善されています)。

あなたはすべての後にモデル固有のレジスタにアクセスする必要があると思いますようだから、見えます。どちらがcan't be done from user-modeです。 The OpenHardwareMonitor projectを使用することができるドライバの両方を持っており、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; 
} 

ほとんどのコンパイラは、あなたの代わりに__asmブロックのtscBefore = __rdtsc();を使用することができ、その場合には固有の__rdtsc()を、提供しています。残念なことに、どちらの方法もプラットフォーム固有とコンパイラ固有です。

+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)またはアンダークロック(過熱のため)する可能性があります。いくつかのプロセッサは、同じ速度でクロックを実行することで溶融を避けるために電力を削減しますが、クロック周波数の概念全体が意味をなさない時点では、いくつかのサイクルでしか動作しません。

この記事では、Windowsが気付かずにCPUが熱的に抑制されていた場所を分析したかなりの数のマシンについて説明します。

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

これを検出することは非常にプロセッサ固有のものですが、それは管理者権限が必要ですいくつかの厄介なコードを記述することも可能です。

私が指摘していることは、あなたが疑わしい質問をしていることです。ほとんどの場合、質問する必要はありません。レジストリの値を使用するか、CPUに何が実行されているかをWindowsに問い合わせてください(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

答えは本当に知りたいことによって異なります。

あなたが現在実行している特定のアプリケーションの動作周波数を見つけることが目的ならば、モデル固有のレジスタにアクセスするには管理者/ root権限が必要で、BIOSへのアクセスさえも必要とするのは難しい問題です。 WindowsではCPU-Z、Linuxではpowertopでこれを行うことができます。

しかし、例えば、ピークフロップを計算できるように、ロード中の1つまたは複数のスレッドのプロセッサの動作周波数を知りたいのであれば、これは次のように実行できます管理者権限を必要としない一般的なコードです。

私は、http://randomascii.wordpress.com/2013/08/06/defective-heat-sinks-causing-garbage-gaming/でBruce Dawsonのコードからアイデアを得ました。主にOpenMPを使用して複数のスレッドで作業するようにコードを拡張しました。

これはLinux、Windowsで、Nahalem、Ivy Bridge、Haswellなどのソケットで最大4ソケット(40スレッド)のソケットでテストしました。結果はすべて正解から0.5%未満である。

ここで周波数を決定する方法を説明しましたので、how-can-i-programmatically-find-the-cpu-frequency-with-cすべての詳細を繰り返すことはありません。

関連する問題