web-dev-qa-db-ja.com

x86 WindowsでCPUキャッシュをフラッシュするにはどうすればよいですか?

WindowsでCPUキャッシュを強制的にフラッシュすることに興味があります(ベンチマークの理由から、CPUキャッシュにデータがない状態でエミュレートしたい)。できれば、基本的なC実装またはWin32呼び出しです。

システムコールを使用してこれを行う既知の方法はありますか、または大きなmemcpyを言うのと同じくらい卑劣なものですらありますか?

Intel i686プラットフォーム(P4以上でも問題ありません)。

46
user183135

幸い、キャッシュを明示的にフラッシュする方法は複数あります。

「wbinvd」命令は、変更されたキャッシュコンテンツを書き戻し、キャッシュを空としてマークします。バスサイクルを実行して、外部キャッシュにデータをフラッシュさせます。残念ながら、これは特権付きの命令です。しかし、DOSのような環境でテストプログラムを実行することが可能な場合は、これが適切な方法です。これには、「OS」のキャッシュフットプリントを非常に小さく保つという利点があります。

さらに、「invd」命令があり、キャッシュを無効化せずにキャッシュをメインメモリにフラッシュバックします。これはメインメモリとキャッシュの一貫性に違反するため、自分で対処する必要があります。あまりお勧めしません。

ベンチマークの目的で、最も簡単な解決策は、WBではなくWC(書き込み結合)でマークされた領域に大きなメモリブロックをコピーすることです。グラフィックカードのメモリマップ領域が適切な候補です。または、MTRRレジスタを使用して、自分で領域をWCとしてマークできます。

クロックサイクルを測定し、パフォーマンスを監視するためのテストプログラムで、短いルーチンのベンチマークに関するいくつかのリソースを見つけることができます。

52
Gunther Piez

CPUに特定のキャッシュラインをフラッシュするよう強制するx86アセンブリ命令( [〜#〜] clflush [〜#〜] など)がありますが、かなりあいまいです。特にCLFLUSHは、L1キャッシュから選択したアドレスのみをフラッシュします。

大きなメモリコピーを言うのと同じくらい卑劣な何か?

はい、これは最も簡単なアプローチであり、CPUがすべてのレベルのキャッシュをフラッシュすることを確認します。ベンチマークからキャッシュフラッシュ時間を除外するだけで、キャッシュプレッシャーのもとでプログラムがどのように動作するかがわかります。

8
intgr

残念ながら、キャッシュを明示的にフラッシュする方法はありません。オプションのいくつかは次のとおりです。

1.)ベンチマークしているコードの反復間で非常に大きなメモリ操作を実行して、キャッシュをスラッシュします。

2.) x86 Control Registers でキャッシュを無効にし、それをベンチマークします。これにより、おそらく命令キャッシュも無効になります。

3.) 非一時的命令 を使用して、ベンチマーク(可能な場合)のコード部分を実装します。ただし、これらはキャッシュの使用に関するプロセッサーへのヒントにすぎませんが、必要なことを実行することはまだ自由です。

1はおそらく最も簡単で目的に十分です。

編集:おっと、x86キャッシュを無効にするための指示があるので修正しました。drhirschの回答を参照してください

2
Falaina

x86命令WBINVDは、すべてのキャッシュをライトバックして無効にします。それは と記述されています

プロセッサの内部キャッシュ内の変更されたすべてのキャッシュラインをメインメモリに書き戻し、内部キャッシュを無効にします(フラッシュします)。次に、この命令は、外部キャッシュに変更されたデータも書き戻すように指示する特殊機能バスサイクルと、外部キャッシュを無効にする必要があることを示す別のバスサイクルを発行します。

重要なことに、この命令はring0、つまりオペレーティングシステムでのみ実行できます。したがって、ユーザーランドプログラムはそれを単純に使用することはできません。 Linuxでは、その命令をオンデマンドで実行できるカーネルモジュールを作成できます。実際、誰かがそのようなカーネルモジュールをすでに書いています: https://github.com/batmac/wbinvd

幸いなことに、カーネルモジュールのコードは非常に小さいため、インターネット上の見知らぬ人からカーネルにコードをロードする前に、実際に確認できます。たとえば、/proc/wbinvdを介してcat /proc/wbinvdを読み取ることで、そのモジュールを使用(およびWBINVD命令をトリガーする)できます。

ただし、この命令(または少なくともこのカーネルモジュール)は本当に遅いことがわかりました。私のi7-6700HQで750µsと測定しました!この数は私には本当に高いようですので、私はこれを測定するのを間違えたかもしれません-覚えておいてください!その指示の説明はただ言う:

WBINVDが完了するまでの時間またはサイクルの量は、さまざまなキャッシュ階層のサイズやその他の要因によって異なります。

1