37

CPUzのようなプログラムは、システムに関する詳細な情報(バス速度、メモリタイミングなど)を提供するのに非常に優れています。

ただし、CPU固有の情報を処理することなく、コアごと(および、CPUごとに複数のコアを持つマルチプロセッサシステムではプロセッサごと)の周波数を計算するプログラム的な方法はありますか。

システム内のすべてのアクティブコア(すべてのプロセッサ)のベンチマーク実行中にCPUクロックを記録できる、不正行為防止ツール(クロックが制限されたベンチマーク競争で使用するため)を開発しようとしています。

4

6 に答える 6

36

ここで私のコメントを拡張します。これは大きすぎて詳細で、コメントに収めることができません。

あなたがやろうとしていることは非常に困難です-以下の理由で非現実的であるという点まで:

  • プロセッサ周波数を取得するためのポータブルな方法はありません。SpeedStepやTurboBoostなどの効果により、常に正しい周波数が得られるとはrdtsc限りません。
  • 周波数を測定するためのすべての既知の方法は、時間を正確に測定する必要があります。ただし、決定された詐欺師は、システム内のすべてのクロックとタイマーを改ざんする可能性があります。
  • 不正開封防止の方法でプロセッサの周波数と時間を正確に読み取るには、カーネルレベルのアクセスが必要です。これは、Windowsのドライバー署名を意味します。

プロセッサ周波数を取得するためのポータブルな方法はありません。

CPU周波数を取得する「簡単な」方法はrdtsc、一定の期間を挟んで2回呼び出すことです。次に、差を分割すると、頻度がわかります。

問題はrdtsc、プロセッサの真の周波数が得られないことです。ゲームなどのリアルタイムアプリケーションはこれに依存しているため、rdtscCPUスロットリングとターボブーストを通じて一貫性を保つ必要があります。したがって、システムが起動rdtscすると、常に同じ速度で実行されます(SetFSBなどでバス速度をいじり始めない限り)。

たとえば、私のCore i7 2600Kでは、rdtsc常に。の周波数が表示され3.4 GHzます。しかし実際には、でアイドル状態になり、でオーバークロックされたターボブーストマルチプライヤを介して負荷がかかった状態1.6 GHzでクロックアップします。4.6 GHz46x

しかし、真の周波数を測定する方法を見つけたら(または、十分満足している場合)、スレッドアフィニティrdtscを使用して各コアの周波数を簡単に取得できます。

真の周波数を取得する:

プロセッサの実際の周波数を取得するには、MSR(モデル固有のレジスタ)またはハードウェアパフォーマンスカウンタのいずれかにアクセスする必要があります。

これらはカーネルレベルの命令であるため、ドライバーを使用する必要があります。したがって、配布を目的としてWindowsでこれを試行する場合は、適切なドライバー署名プロトコルを実行する必要があります。さらに、コードはプロセッサのメーカーとモデルによって異なるため、プロセッサの世代ごとに異なる検出コードが必要になります。

この段階に到達すると、頻度を読み取るさまざまな方法があります。

Intelプロセッサでは、ハードウェアカウンタを使用して生のCPUサイクルをカウントできます。リアルタイムを正確に測定する方法(次のセクション)と組み合わせると、真の周波数を計算できます。MSRを使用すると、CPU周波数乗数などの他の情報にアクセスできます。


周波数を測定するためのすべての既知の方法では、時間を正確に測定する必要があります。

これはおそらくより大きな問題です。周波数を測定するにはタイマーが必要です。有能なハッカーは、C /C++で使用できるすべての時計を改ざんすることができます。これには、次のすべてが含まれます。

  • clock()
  • gettimeofday()
  • QueryPerformanceCounter()
  • 等...

リストはどんどん増えていきます。言い換えれば、有能なハッカーがすべてのタイマーをスプーフィングできるため、どのタイマーも信頼できません。たとえばclock()gettimeofday()OS内でシステムクロックを直接変更することでだまされる可能性があります。だましQueryPerformanceCounter()は難しいです。

時間の真の測定値を取得する:

上記のすべてのクロックは、同じシステムベースクロックから何らかの方法で派生していることが多いため、脆弱です。そして、そのシステムベースクロックは、多くの場合、システムベースクロックに関連付けられています。これは、システムがオーバークロックユーティリティを使用してすでに起動した後に変更できます。

したがって、信頼性が高く改ざんされない時間測定を行う唯一の方法は、HPETACPIなどの外部クロックを読み取ることです。残念ながら、これらもカーネルレベルのアクセスを必要とするようです。


要約する:

あらゆる種類の改ざん防止ベンチマークを構築するには、ほぼ確実に、Windowsの証明書署名を必要とするカーネルモードドライバーを作成する必要があります。これは、多くの場合、カジュアルなベンチマークライターにとっては負担が大きすぎます。

これにより、改ざん防止ベンチマークが不足し、近年の競争力のあるオーバークロックコミュニティの全体的な衰退の一因となった可能性があります。

于 2011-12-02T07:32:23.290 に答える
3

私はこれがすでに答えられていることを理解しています。また、これは基本的にブラックアートであると認識しているので、それを取るか、そのままにしておくか、フィードバックを提供してください。

スロットルされた(microsft、hp、およびdellに感謝)HyperVホスト(信頼性の低いパフォーマンスカウンター)およびHyperVゲスト(現在ではなく、ストックCPU速度のみを取得できる)のクロックレートを見つけるために、試行エラーとfluke、クロックごとに1回だけループするループを作成します。

