質問
C ++プログラムを設計する際にキャッシュミスの可能性を減らす方法は?
インライン関数は毎回役立ちますか?または、プログラムがCPUに制限されている(つまり、プログラムがI / O指向ではなく計算指向である)場合にのみ適切ですか?
解決
この種のコードを作成する際に考慮すべき点がいくつかあります。
- <!> quot;配列の構造<!> quot;または<!> quot;構造の配列<!> quot;。どちらを使用するかは、データの各部分によって異なります。
- キャッシュ行を均等にパックするために、構造を32バイトの倍数に保つようにしてください。
- データをホットエレメントとコールドエレメントに分割します。クラスoのオブジェクトの配列があり、ox、oy、ozを頻繁に一緒に使用するが、まれにoi、oj、okにアクセスする必要がある場合は、ox、oy、ozをまとめてi、j、およびkは並列a窩データ構造に分割します。
- データの多次元配列がある場合、通常の行順序レイアウトでは、優先次元に沿ってスキャンするときのアクセスは非常に速く、他の次元に沿ってアクセスするのは非常に遅くなります。 スペースを埋める 曲線を使用すると、任意の次元を移動する際のアクセス速度のバランスを取ることができます。 (ブロッキングのテクニックは似ています-基数の大きいZオーダーです。)
- キャッシュミスが発生する必要がある場合は、コストを償却するために、可能な限りそのデータを使用してください。
- マルチスレッドを実行していますか?キャッシュ一貫性プロトコルの速度低下に注意してください。フラグと小さなカウンターをパディングして、別々のキャッシュラインに配置します。
- IntelのSSEは、事前に十分にアクセスするものを知っている場合、プリフェッチ組み込み関数を提供します。
他のヒント
このトピックについて言及しているHerb Sutterによる非常に素晴らしいビデオがありますこちら
データバインド操作の場合
-
配列を使用<!> amp;リスト上のベクトル、マップ<!> amp;セット
-
列の行ごとに処理
CPUがデータを効率的にプリフェッチできるようにします。たとえば、列ではなく行、ループの展開などによって多次元配列を処理するキャッシュミスの数を減らすことができます。
この種の最適化はハードウェアアーキテクチャに依存するため、Intel VTuneなどのプラットフォーム固有のプロファイラーを使用して、キャッシュで発生する可能性のある問題を検出することをお勧めします。
関数のインライン化を実行すると、命令キャッシュが破損するリスクがあります。また、メモリがフェッチバウンドされていない場合、(もしあれば)多くの違いを生じることはほとんどありません。
いつものように、最適化は、予測ではなくプロファイリングによって通知される必要があります。プロファイラーが何を伝えているかを理解する必要があることは言うまでもありません。これは、アセンブリ言語と最適化するプラットフォームの特定の特性に精通していることを意味します。
もう少し古いですが、Mike Abrashの<!> quot; Graphicのプログラミングブラックブック<!> quot;まだ一般的なアドバイスがたくさんあります。
また、C ++を実行し、マルチスレッドを使用する場合は、各プロセッサのキャッシュ上のデータの偽共有、ローカリティ、ホットネスを考慮する必要があります。それは大きな違いを生むことができます。また、特にマルチスレッドLIFO方式での計算は、FIFO方式での計算よりも効率的ですが、シングルプロセッサアーキテクチャでも有効です。
必要でないときは動的メモリを使用しないでください。新規、削除、スマートポインターなどを使用すると、プログラムデータがメモリ全体に広がる傾向があります。それは良いことではありません。スタック上のオブジェクトを宣言するなどして、ほとんどのデータをまとめて保持できる場合、キャッシュは確実に機能します。