プリフェッチ命令がその操作を完了するまでコードが処理でビジー状態であれば、プリフェッチを追加できるというのがプリフェッチ使用の一般的なロジックのようです。しかし、プリフェッチ命令が多すぎると、システムのパフォーマンスに影響を与えるようです。まず、プリフェッチ命令なしで動作するコードを用意する必要があることがわかりました。後で、コードのさまざまな場所でプリフェッチ命令をさまざまに組み合わせて分析し、プリフェッチによって実際に改善できるコードの場所を特定する必要があります。プリフェッチ命令を使用する正確な場所を特定するより良い方法はありますか?
3 に答える
ほとんどの場合、プリフェッチ命令はほとんどまたはまったくメリットがなく、場合によっては逆効果になることさえあります。最近のほとんどの CPU には自動プリフェッチ メカニズムが備わっており、ソフトウェア プリフェッチ ヒントを追加してもほとんど効果がないか、自動プリフェッチに干渉し、実際にはパフォーマンスが低下する可能性があります。
実際の処理がほとんど行われていない大きなデータ ブロックをストリーミングしている場合など、まれなケースでは、ソフトウェアが開始するプリフェッチでレイテンシを隠すことができますが、それを正しく行うのは非常に困難です。データを使用する前に数百サイクルのプリフェッチを開始します。遅すぎるとキャッシュミスが発生し、早すぎるとデータを使用する準備が整う前にキャッシュから追い出される可能性があります。多くの場合、これはコードの無関係な部分にプリフェッチを配置し、モジュール性とソフトウェアのメンテナンスに悪影響を及ぼします。さらに悪いことに、アーキテクチャが変更された場合 (新しい CPU、異なるクロック速度など)、DRAM アクセスのレイテンシが増減した場合、プリフェッチ命令をコードの別の部分に移動して、効果を維持する必要がある場合があります。
とにかく、本当にプリフェッチを使用する必要があると思われる場合は、プリフェッチの有無にかかわらずコードをコンパイルし、実際にパフォーマンスを向上させている (または妨げている) かどうかを確認できるように、プリフェッチ命令の周りに #ifdefs をお勧めします。
#ifdef USE_PREFETCH
// prefetch instruction(s)
#endif
ただし、一般的には、より生産的で明白なことをすべて行った後は、ソフトウェアのプリフェッチを最後の手段としてマイクロ最適化として後回しにすることをお勧めします。
コードのプリフェッチのパフォーマンスを考慮することさえ、すでに問題になっているに違いありません。
1: コード プロファイラを使用します。プロファイラーなしでプリフェッチを使おうとするのは時間の無駄です。
2: クリティカルな場所で異常に遅い命令を見つけると、プリフェッチの候補になります。多くの場合、実際の問題は、プロファイラーによって示される遅いものではなく、遅いものよりも前の行のメモリ アクセスにあります。問題の原因となっているメモリ アクセスを特定し (必ずしも簡単ではありません)、プリフェッチします。
3 プロファイラーを再度実行して、違いが生じるかどうかを確認します。取り出さなければ。時々、この方法でループを 300% 高速化しました。一般に、メモリに非連続的にアクセスするループがある場合に最も効果的です。
最新の CPU ではあまり役に立たないという点については完全に同意しません。完全に反対であることがわかりましたが、古い CPU では約 100 命令のプリフェッチが最適でしたが、最近ではその数を 500 程度にしています。
確かに、少し実験する必要がありますが、データが必要になる前に数百サイクル (100 ~ 300) を取得する必要があるわけではありません。L2 キャッシュは、プリフェッチされたデータがしばらくそこに留まるのに十分な大きさです。
このプリフェッチは、aa ループ (もちろん数百サイクル) の前では非常に効率的です。特に、それが内側のループであり、ループが 1 秒間に 1000 回以上開始される場合はなおさらです。
また、非常に高速な LL 実装またはツリー実装では、データがすぐに必要になることを CPU が認識していないため、プリフェッチによって測定可能な利点が得られる可能性があります。
ただし、プリフェッチ命令はデコーダー/キューの帯域幅を消費するため、それらを使いすぎるとパフォーマンスが低下することに注意してください。