レジスタ変数は、高速アクセスを取得するためのよく知られた方法です ( register int i
)。しかし、レジスターが階層 (レジスター、キャッシュ、メインメモリー、セカンダリーメモリー) の最上位にあるのはなぜですか? レジスタへのアクセスを非常に高速にするすべての要因は何ですか?
6 に答える
レジスタは、算術回路を含む ALU に文字通り直接配線された回路です。クロック サイクルごとに、CPU コアのレジスタ ユニットは、半ダースほどの変数を他の回路に供給することができます。実際には、データパス内のユニット (ALU など) は、バイパス ネットワークを介して互いにデータを直接供給することができます。バイパス ネットワークは、ある意味でレジスタの上に階層レベルを形成しますが、レジスタ番号を使用して互いにアドレス指定します。(完全にパイプライン化された CPU の制御セクションは、データパス ユニットをレジスタ番号に動的にマップします。)
Cのregister
キーワードは何の役にも立たないので、使用しないでください。コンパイラは、どの変数をいつレジスタに入れるかを決定します。
レジスタは CPU のコア部分であり、CPU の命令セットの多くは、メモリ位置ではなくレジスタに対して動作するように調整されます。レジスタの値へのアクセスには、通常、ごくわずかなクロック サイクル (おそらく 1 サイクル) しか必要としません。メモリにアクセスするとすぐに、事態はより複雑になり、キャッシュ コントローラ/メモリ バスが関与し、操作にかなりの時間がかかります。
いくつかの要因により、レジスターがキャッシュよりも高速になります。
直接アドレス指定と間接アドレス指定
まず、レジスタは命令のビットに基づいて直接アドレス指定されます。多くの ISA は、ソース レジスタ アドレスを一定の場所にエンコードし、命令がデコードされる前にアドレスをレジスタ ファイルに送信できるようにし、一方または両方の値が使用されることを推測します。最も一般的なメモリ アドレス指定モードは、レジスタを介して間接的に行われます。ベース + オフセット アドレッシングが頻繁に行われるため、多くの実装では、この場合にパイプラインを最適化しています。(さまざまな段階でキャッシュにアクセスすると、複雑さが増します。) キャッシュはタグ付けも使用し、通常はセットの結合性を使用します。これにより、アクセスの待ち時間が長くなる傾向があります。ミスの可能性を処理する必要がないため、レジスタ アクセスの複雑さも軽減されます。
複雑化する要因順不同の実装と、スタックまたはローテーション レジスタ (SPARC、Itanium、XTensa など) を使用する ISA は、レジスタの名前を変更します。Todd Austin の Knapsack Cache (オフセットを使用してキャッシュに直接インデックスを付ける) などの特殊なキャッシュや、いくつかのスタック キャッシュ設計 (たとえば、小さなスタック フレーム番号を使用し、そのフレーム番号とオフセットを使用して特殊なスタック キャッシュのチャンクに直接インデックスを付ける)レジスタの読み取りと加算は避けてください。シグニチャ キャッシュは、レジスタ名とオフセットをストレージの小さなチャンクに関連付け、構造体の下位メンバーへのアクセスのレイテンシを短縮します。インデックス予測 (例: オフセットとベースの XOR 演算、キャリー伝搬遅延の回避) により、レイテンシを削減できます (予測ミスの処理が犠牲になります)。レジスタ間接、ただし、2 つの異なるパイプライン ステージでキャッシュにアクセスすると、複雑さが増します。(Itanium はレジスタ間接アドレス指定のみを提供しました — オプションのポスト インクリメントを使用します。) ウェイ予測 (および直接マップされたキャッシュの場合はヒット スペキュレーション) により、レイテンシを削減できます (ここでも予測ミスの処理コストがかかります)。スクラッチパッド (別名密結合) メモリにはタグや連想性がないため、わずかに高速で (アクセス エネルギーも低く)、アクセスがその領域へのアクセスであると判断されると、ミスは不可能になります。ナップザック キャッシュの内容はコンテキストの一部として扱うことができ、コンテキストはそのキャッシュがいっぱいになるまで準備ができているとは見なされません。理論的には、レジスターは (特に Itanium スタック レジスターの場合) 遅延ロードされる可能性があるため、レジスター ミスの可能性を処理する必要があります。
固定サイズと可変サイズ
通常、レジスタは固定サイズです。これにより、アラインされたストレージから取得したデータをシフトして、実際の最下位ビットを実行ユニットの適切な場所に配置する必要がなくなります。さらに、多くのロード命令は、ロードされた値を符号拡張するため、レイテンシが追加される可能性があります。(ゼロ拡張はデータ値に依存しません。)
複雑化する要因一部の ISA はサブレジスタ、注目すべき x86 および zArchitecture (S/360 から派生) をサポートしており、事前シフトが必要になる場合があります。より低いレイテンシーで完全にアライメントされたロードを提供することもできます (おそらく、他のロードのために 1 サイクルの余分なレイテンシーが犠牲になります)。サブワードのロードは十分に一般的であり、追加のレイテンシは十分に小さいため、特殊なケースは一般的ではありません。符号拡張レイテンシは、キャリー伝搬レイテンシの背後に隠れている可能性があります。あるいは、符号予測を使用するか (投機的なゼロ拡張のみ)、符号拡張を遅いケースとして扱うこともできます。(アライメントされていないロードのサポートにより、キャッシュ アクセスがさらに複雑になる可能性があります。)
小容量
インオーダー 64 ビット RISC の典型的なレジスタ ファイルは、約 256 バイト (32 個の 8 バイト レジスタ) しかありません。8KiB は最新のキャッシュでは小さいと見なされます。これは、速度を上げるために物理的なサイズと静的電力を乗算しても、総面積と静的電力に与える影響ははるかに小さいことを意味します。トランジスタが大きいほどドライブ強度が高くなり、その他の面積を増やす設計要因によって速度が向上する可能性があります。
複雑化する要因一部の ISA には多数のアーキテクチャ化されたレジスタがあり、非常に幅の広い SIMD レジスタがある場合があります。さらに、一部の実装では、名前の変更やマルチスレッドのサポートのためにレジスタを追加します。SIMD を使用し、マルチスレッドをサポートする GPU は、特に大容量のレジスタ ファイルを持つことができます。GPU レジスタ ファイルは、CPU レジスタ ファイルとは異なり、通常はシングル ポートであり、実行で使用できるサイクルごとに 1 つのオペランド/結果の 4 倍のベクトル要素にアクセスします (たとえば、512 ビット幅の積和実行では、読み取り3 つのオペランドのそれぞれに 2KiB、結果に 2KiB を書き込みます)。
一般的なケースの最適化
レジスタ アクセスは一般的なケースであることを意図しているため、この機能のパフォーマンスを向上させるために、面積、消費電力、および設計の労力がより有益に費やされます。命令の 5% がソース レジスタを使用しない場合 (ダイレクト ジャンプと呼び出し、レジスタ クリアなど)、70% が 1 つのソース レジスタを使用 (単純なロード、即値を伴う操作など)、25% が 2 つのソース レジスタを使用し、75% が 2 つのソース レジスタを使用します。 % がデスティネーション レジスタを使用し、50% がデータ メモリにアクセスします (40% がロード、10% がストア) — MIPS 用の SPEC CPU2000 からのデータに基づく大まかな概算 — 次に、3 倍以上の数 (よりタイミングが重要な要素) ) 読み取りはメモリよりもレジスタからである (命令あたり 1.3 対 0.4) および
複雑化する要因すべてのプロセッサが「汎用」ワークロード向けに設計されているわけではありません。たとえば、メモリ内ベクトルを使用し、ベクトル開始アドレス、ベクトル長、およびアキュムレータにレジスタを使用してドット積のパフォーマンスを目標とするプロセッサには、レジスタ レイテンシを最適化する理由がほとんどない可能性があり (極端な並列処理により、レイテンシの隠蔽が簡素化されます)、メモリ帯域幅はレジスタよりも重要になります。帯域幅。
小さなアドレス空間
最後に、レジスターのややマイナーな利点は、アドレス空間が小さいことです。これにより、ストレージ アレイにインデックスを付ける際のアドレス デコードのレイテンシが短縮されます。アドレスのデコードは、一連のバイナリ決定 (ストレージのチャンクのこの半分または他の半分) として考えることができます。典型的なキャッシュ SRAM アレイには、約 256 のワードライン (列、インデックス アドレス) (デコードするのに 8 ビット) があり、通常、SRAM アレイの選択にはアドレス デコードも含まれます。単純な順序付き RISC には、通常、32 個のレジスタ (デコードするのに 5 ビット) があります。
複雑化する要因最新の高性能プロセッサは、簡単に 8 ビットのレジスタ アドレスを持つことができます (Itanium にはコンテキスト内に 128 を超える汎用レジスタがあり、ハイエンドのアウトオブオーダー プロセッサはさらに多くのレジスタを持つことができます)。これも上記の考慮事項に比べてそれほど重要ではありませんが、無視すべきではありません。
結論
上記の考慮事項の多くは重複しており、これは最適化された設計で予想されることです。特定の機能が共通であると予想される場合は、実装が最適化されるだけでなく、インターフェースも最適化されます。柔軟性 (直接アドレッシング、固定サイズ) を制限すると、当然最適化が促進され、小さいほど高速化が容易になります。
レジスタは本質的に内部 CPU メモリです。したがって、レジスタへのアクセスは、他の種類のメモリ アクセスよりも簡単かつ迅速です。
一般に、小さいメモリは大きいメモリよりも高速です。また、アドレス指定に必要なビットが少なくて済みます。32 ビットの命令語は、3 つの 4 ビット レジスタ アドレスを保持でき、オペコードやその他のもののための多くの余地があります。1 つの 32 ビット メモリ アドレスが命令ワードを完全に埋めてしまい、他に何も入れる余地がありません。さらに、メモリのアドレス指定に必要な時間は、メモリ サイズの対数に比例する以上の割合で増加します。4 ギガのメモリ空間から 1 ワードにアクセスすると、16 ワードのレジスタ ファイルから 1 ワードにアクセスするよりも、数百倍とは言わないまでも数十倍の時間がかかります。
小さな高速レジスタ ファイルからのほとんどの情報要求を処理できるマシンは、低速のメモリをすべてに使用するマシンよりも高速です。
Bill が述べたように、すべてのマイクロコントローラーには CPU があり、ALU の基本コンポーネント、一部の RAM、およびその操作を支援する他の形式のメモリを備えています。RAM は、メイン メモリと呼ばれるものです。
ALU はすべての算術論理演算を処理し、これらの計算を実行するために任意のオペランドを操作するために、オペランドをレジスタにロードし、これらの演算を実行してから、プログラムがこれらのレジスタに格納された結果に直接または間接的にアクセスします。
レジスターは CPU の心臓部 (つまり、プロセッサーの頭脳) に最も近いため、チェーンの上位にあり、もちろん、レジスターで直接実行される操作は最小のクロック サイクルで済みます。