4

JIT コンパイラでいくつかのオペコードを動的に生成しており、オペコードの配置に関するガイドラインを探しています。

1) 呼び出しの後に nops を追加することで、アライメントを簡単に「推奨」するコメントを読みました

2)並列処理のためにシーケンスを最適化するために nop を使用することについても読みました。

3) ops のアラインメントが「キャッシュ」のパフォーマンスに適していることを読みました

通常、これらのコメントは裏付けとなる参照を提供しません。ブログやコメントを読んで、「これを行うのは良い考えだ」と言うのと、特定の op シーケンスを実装するコンパイラを実際に書いて、オンラインのほとんどの資料、特にブログが役に立たないことに気付くのとは別のことです。実用化のために。だから私は自分で物事を見つけることを信じています(実際のアプリが何をするかを見るために逆アセンブルなど)。これは、外部情報が必要な 1 つのケースです。

コンパイラは通常、前の命令シーケンスの直後に奇数バイトの命令を開始することに気付きました。そのため、ほとんどの場合、コンパイラは特別な注意を払っていません。あちこちで「nop」を見かけますが、通常、nop は控えめに使用されているようです。オペコードのアライメントはどの程度重要ですか? 実際に実装に使える事例を参考にしていただけないでしょうか?ありがとう。

4

2 に答える 2

5

ブランチ ターゲットの配置を除いて、nop を挿入しないことをお勧めします。一部の特定の CPU では、分岐予測アルゴリズムが制御転送にペナルティを課す可能性があるため、nop はフラグとして機能し、予測を反転できる場合がありますが、それ以外の場合は役に立たない可能性があります。

いずれにせよ、最新の CPU は ISA ops をmicro-opsに変換しようとしています。これにより、従来のアライメント手法の重要性が低下する可能性があります。おそらく、マイクロオペレーション トランスコーダーは nops を省略し、秘密の真のマシン オペレーションのサイズとアライメントの両方を変更するからです。

ただし、同じように、第一原理に基づく最適化はほとんどまたはまったく害を及ぼすべきではありません。

理論的には、キャッシュ ラインの境界でループを開始することにより、キャッシュをより有効に利用できるというものです。ループがキャッシュ ラインの途中で開始された場合、キャッシュ ラインの前半が不可避的にロードされ、ループ中にロードされたままになります。これは、ループが 1/キャッシュ ラインの 2。

また、分岐ターゲットの場合、キャッシュ ラインの初期ロードは、ターゲットがアラインされたときに、命令ストリームの最大のフォワード ウィンドウをロードします。

分岐ターゲットではないインライン命令を nop で分離することに関して、最新の CPU でこれを行う理由はほとんどありません。(RISC マシンに遅延スロットがあり、制御転送の後に nop が挿入されることがよくありました。) 命令ストリームのデコードはパイプライン処理が容易であり、アーキテクチャに奇数バイト長の op がある場合、それらが適切にデコードされることを保証できます。 .

于 2010-03-21T03:48:30.213 に答える
4

これらすべてのマイクロ最適化の最良の情報源は、Agner Fog の x86 最適化マニュアルです。これらのドキュメントには、必要なものがすべて含まれている必要があります。:)

考えられることの 1 つは、ループ コードがキャッシュ ラインの境界を超えないようにループを調整することです。つまり、ループは < 64 バイトで、64 で割り切れるアドレスから開始します。これにより、ループ全体が 1 つのキャッシュに収まります。行し、他のことに使用できるキャッシュ行を残します。ただし、その特定のループがたまたま「ホット」であっても、実際のプログラムではそれが問題になるとは思いません。

于 2010-03-21T03:13:15.007 に答える