次のようにコーディングします-C#5.0、SharpDev、32ビット、Target 3.5、Optimize on(重要)、デバッガーなしアクティブ(重要)

        long frequency, start, stop;
        double multiplier = 1000 * 1000 * 1000;//nano
        if (Win32.QueryPerformanceFrequency(out frequency) == false)
            throw new Win32Exception();

        Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
        const int gigahertz= 1000*1000*1000;
        const int known_instructions_per_loop = 1; 

        int iterations = int.MaxValue;
        int g = 0;

        Win32.QueryPerformanceCounter(out start);
        for( i = 0; i < iterations; i++)
        {
            g++;
            g++;
            g++;
            g++;
        }
        Win32.QueryPerformanceCounter(out stop);

        //normal ticks differs from the WMI data, i.e 3125, when WMI 3201, and CPUZ 3199
        var normal_ticks_per_second = frequency * 1000;
        var ticks = (double)(stop - start);
        var time = (ticks * multiplier) /frequency;
        var loops_per_sec = iterations / (time/multiplier);
        var instructions_per_loop = normal_ticks_per_second  / loops_per_sec;

        var ratio = (instructions_per_loop / known_instructions_per_loop);
        var actual_freq = normal_ticks_per_second / ratio;

        Console.WriteLine( String.Format("Perf counhter freq: {0:n}", normal_ticks_per_second));
        Console.WriteLine( String.Format("Loops per sec:      {0:n}", loops_per_sec));
        Console.WriteLine( String.Format("Perf counter freq div loops per sec: {0:n}", instructions_per_loop));
        Console.WriteLine( String.Format("Presumed freq: {0:n}", actual_freq));
        Console.WriteLine( String.Format("ratio: {0:n}", ratio));

ノート

  • デバッガーがアクティブな場合、ループごとに25命令
  • プロセッサをスピンアップするために、事前に2秒または3秒のループを実行することを検討してください(または、最近サーバーがどれほど厳しく抑制されているかを知って、少なくともスピンアップを試みてください)
  • 64ビットCore2およびHaswellPentiumでテストされ、CPU-Zと比較されました
于 2015-08-08T03:17:51.040 に答える
2

私は以前にこの主題について(基本的なアルゴリズムとともに)投稿しました:ここ。私の知る限り、アルゴリズム(説明を参照)は非常に正確です。たとえば、Windows7は私のCPUクロックを2.00GHz、CPU-Zを1994-1996 MHz、アルゴリズムを1995025-1995075kHzと報告します。

アルゴリズムはこれを行うために多くのループを実行します。これにより、CPU周波数が最大に増加するため(ベンチマーク中も同様)、速度調整ソフトウェアは機能しません。

ここここの追加情報。

速度調整の問題については、アプリケーションが速度値を使用して経過時間を決定し、時間自体が非常に重要である場合を除いて、実際には問題とは見なされません。たとえば、分割を完了するためにxクロックサイクルが必要な場合、CPUが3GHzまたは300MHzで実行されているかどうかは関係ありません。それでもxクロックサイクルが必要であり、唯一の違いは、分割が10分の1で完了することです。 @3GHzでの時間の。

于 2011-12-13T10:58:21.387 に答える
2

これを行う最も簡単な方法の1つはを使用することですがRDTSC、これは不正行為防止メカニズム用であるため、カーネルドライバーまたはハイパーバイザーに常駐するコードとしてこれを配置します。

おそらく、独自のタイミングコード**をロールする必要もあります。これも次の方法で実行できますRDTSC(以下の例で使用されているQPCはを使用しますRDTSC。実際、リバースエンジニアリングしてのローカルコピーを使用するのは非常に簡単です。つまり、それを改ざんする、あなたはあなたのドライバーを改ざんする必要があるでしょう)。

void GetProcessorSpeed()
{
    CPUInfo* pInfo = this;
    LARGE_INTEGER qwWait, qwStart, qwCurrent;
    QueryPerformanceCounter(&qwStart);
    QueryPerformanceFrequency(&qwWait);
    qwWait.QuadPart >>= 5;
    unsigned __int64 Start = __rdtsc();
    do
    {
        QueryPerformanceCounter(&qwCurrent);
    }while(qwCurrent.QuadPart - qwStart.QuadPart < qwWait.QuadPart);
    pInfo->dCPUSpeedMHz = ((__rdtsc() - Start) << 5) / 1000000.0;
}

** @Mysticalが述べたように、これはセキュリティのためですが、低レベルのシステムタイミングメカニズムを破壊したいという衝動を感じたことがないので、もっと複雑になる可能性があります。Mysticalがそれに何かを追加できればいいでしょう:)

于 2011-12-02T07:23:58.237 に答える
1

このホワイトペーパーを参照してください:インテル®Core™マイクロアーキテクチャー(Nehalem)ベースのプロセッサーにおけるインテル®ターボブーストテクノロジー。基本的に、サンプル期間TにわたってUCC固定パフォーマンスカウンターの複数の読み取りを生成します。

Relative.Freq = Delta(UCC)  / T

Where:
   Delta() = UCC @ period T
                 - UCC @ period T-1

Nehalemアーキテクチャから始めて、UCCは、コアのUnhalted状態に比べてクリックティックの数を増減します。

SpeedStepまたはTurboBoostがアクティブになると、UCCを使用した推定周波数がそれに応じて測定されます。TSCは一定のままです。たとえば、ターボブーストの動作は、Delta(UCC)がDelta(TSC)以上であることを示しています。

Cyringでの関数Core_Cycle関数の例| CoreFreqGitHub

于 2016-10-10T04:48:24.367 に答える
1

CallNtPowerInformationを使用する必要があります。これがputilプロジェクトのコードサンプルです。これにより、現在および最大のCPU周波数を取得できます。私の知る限り、CPUごとの周波数を取得することはできません。

于 2017-01-20T17:39:36.550 に答える