アンアライン アクセスは実行時エラーの原因となり、プログラムがクラッシュしたり、メモリ アクセスが遅くなったりするため、良くないとよく耳にします。ただし、どれだけ遅くなるかについての実際のデータは見つかりません。
x86 を使用していて、アラインされていないアクセスの (まだ不明な) シェアがあるとします。実際に可能な最悪のスローダウンは何であり、すべてのアラインされていないアクセスを排除して 2 つのバージョンのコードの実行時間を比較せずに、どのように見積もればよいでしょうか?
アンアライン アクセスは実行時エラーの原因となり、プログラムがクラッシュしたり、メモリ アクセスが遅くなったりするため、良くないとよく耳にします。ただし、どれだけ遅くなるかについての実際のデータは見つかりません。
x86 を使用していて、アラインされていないアクセスの (まだ不明な) シェアがあるとします。実際に可能な最悪のスローダウンは何であり、すべてのアラインされていないアクセスを排除して 2 つのバージョンのコードの実行時間を比較せずに、どのように見積もればよいでしょうか?
これは命令によって異なります。ほとんどの x86 SSE ロード/ストア命令 (アラインされていないバリアントを除く) では、エラーが発生します。つまり、プログラムがクラッシュするか、例外ハンドラーへのラウンド トリップが何度も発生する可能性があります (つまり、ほとんどまたはすべてのパフォーマンスが失われます)。アライメントされていないロード/ストア バリアントは、部分的な読み取り/書き込みを実行するため、IIRC の 2 倍のサイクル量で実行されるため、操作を実行するには 2 つが必要です (幸運でキャッシュ内にある場合を除き、ペナルティが大幅に軽減されます)。
一般的な x86 ロード/ストア命令の場合、読み書きに必要なサイクル数が増えるため、速度が低下します。アンアライメントはキャッシングにも影響し、キャッシュ ラインの分割やキャッシュ境界のまたがりにつながる可能性があります。また、読み取りと書き込みのアトミック性を防ぎます (x86 のすべてのアライメントされた読み取り/書き込みに対して保証されていますが、バリアと伝播は別のものですが、アライメントされていないデータで LOCK された命令を使用すると、例外が発生したり、既に大きなペナルティが大幅に増加したりする可能性があります。ロックが発生します)、これは並行プログラミングには禁物です。
Intel の x86 & x64 最適化マニュアルでは、前述の問題、その副作用、およびそれらを修正する方法について詳しく説明しています。
Agner Fog の最適化マニュアルには、生のサイクル スループットに関して探している正確な数値が記載されているはずです。
一部の Intel マイクロアーキテクチャでは、キャッシュライン境界によって分割されたロードに通常よりも 12 サイクル長くかかり、ページ境界によって分割されたロードには 200 サイクル以上長くかかります。ロードがループ内で一貫してずれている場合は、たとえそれpalignr
がオプションでなくても、2 つのアライメントされたロードを実行し、結果を手動でマージする価値があります。SSE の位置合わせされていない負荷でさえ、ちょうど真ん中で分割されていない限り、あなたを救うことはできません。
AMD ではこれは決して問題ではなく、Nehalem ではこの問題はほとんどなくなりましたが、Core2 もまだたくさんあります。
一般に、最近のプロセッサの速度を見積もるのは非常に複雑です。これは、アラインされていないアクセスだけでなく、一般的にも当てはまります。
最新のプロセッサは、パイプライン化されたアーキテクチャを備えており、順序が狂っており、場合によっては命令の並列実行や、実行に影響を与える可能性のある他の多くのものがあります。
非境界整列アクセスがサポートされていない場合、例外が発生します。ただし、サポートされている場合、多くの要因によって速度が低下する場合とされない場合があります。これらの要因には、アライメントされていない命令の前後に実行していた他の命令が含まれます (プロセッサは、前の命令の実行中にデータのフェッチを開始したり、待機中に先に進んで後続の命令を実行したりできるため)。
非整列アクセスがキャッシュラインの境界を越えて発生した場合、もう 1 つの非常に重要な違いが発生します。一般に、キャッシュへの 2 倍のアクセスはアライメントされていないアクセスで発生する可能性がありますが、実際の速度低下は、アクセスがキャッシュラインの境界を越えて二重のキャッシュ ミスが発生した場合です。最悪の場合、2 バイトのアライメントされていない読み取りでは、プロセッサが 2 つのキャッシュラインをメモリにフラッシュしてから、メモリから 2 つのキャッシュラインを読み取る必要があります。それは大量のデータの移動です。
ここでも最適化の一般的なルールが適用されます。最初にコードを作成し、次に測定し、問題がある場合にのみ解決策を見つけます。