37

何年も前、私は x86 アセンブラ、CPU パイプライン処理、キャッシュ ミス、分岐予測などについて学んでいました。

それは2つの半分の物語でした。プロセッサの長いパイプライン、つまり命令の並べ替え、キャッシュのプリロード、依存関係のインターリーブなどの素晴らしい利点について読みました。

マイナス面は、標準からの逸脱が非常に高くつくことでした。たとえば、初期ギガヘルツ時代の特定の AMD プロセッサである IIRC では、ポインタ (!) を介して関数を呼び出すたびに40 サイクルのペナルティがありましたが、これは明らかに正常でした。

これは無視できる「心配しないで」という数値ではありません。通常、「優れた設計」とは、「関数を可能な限り分解する」ことと、仮想インターフェイスを意味することが多い「データ型にセマンティクスをエンコードする」ことを意味することに注意してください。

トレードオフは、そのような操作を実行しないコードがサイクルごとに 2 つ以上の命令を取得する可能性があることです。これらは、オブジェクト設計が重く、計算処理が少ない高性能 C++ コードを作成する場合に考慮したい数値です。

低電力時代に入り、長い CPU パイプラインの傾向が逆転していることを理解しています。これが私の質問です:

最新世代の x86 互換プロセッサは、依然として仮想関数呼び出し、不適切な分岐予測などの大きなペナルティを被っていますか?

4

1 に答える 1

34

初期のギガヘルツ時代の AMD プロセッサには、関数を呼び出すたびに 40 サイクルのペナルティがありました

はぁ…めっちゃ大きい…

少し前に同じ間接ジャンプがあった場合に、仮想関数ジャンプを予測するのに役立つ「間接分岐予測」メソッドがあります。最初の予測ミスの virt にはまだペナルティがあります。関数ジャンプ。

サポートは、単純な「前の間接分岐がまったく同じ場合にのみ正しいと予測される」ものから、単一の間接 jmp 命令の 2 ~ 3 ターゲット アドレスの定期的な変更を検出する非常に複雑な 2 レベルの数十または数百のエントリまでさまざまです。

ここは進化が凄かった…

http://arstechnica.com/hardware/news/2006/04/core.ars/7

Pentium M: ... 間接分岐予測器で最初に導入されました。

間接分岐予測子

間接分岐はレジスターから分岐先をロードするため、直接分岐の場合のように分岐先をすぐに利用できるようにするのではなく、予測が難しいことで知られています。Core の間接分岐予測子は、フロントエンドが遭遇する各間接分岐の優先ターゲット アドレスに関する履歴情報を格納するテーブルです。したがって、フロントエンドが間接分岐に遭遇し、それが実行されると予測すると、間接分岐予測子に、分岐がおそらく必要とする BTB 内のアドレスに誘導するように依頼できます。

http://www.realworldtech.com/page.cfm?ArticleID=rwt051607033728&p=3

間接分岐予測は、Intel の Prescott マイクロアーキテクチャで最初に導入され、その後 Pentium M.

すべての分岐予測ミスの 16 ~ 50% が間接的なものでした (平均 29%)。間接的な分岐予測ミスの真価は、Ruby、Perl、Python など、インタープリターを使用する新しいスクリプト言語や高水準言語の多くに当てはまります。その他の一般的な間接分岐の一般的な原因には、仮想関数 (C++ で使用される) と関数ポインターの呼び出しが含まれます。

http://www.realworldtech.com/page.cfm?ArticleID=RWT102808015436&p=5

AMD はこれらの改良の一部を採用しています。たとえば、バルセロナ以降のプロセッサに間接分岐予測配列を追加します。ただし、K8 には、Core 2 よりも古く、精度の低い分岐予測子があります。

http://www.agner.org/optimize/microarchitecture.pdf

3.12 古いプロセッサでの 間接ジャンプ 間接ジャンプ、間接呼び出し、およびリターンは、毎回異なるアドレスに移動する場合があります。間接ジャンプまたは間接呼び出しの予測方法は、PM および K10 よりも古いプロセッサでは、前回実行されたときと同じターゲットに移動することを予測するだけです。

および同じpdf、14ページ

間接ジャンプ予測 間接ジャンプまたは呼び出しは、2 つ以上の可能なターゲットを持つ制御転送命令です。C++ プログラムは、仮想関数を使用して間接ジャンプまたは呼び出しを生成できます。間接ジャンプまたは間接呼び出しは、ジャンプまたは呼び出し命令の宛先としてレジスタまたはメモリ変数またはインデックス付き配列を指定することにより、アセンブルで生成されます。多くのプロセッサは、間接的なジャンプまたは呼び出しに対して BTB エントリを 1 つだけ作成します。これは、前回と同じターゲットに向かうことが常に予測されることを意味します。多様なクラスを使用したオブジェクト指向プログラミングがより一般的になるにつれて、複数のターゲットでの間接呼び出しを予測する必要性が高まっています。これは、遭遇するすべての新しいジャンプ ターゲットに新しい BTB エントリを割り当てることで実行できます。ヒストリ バッファとパターン ヒストリ テーブルには、2 つ以上の可能なターゲットを区別するために、ジャンプ インシデントごとに 1 ビット以上の情報用のスペースが必要です。PM は、この方法を実装した最初の x86 プロセッサです。pの予測ルール。12 は、完全に予測できる理論上の最大期間が mn であるという修正を加えても適用されます。ここで、m は間接ジャンプあたりの異なるターゲットの数です。ただし、この理論上の最大値は、BTB またはパターン履歴テーブルのサイズを超えると到達できません。12 は、完全に予測できる理論上の最大期間が mn であるという修正を加えても適用されます。ここで、m は間接ジャンプあたりの異なるターゲットの数です。ただし、この理論上の最大値は、BTB またはパターン履歴テーブルのサイズを超えると到達できません。12 は、完全に予測できる理論上の最大期間が mn であるという修正を加えても適用されます。ここで、m は間接ジャンプあたりの異なるターゲットの数です。ただし、この理論上の最大値は、BTB またはパターン履歴テーブルのサイズを超えると到達できません。

Agner のマニュアルには、多くの最新の CPU における分岐予測子の詳細な説明と、すべての製造元 (x86/x86_64) の CPU における予測子の進化が記載されています。

また、多くの理論的な「間接分岐予測」メソッド (Google 学者を参照)。ウィキでさえ、それについていくつかの言葉を述べましたhttp://en.wikipedia.org/wiki/Branch_predictor#Prediction_of_indirect_jumps /

アグナーのミクロからの原子の場合:

間接分岐の予測 私のテストによると、Atom には間接分岐のパターン予測子がありません。間接分岐は前回と同じターゲットに行くと予想されます。

したがって、低電力の場合、間接分岐予測はそれほど高度ではありません。Via Nano も同様です。

間接ジャンプは前回と同じターゲットに向かうと予想。

低電力 x86 の短いパイプラインは、ペナルティが低く、7 ~ 20 ティックだと思います。

于 2011-08-31T21:50:06.483 に答える