プロセッサーは命令セットアーキテクチャ(ISA)を実装します。ISA は、命令、レジスター、 データ型、アドレス形成、例外、特権動作を定義する規約です。マイクロアーキテクチャは、 パイプライン、実行ユニット、キャッシュ、予測器、内部キューによって、その規約を実装します。 プログラムから観測できるのはアーキテクチャ状態ですが、性能はマイクロアーキテクチャ状態に 依存します。
フェッチからリタイアまで #
概念上、プロセッサーは命令バイト列をフェッチし、命令をデコードし、オペランドを取得して 処理を実行し、必要に応じてメモリへアクセスした後、結果をコミットします。単純なプロセッサー では、これらの段階を順番に実行できます。パイプライン方式のプロセッサーは複数の命令の 各段階を重ねて実行するため、すべての命令のレイテンシーを短縮しなくてもスループットを 向上させられます。
アーキテクチャ状態には、汎用レジスター、ステータスレジスター、プログラムカウンター、 アーキテクチャ上可視なメモリが含まれます。マイクロアーキテクチャ状態には、デコード済み オペレーションのキャッシュ、物理レジスター、リオーダーバッファー、分岐履歴、 キャッシュ置換メタデータが含まれます。コンテキストスイッチでは ABI が保証する アーキテクチャ状態を保存する必要がありますが、内部の予測器やパイプラインの全エントリーを 保存または公開するわけではありません。
パイプラインでは、次の 3 種類の依存関係を処理する必要があります。
- データハザードは、ある処理が、別の処理でまだ生成されていない結果を使用するときに 発生します。
- 構造ハザードは、複数の処理が実行ユニット、ポート、キュー、キャッシュリソースを 競合して使用するときに発生します。
- 制御ハザードは、分岐によって次のフェッチアドレスが変わる可能性があるため発生します。
フォワーディングは、レジスターへの書き戻し前に結果を供給します。レジスターリネーミングは、 アーキテクチャ上の名前をより大きな物理レジスターセットへ対応付けるため、write-after-read および write-after-write の偽の依存関係を取り除きます。リオーダーバッファーにより、 独立した処理をアウトオブオーダーで実行しながら、正確なアーキテクチャ例外を維持する順序で 完了した処理をリタイアできます。
スーパースカラー実行と投機的実行 #
スーパースカラー方式のフロントエンドは、1 サイクルに複数の処理をデコードまたは発行 できます。ディスパッチ幅だけが制約ではありません。真の依存関係、実行ポートへの負荷、 キャッシュミス、リタイア幅によって、持続可能なスループットが低下する場合があります。
分岐予測は、分岐結果が確定する前に可能性の高い制御フローパスを選択します。予測が正しければ パイプラインへの供給が維持されます。予測が外れると、後続の投機的な処理を破棄し、確定した ターゲットからフェッチを再開します。投機によって誤ったアーキテクチャ状態をコミットしては なりませんが、一時的実行はキャッシュやほかの共有マイクロアーキテクチャリソースに影響を 与える可能性があります。したがって、分離を担うコードは、アーキテクチャ上の特権チェック だけに依存せず、一時的実行の脆弱性に関するプラットフォームの指針に従う必要があります。
キャッシュ階層とメモリレイテンシー #
高速な記憶装置は高コストで物理的制約もあるため、プロセッサーコアは階層を介して DRAM に アクセスします。L1 命令キャッシュと L1 データキャッシュは小さく、コアの近くにあります。 より大きな L2 キャッシュと最終レベルキャッシュは、レイテンシーと容量をトレードオフします。 キャッシュラインは隣接するバイトをまとめて転送するため、シーケンシャルアクセスは空間的 局所性を、再利用は時間的局所性を活用します。
キャッシュはアドレスをタグ、セットインデックス、ラインオフセットに分割します。 セットアソシアティビティにより 1 つのセットへ複数のラインを格納できるため、タグ比較と 置換処理の複雑性を代償として競合ミスを減らせます。ハードウェアプリフェッチャーは予測可能な レイテンシーを隠蔽できますが、ポインターチェイシングや容量ミスでは、下位キャッシュまたは DRAM の遅延が依然として顕在化します。
マルチコアシステムでは、コヒーレンスプロトコルによって同じラインのキャッシュ済みコピーを 調整します。コヒーレンスは 1 つの位置に対する書き込み順序を確立し、メモリ一貫性モデルは 異なるアクセス間で許容される順序を定義します。キャッシュコヒーレンスによって、同期されて いない複合操作がアトミックになるわけではないため、正しい並行ソフトウェアでは、言語が 提供するアトミック操作、ロック、またはほかの同期機構を使用する必要があります。
仮想メモリ用ハードウェアは、ページテーブルを介して仮想アドレスを変換します。 トランスレーションルックアサイドバッファーは最近の変換をキャッシュします。したがって、 データ自体がキャッシュされていても、TLB ミスによってページテーブルウォークが追加されます。 NUMA システムでは、さらに距離の違いが加わります。コアは、別のソケットに接続された メモリよりも、ローカルメモリへ低レイテンシーまたは高帯域幅でアクセスできます。
コア、スレッド、SIMD #
コアには、1 つ以上のアーキテクチャ上の実行コンテキストが含まれます。同時 マルチスレッディング(SMT)では、ハードウェアスレッドがコアのフロントエンド、 キャッシュ、実行リソースを共有します。SMT は空いている発行スロットを利用できますが、 競合によってスレッドごとの性能が低下する場合もあります。オペレーティングシステムの スレッドはスケジューリング対象であり、その数はコア数とハードウェアスレッド数の どちらよりも多くなる可能性があります。
複数のコアは独立した命令ストリームを実行します。共有メモリプログラムでは、引き続き同期、 キャッシュラインの競合、フォルスシェアリングを考慮する必要があります。コアを追加しても、 直列の依存関係チェーンは高速化されません。
SIMD 命令は、ベクトルレジスター内の複数のレーンへ 1 つの処理を適用します。x86 は SSE、AVX、AVX-512 の各ファミリーを提供し、Arm と RISC-V はそれぞれ独自のベクトル機能を 提供します。公称ベクトル幅が表すのはアーキテクチャ状態であり、レイテンシーやスループット ではありません。コンパイラーが安全にベクトル化するには、エイリアシング、アラインメント、 依存関係、ターゲット機能に関する情報が必要です。
アセンブリ構文と ABI 境界 #
アセンブリ構文はツールの規約であり、ISA の特性ではありません。x86 の Intel 構文では デスティネーションを先に記述します。
mov rax, rbxAT&T 構文ではソースを先に記述し、レジスターに % を付け、多くのニーモニックに
オペランドサイズを表す接尾辞を付けます。
movq %rbx, %raxNASM は Intel 構文を使用します。一方、GNU の objdump -d はデフォルトで AT&T 構文を
使用し、-Mintel も受け付けます。ほかのアーキテクチャには、それぞれ独自の構文と
ツール固有のディレクティブがあります。構文は呼び出し規約も定義しません。引数レジスター、
呼び出し先保存状態、スタックアラインメント、オブジェクト形式は ABI に属します。
アセンブラーのワークフローについては、NASMを参照してください。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)