コンピュータの構成と設計 4.11~4.15節

パタヘネ4.11~4.15節です。前回まではパイプラインをいかにして実装するかという話題を議論していましたが、今回は更に並列度を増やして命令を実行しスループットを上げるにはどうしたらいいかという話題と、ARM・x86のパイプラインの実例が述べられています。

4.11

 パイプライン処理は命令を途中まで実行した段階で次の命令の処理を始めるという、命令レベル並列性が高速化の中心的なアイデアだった。並列性を高める方法として、データパスの各コンポーネントを複数用意しておいて、一度に複数の命令をそれぞれのコンポーネントで処理するという複数命令発行が考えられる。全てのコンポーネントを高い稼働率で動作させ、次のパイプラインステージに仕事を移すという作業が必要となるが並列性はあがる。このような1ステージで複数の命令を同時に実行開始する方法では、理想的な状況下でCPIが1を切ることがある。

 複数命令発行を実現する方式として、静的複数命令発行と動的複数命令発行が存在する。前者では同時に発行可能な命令をコンパイラが事前に考えて発行する。後者ではプロセッサが実行中に同時発行できる命令を考え、発行する。また、複数命令発行でもハザードは起こるので、起きた場合の対応も必要となる。静的複数命令発行ではコンパイラが事前に回避するが、動的複数命令発行ではプロセッサがハザードの検出と対応を行う。なお、両者は完全に分かれた概念ではなく、しばしば混在して用いられる。

 また、命令レベル並列性を高めるための重要な概念として投機実行が挙げられる。投機実行では、命令のこれから先の挙動を見込んで命令の完了を本来待つ必要がある別の命令を先に実行してしまう。例えばストア命令のあとのロード命令がストア命令を使わないと予想できればロード命令を先に実行できる。もし見込みが間違っていたら、間違っていた分の命令実行結果を元に戻す必要がある。投機実行はコンパイラかプロセッサが行う。コンパイラが投機実行を行う場合は、見込みがあたっていたかどうかをチェックする命令を用意し、間違っていた場合に状況を修復するルーチンが実行される。プロセッサが行う場合は、見込みがあたっていたかどうか確定するまで命令実行結果をバッファにためておく。見込みがあたっていたらメモリに命令実行結果を書き込み、間違っていたらバッファをフラッシュし、正しい命令を改めて実行する。投機実行の結果、例外が発生した場合は、その例外が本来発生すべきであるかどうか、後に判定し、発生すべきでないと分かった場合には握りつぶすことが必要となる。投機実行しているのがコンパイラであってもプロセッサであってもこの処理は必要となる。

 静的複数命令発行は発行パケットと呼ばれる、複数の命令をひとかたまりにした大きな命令を一括で実行する。そのためこの方式は超長形式機械命令(VLIW)と呼ばれる。同時に実行してしまうとハザードが発生する場合は、組にしている命令のうち一部をnopにする。この方式では、ハザードによる相対的な損失が増大する。例えば、算術・分岐命令とロード・ストア命令を2つ1組で実行するプロセッサでは、算術命令で出た結果を組となったロード・ストア命令で使用できないので、ALU演算に1命令分の使用レイテンシが付加されることになる。そのため、高度な命令スケジューリングが要求される。

 ループの性能を改善する方法として、ループ展開がある。2命令を同時に実行できるプロセッサでループしながら配列値に定数を加算していく場合を考える。例えば、

Loop:
nop lw $t0,0($s1)
addi $s1,$s1,-4 nop
addu $t0,$t0,$s2 nop
bne $s1,$zero,Loop sw $t0,4($s1)

というコードではCPIが0.8となる。一方、$s1のポインタを4byteずつデクリメントするのではなく、次のように16byteデクリメントし、加算結果を複数のレジスタに入れることでCPIを改善できる。

Loop:
addi $s1,$s1,-16 lw $t0,0($s1)
nop lw $t1,12($s1)
addu $t0,$t0,$s2 lw $t2,8($s1)
addu $t1,$t1,$s2 lw $t2,4($s1)
addu $t2,$t2,$s2 sw $t0,16($s1)
addu $t3,$t3,$s2 sw $t1,12($s1)
nop sw $t2,8($s1)
bne $s1,$zero,Loop sw $t3,4($1)

