ムーアの法則 (Moore's law) とは、集積回路当たりに実装できる素子数が18ヶ月で2倍になるという予測であり、後に法則となった。
命令アーキテクチャの設計アプローチにはCISC (Complex Instruction Set Computer) とRISC (Reduced Instruction Set Computer) の2つに分けられる。
CISCは複雑な命令を極力一命令で実現させる設計アプローチである。 反対に、RISCは単純な命令のみを命令セットに含める設計アプローチである。
アプローチ | ハードウェアの構造 | 命令数 | 一命令当たりの実行時間 |
---|---|---|---|
CISC | 複雑 | 多い | 遅い |
RISC | 単純 | 少ない | 早い |
RISCを採用したプロセッサではプログラムが単純な命令のみで構成されるため、命令数は多くなる。 しかし、命令が固定長でありハードウェア構造が比較的単純であることから、最適化がしやすい。 (後述のマイクロアーキテクチャ参照)
スーパースカラ (superscalar) は、クロックサイクル毎に複数の命令を読みそれらを複数のユニットを使って処理することで1サイクル当たりの並列実行命令数を増やす、プロセッサの最適化手法の一つである。
プロセッサの命令は以下のステージに細分化することができる。 (ただし、プロセッサはRISCを採用しているとする)
内部処理 | 略称 | 内容 | 利用する機能ユニット |
---|---|---|---|
命令フェッチ | IF (Instruction Fetch) | メモリあるいは命令キャッシュから命令を読む | フェッチユニット |
命令デコード | ID (Instruction Decode) | 命令を解釈する | デコードユニット |
オペランド | RR (Register Read) | 命令の実行に必要なオペランド (operand, 演算の対象) をレジスタから読む | レジスタファイル |
メモリアクセス | MA (Memory Access) | メモリを読み書きする | ロード/ストアユニット |
実行 | EX (EXecute) | 指定された演算を行う | 演算ユニット |
レジスタへのライトバック | WB (Write Back) | 演算結果をレジスタに書く | レジスタファイル |
処理中の命令の終了を待って次の命令の処理を開始するのでは、機能ユニットが遊んでいるサイクルが発生してしまう。 そこで、それぞれの機能ユニットの処理結果をレジスタに格納し次のサイクルには次の命令の処理を始めることで、順次実行するより性能向上が期待できる。 この方式をパイプライン (pipeline) 処理方式という。
命令パイプラインのイメージ
クロックサイクル/命令No | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
1 | IF | ID | RR | EX | MA | WB | ||
2 | IF | ID | RR | EX | MA | WB | ||
3 | IF | ID | RR | EX | MA | WB | ||
4 | IF | ID | RR | EX | MA |
プログラマがプログラムを書くとき、命令は順序通りに一つ一つ実行されることを期待する。 前述のパイプライン処理を行う場合と逐次実行した場合で結果が異なるような場合、それを回避するために命令パイプラインへの命令の投入を中断せざるを得ない状況が生じうる。 このような状況をパイプラインハザード (pipeline hazard) という。 パイプラインハザードには以下の3つに分類される。
他の命令とのハードウェア資源の競合が発生し、一方の命令がもう一方を待つことによるハザード。
ある命令のオペランドがその前の命令の演算結果であり、前の命令の処理完了を待つことによるハザード。
分岐条件の成立/不成立で処理を分岐する場合、条件が評価されるまで分岐先の命令をフェッチできないことによるハザード。
また、命令パイプライン中の命令を実行できないステージをパイプラインバブル (pipeline bubble) という。
Out-of-Order実行は、プログラムにおける命令の実行順序に依らず、処理可能な (オペランドが揃っている) 命令から逐次実行することでプログラムの並列性を向上させる、プロセッサの最適化手法の一つである。
Out-of-Order実行では、命令の実行順序を変更しても逐次実行したときと同じ結果が得られることを保証しなければならない。
しかし、命令間のデータ依存によって、命令の実行順序を変更できない場合がある。 具体的には、命令間のデータ依存は以下の3つの分けられる。
ある命令のオペランドがその前の命令の演算結果であるような状況。 (パイプライン処理のデータハザード)
レジスタリネーム (register renaming) は、逆依存あるいは出力依存の依存関係をもつ命令間において、それぞれ別々のレジスタを割り当てることでデータハザードを解消する、プロセッサの最適化手法の一つである。
リザベーションステーション (reservation station) は、Out-of-Order実行において命令の実行順序を変更しても逐次実行したときと同じ結果が得られることを保証するため、命令のデータ依存 (フロー依存) を管理する。
デコードされた命令は直接実行パイプラインには送られず、命令種別ごとに設けられたリザベーションステーションに格納される。
リザベーションステーションは、オペランドが揃って実行可能になった命令を順次実行パイプラインに送る。 また、リザベーションステーションは実行パイプラインの実行結果をモニタリングし、その実行結果をオペランドとして待つ命令があれば、実行結果をその命令のオペランドとして格納する。
逆依存と出力依存はレジスタリネームで解消し、フロー依存はリザベーションステーションで管理する。
レジスタバイパス (register bypass) はある命令のオペランドがその前の命令の演算結果である場合に前の命令の演算結果をレジスタを経由せずに直接受け取ることにより、演算結果をレジスタに書くステージ (WB) とオペランドをレジスタから読むステージ (RR) を省略する、プロセッサの最適化手法の一つである。 これにより、前述のデータハザードの軽減が期待できる。
分岐予測 (branch prediction) は、プログラム実行の中で条件分岐命令が分岐するかしないかを予測する、プロセッサの最適化手法の一つである。
Out-of-Order実行と組み合わせて、予測に基づき条件分岐命令後の命令を先に実行してしまう方式を投機実行 (speculative execution) といい、これにより前述の制御ハザードの軽減が期待できる。
例えば、for
文や while
文などのループの継続条件による条件分岐は最後のループを除いてすべて成立する。
このような理由から、常に分岐が成立すると予測したとしてもある程度の予測精度が期待できる。
飽和カウンタを用いた予測では、それぞれの条件分岐命令ごとに過去に分岐が成立したか (taken/not taken) の履歴を2ビットのカウンタ (飽和カウンタ) で記憶する。
飽和カウンタの値 | 定義 |
---|---|
00 | Strongly Not Taken |
01 | Weakly Not Taken |
10 | Weakly Taken |
11 | Strongly Taken |
メモリの種類 | 記憶素子 | 面積 (容量当たり) | 価格 (容量当たり) | 備考 |
---|---|---|---|---|
DRAM (Dynamic RAM) | コンデンサ (キャパシタ) | 小さい | 安い | 揮発性があるため、一定間隔毎にリフレッシュ動作が必要。 |
SRAM (Static RAM) | フリップフロップ | 大きい | 高い |
メモリアクセスには、今日のプロセッサのサイクル換算で約200サイクル近くのコストがかかる。 高コストなメモリアクセスを少しでも減らすため、メモリデータはより高速でよりプロセッサに近いSRAMにキャッシュされる。
プログラムのメモリセグメントを互いに重ならないように (物理) メモリ空間に並べていく方式をセグメント方式という。
セグメント方式の問題として、プログラムが開始や終了を繰り返すとメモリ空間の空き領域の場所が散らばり、空き容量の合計に対して確保できるメモリ領域が少なくなるという問題が挙げられる。 この問題をフラグメンテーション (fragmentation, 英語で「断片化」という意味) という。
ページング方式 (paging) は、(物理) メモリ空間をページ (page) という一定サイズ (4kB or 8kB) の単位で管理する。
各ページには、実際の先頭メモリアドレス (以下、物理アドレス (physical address)) とは別に論理アドレス (logical address) が割り当てられる。 これにより、物理メモリ空間では散らばっている空き領域も、論理メモリ空間では連続する領域として使うことができる。
物理アドレスと論理アドレスの対応は、OSが管理するメインメモリ領域内のページテーブル (page table) というテーブルで管理される。
プロセッサに搭載されているメモリ管理ユニット (MMU, Memory Management Unit) は、論理アドレスからそのページの物理アドレスを調べ、実際のメモリアクセスを行う処理を担う。 また、MMUは内部にページテーブルのキャッシュをもっており、このキャッシュをTLB (Translation Lookaside Buffer) という。
つまり、MMUは物理メモリ空間にアクセスするための高速で透過的な手段を提供する。
今日ではメインメモリの容量が大きくなっているため、より大きなサイズ (数MB) をもつページが使えるようになっている。 これをヒュージページ (huge page) という。
Linuxには確保するメモリサイズに応じて自動的にヒュージページによるページングを行う、THP (Transparent Huge Pages) という機能がある。
しかし、CoW (Copy-on-Write) を前提としたプロセスフォークを行う一部のマルチプロセスアプリケーション (例: Redis) とは相性が悪い。
それぞれ独立したキャッシュをもつマルチプロセッサシステムにおいて、各プロセッサ間のキャッシュの整合性をとることをキャッシュコヒーレンシ制御という。
MSIプロトコルは、キャッシュコヒーレンシ制御において最も基本的なプロトコルであり、キャッシュラインの状態を2つのフラグ (Invalid, Modified) で管理する。
Invalid | Modified | 状態 |
---|---|---|
0 | 0 | Shared |
0 | 1 | Modified |
1 | 0 | Invalid |
1 | 1 | 存在しない |
MSIはキャッシュラインがとりうる3つの状態 Modified, Shared, Invalid の頭文字である。
MSIプロトコルでは、各プロセッサはメモリの内容を書き換える前に他のプロセッサに対して同じメモリアドレスのキャッシュをインバリデートするよう要求を送る。 この要求をSnoop (英語で「覗き」という意味) とも呼ぶ。
また、キャッシュがライトバックキャッシュである場合は、メモリからデータを読む前に、他のプロセッサに対して同じメモリアドレスのキャッシュをメモリに書き戻すよう要求を送る。
MESIプロトコルでは、MSIプロトコルのキャッシュの状態を表すフラグ (Invalid, Modified) に新たに Exclusive が加わる。
MESIプロトコルの Exclusive フラグは「そのキャッシュのデータは変更されておらず、他のプロセッサにキャッシュされていない」状態を表す。 これにより、Exclusive なキャッシュは他のプロセッサにインバリデート要求を送ることなく変更でき、高速化が期待できる。
MOSIプロトコルでは、MSIプロトコルのキャッシュの状態を表すフラグ (Invalid, Modified) に新たに Owned が加わる。
MOSIプロトコルの Owned フラグは「そのキャッシュのデータは変更されている」状態を表す。
ライトバックキャッシュにおいて、プロセッサ1が Owned 状態のキャッシュをもち、プロセッサ2が同じメモリアドレスのキャッシュに書き込むとき、プロセッサ1はプロセッサ2に変更後のキャッシュデータを直接送る。 これにより、メモリに書き戻す回数が減り、高速化が期待できる。 また、このときプロセッサ1はキャッシュの状態を Shared に変更し、プロセッサ2はキャッシュの状態を Owned に変更する。 つまり、Owned 状態は、そのキャッシュが追い出されるときに、そのデータをメモリに書き戻す責任があるかどうかを表すフラグにもなる。