5

ご存じのとおり、X86 CPU には 64 ビットのデータ バスがあります。私の理解では、CPU は任意のアドレスにアクセスできません。CPU がアクセスできるアドレスは、そのデータ バス幅の整数倍です。パフォーマンスのために、余分なメモリアクセスを避けるために、変数はこれらのアドレスで (アラインされて) 開始する必要があります。4 バイト境界に整列された 32 ビット変数は、x86 64 ビット データ バスに対応する 8 バイト (64 ビット) 境界に自動的に整列されます。しかし、なぜコンパイラは 128 ビットの変数を 16 バイトの境界に揃えるのでしょうか? 8Byte境界ではありませんか?

ありがとう

もっと具体的に言ってみましょう。コンパイラは、変数の長さを使用して整列します。たとえば、変数の長さが 256 ビットの場合、Complier はそれを 32 バイトの境界に揃えます。こんなに長いデータバスを持つCPUは他にないと思います。さらに、一般的な DDR メモリは、キャッシュがあるにもかかわらず、64 ビット データを 1 回しか転送しないのに、どうしてメモリが CPU のより広いデータ バスを占有するのでしょうか? それともキャッシュのみですか?

4

2 に答える 2

4

非常に多くの異なるプロセッサ モデルがあるため、理論的および一般的な用語でのみこれに答えるつもりです。

16 バイトではなく 8 バイトの倍数であるアドレスで始まる 16 バイト オブジェクトの配列を考えてみます。質問に示されているように、一部のプロセッサがそうでない場合でも、プロセッサに8バイトのバスがあるとします。ただし、配列内のある時点で、オブジェクトの 1 つがページ境界をまたぐ必要があることに注意してください。メモリ マッピングは通常、4096 バイト境界で始まる 4096 バイト ページで機能します。8 バイトでアラインされた配列では、配列の一部の要素が 1 ページのバイト 4088 から始まり、次のページのバイト 7 まで続きます。

プログラムがページ境界を越える 16 バイトのオブジェクトを読み込もうとすると、単一の仮想から物理へのメモリ マップを実行できなくなります。最初の 8 バイトに対して 1 回のルックアップを実行し、次の 8 バイトに対して別のルックアップを実行する必要があります。ロード/ストア ユニットがこのように設計されていない場合、命令には特別な処理が必要です。プロセッサは、命令を実行する最初の試行を中止し、それを 2 つの特別なマイクロ命令に分割し、それらを実行のために命令キューに送り返す場合があります。これにより、多くのプロセッサ サイクルだけ命令が遅延する可能性があります。

さらに、Hans Passant が指摘したように、アラインメントはキャッシュと相互作用します。各プロセッサにはメモリ キャッシュがあり、キャッシュが 32 バイトまたは 64 バイトの「ライン」に編成されるのが一般的です。16 バイトにアラインされた 16 バイトのオブジェクトをロードし、そのオブジェクトがキャッシュにある場合、キャッシュは必要なデータを含む 1 つのキャッシュ ラインを提供できます。16 バイト アラインされていない配列から 16 バイト オブジェクトをロードする場合、配列内の一部のオブジェクトは 2 つのキャッシュ ラインにまたがります。これらのオブジェクトがロードされると、キャッシュから 2 行をフェッチする必要があります。これにはさらに時間がかかる場合があります。プロセッサがサイクルごとに 2 つのキャッシュ ラインを提供するように設計されているため、2 つのラインを取得するのに時間がかからなくても、プログラムが実行している他の処理に干渉する可能性があります。通常、プログラムは複数の場所からデータをロードします。負荷が効率的であれば、プロセッサは、一度に 2 つの処理を実行できる場合があります。ただし、そのうちの 1 つが通常のキャッシュ ラインではなく 2 つのキャッシュ ラインを必要とする場合、他のロード操作の同時実行がブロックされます。

さらに、アラインされたアドレスを明示的に要求する命令もあります。プロセッサは、これらの命令をより直接的にディスパッチし、整列されたアドレスなしで操作を修正するいくつかのテストをバイパスする場合があります。これらの命令のアドレスが解決され、ミスアライメントが見つかった場合、修正操作がバイパスされているため、プロセッサはそれらを中止する必要があります。

于 2013-05-23T01:08:44.897 に答える