値を加算した結果を入れるレジスタとして$t0にこだわる理由は何ら存在しないので、$t1,$t2,$t3を利用している。このようなレジスタの選び方を変更する最適化をレジスタ・リネーミングという。$t0を計算に使用することで生じている命令間の依存関係を擬似依存関係といい、本質的な依存関係ではない。

 動的複数命令発行方式を取っているプロセッサをスーパースカラという。スーパースカラでは動的パイプライン・スケジューリングという、ストールを避けるため命令を発行する順序をハードウェアで並び替える処理を行っている。動的パイプライン・スケジューリングでは、命令フェッチ/デコード、機能ユニット(整数演算や浮動小数点演算、ロード・ストアなど)、リザベーション・ステーション、確定ユニットというコンポーネントを利用する。リザベーション・ステーションは機能ユニットごとに存在し、今後その機能ユニットで実行する命令とオペランドをバッファしている。機能ユニットが利用可能になり次第その命令を実行する。確定ユニットは実行された命令をレジスタやメモリに書き込んでいいタイミングが来るまでリオーダ・バッファにバッファリングしておきタイミングが来たらレジスタやメモリに書き込む。

 リザベーション・ステーションにはオペランドのレジスタ値がコピーされる。そのため、コピー後になにか別の命令が当該レジスタの値を上書きしても問題ない。また、命令が必要とするオペランドの結果がまだ出ていない場合、機能ユニットからその結果が出てくるのを待つ必要がある。結果が出たらレジスタに書き込まれるのを待たず、リザベーション・ステーションに値が直接コピーされる。これらの動作の結果として、命令に指定されているレジスタ番号は名目上のものとなり、一種のレジスタ・リネーミングが起きているのと等価となる。

 以上のように、動的パイプライン・スケジューリングは命令をフェッチした順序どおりに命令を実行せず、プログラムのデータフロー構造を分析して実行している。このことをアウトオブオーダー実行という。一方、確定ユニットは元々の命令の順序と辻褄が合うように結果をレジスタやメモリに書き込む。この動作をインオーダー確定という。アウトオブオーダー実行を行う場合は、新たなタイプのパイプラインハザードが起こる。プログラム中の先行する命令iと後続する命令jを考える。iが読み込むレジスタもしくはメモリにjが書き込むとき、Write-After-Read(WAR)ハザードが起きる。iが書き込むレジスタもしくはメモリ位置にjが書き込むときWrite-After-Write(WAW)ハザードが起きる。これまでに見てきたパイプラインハザードはRead-After-Write(RAW)ハザードという。

 複数命令発行方式と投機実行で命令レベル並列性を活用しようとするとエネルギー効率が悪くなる。近年はパイプライン段数と消費電力を減少させる方向でプロセッサが設計されている。

4.12

 ARM Cortex-A53はデュアル発行と静的スケジュールを行うスーパースカラプロセッサである。また、動的命令発行検出機能をもつ。デュアル発行なのでCPIは理想的には0.5となる。浅いパイプラインと積極的な分岐予測器を使用することでパイプラインでのロスを抑え、電力消費が低くても高いクロック周波数が達成されている。結果としてA53の消費電力はi7の200分の1である。

 Intel Core i7 6700では精巧なパイプライン処理方式が取られている。x86命令セットは非常に複雑なので、マイクロオペレーションというMIPS風の内部的な命令に翻訳して実行している。i7では投機実行が積極的に行われている。また、大規模な待ち行列やバッファが存在しており、リザベーション・ステーションや名前替えレジスタやリオーダー・バッファの枯渇によるストールの可能性が相当に軽減されている。従ってロスの原因は分岐予測ミスかキャッシュ・ミスに起因する。様々なプログラムでベンチマークを取り、平均命令実行時間を比較するとi7はA53より5倍以上高速に動作する。反面前述の通り消費電力は200倍となる。

4.13

前章で作成したSIMDを用いる行列演算にループアンローリングを適用してさらなる高速化ができる。

4.14

省略

4.15

 これまで見てきたようにパイプライン処理は難しく、著者が出した別の本にパイプラインに関するバグが存在したときは、100人以上の人にレビューを行ってもらったにも関わらずバグが見つからなかった。

 パイプラインの設計思想は製造テクノロジと不可分であり、トランジスタ数とトランジスタ速度の制限が大きかった時代は遅延分岐が制御ハザードに対するベストな解だった。トランジスタ数とトランジスタ速度が向上するにつれ、動的分岐予測と投機実行が理にかなうようになった。現在は消費電力への懸念から複雑な設計は回避されるようになってきている。

 命令セットの設計が悪いとパイプラインに負の効果を与える。命令長や実行時間が大幅に可変であるとステージ間のバランスが崩れ、ハザード検出が困難になる。また、精緻なアドレッシングモード、例えばレジスタを自動更新するようなアドレッシングモードを使うとハザード検出が困難になる。

コメント

タイトルとURLをコピーしました