CPUキャッシュ(C)を最適化する際に重要なことは何ですか?


13

これら 2つの質問を読んで、メモリ内の大量のデータを扱う場合、CPUキャッシュの動作を理解することが重要になることがわかります。最適化ツールボックスに別のツールを追加するためのキャッシュの仕組みを理解したいと思います。

CPUキャッシュがうまく機能するように、キャッシュを賢明に使用するコードを書くことができる中核となる点は何ですか?これに関連して、コードのプロファイルを作成して、キャッシュの使用が悪いために速度が低下していないかどうかを確認する方法はありますか?


キャッシュはどこでも同じではありません。最も明らかに、それらはサイズが異なります。深い秘密を学ぶことは期待せず、良い実践(Michael Borgwardtのアドバイスのような)だけを学んでください。
デビッドソーンリー

回答:


17
  • 可能な限りデータを小さく保つ
  • 一緒に(または次々に)アクセスされるものをメモリ内で隣り合わせに保持する
  • コンパイラの最適化パラメーターについて学ぶ
  • すべてのプログラマーがメモリについて知っておくべきことを読んで、あなたが望むことができる以上の詳細を読んでください

+1「アクセスするものを互いに隣り合わせて保持する」ため。それは忘れやすいものです。
ドナルフェローズ

そして、最適化するようコンパイラーに指示します。
右折

@WTP:右-追加。
マイケルボルグワード

また、ミューテックスを十分に分離してください。ミューテックスを変更すると、すべてのCPUにあるすべてのキャッシュラインがフラッシュされるはずです。1つのキャッシュラインで2〜3個のミューテックスを取得できた場合、これはパフォーマンスに大きな影響を与える可能性があります。
Vatine

12

この問題の複雑さは、最近の人間の理解を超えています。(過去5年間からそうでした。)それを短ベクトル並列処理(SIMD)と組み合わせると、手作業でコードを最適化することはもはや経済的に実行不可能であるという絶望感があります-それは不可能ではありませんが、もう費用対効果がありません。

現在のアプローチは、さまざまな構造(ループ、データ構造、アルゴリズム)で同じ答えを計算するコードのバリエーションを作成し、パフォーマンスを自動的に評価することにより、最適化の方法をコンピューターに教えることに依存しています。コード変換のルールは非常に厳密な数学的モデルで指定されているため、コンピューター科学者が理解でき、コンピューターが実行できるものです。

以下はラリーオブライエン答えの 1つに投稿したリンクです。

http://onward-conference.org/2011/images/Pueschel_2011_AutomaticPerformanceProgramming_Onward11.pdf


2
最速のBLAS実装(GotoBLAS)は、手で最適化されたコードを使用して、行列乗算の最大キャッシュ使用を保証します
-quant_dev

2

キャッシュを理解して最適化することは非常に可能です。それはハードウェアを理解することから始まり、システムを制御し続けます。システムに対する制御が少ないほど、成功する可能性は低くなります。アイドル状態ではないアプリケーション/スレッドを実行しているLinuxまたはWindows。

ほとんどのキャッシュはプロパティが多少似ており、アドレスフィールドの一部を使用してヒットを探し、深さ(ウェイ)と幅(キャッシュライン)を持っています。いくつかは書き込みバッファを持ち、いくつかは書き込みなどでキャッシュをバイパスするように設定できます。

そのキャッシュにヒットする進行中のすべてのメモリトランザクションを鋭く認識する必要があります(一部のシステムでは、タスクを容易にする独立した命令キャッシュとデータキャッシュがあります)。

メモリを慎重に管理しないと、キャッシュを簡単に役に立たなくすることができます。たとえば、処理中のデータブロックが複数あり、それらをキャッシュに保持したいが、メモリのキャッシュヒット/ミスチェックと比較して偶数倍のアドレス、たとえば0x10000 0x20000 0x30000にあり、さらにこれらは、キャッシュ内のウェイよりも、キャッシュがオンの場合は非常に遅く、キャッシュがオフの場合よりも実行速度が非常に遅くなることがあります。ただし、これをおそらく0x10000、0x21000、0x32000に変更すると、キャッシュを最大限に活用して追い出しを減らすのに十分かもしれません。

結論として、キャッシュを最適化するための鍵は(システムを十分に理解していることを除いて)、パフォーマンスを必要とするすべてのものを同時にキャッシュに保持し、そのデータを整理できるようにすることです。すべて一度にキャッシュに入れます。また、コード実行、割り込み、その他の定期的またはランダムなイベントなどが、使用しているこのデータのかなりの部分を排除するのを防ぎます。

コードについても同じことが言えます。ただし、キャッシュに保持したい他のコードとの衝突を避けるために、コードが存在する場所を制御する必要があるため、少し難しくなります。キャッシュを通過するコードのテスト/プロファイリング中に、コードの1行をあちこちに追加したり、1つのnopを追加したり、コードが存在するアドレスをあるコードから別のコードにコンパイルまたは変更したり、キャッシュラインはそのコード内に含まれ、削除されるものと重要なセクションに含まれないものを変更します。


1

nwongMichael Borgwardtの両方答えが良いアドバイスを与えます。

また、これらの問題に関するコンパイラの最適化を最初に信頼してください。

最近のGCCコンパイラを使用している場合は、その__builtin_prefetch機能を(節約して)使用できます。stackoverflowでこの回答を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.