それでは、このパイプラインをどのように構成して行くかを見てみよう。
パイプラインステージの長さ
これまでに見てきたように、パイプライン的に処理を行う場合、メモリアクセス、命令デコード、演算器などが並列に動作する。
図4.1 パイプラインステージの遅延時間 |
図4.1は、図3.11のパイプラン動作の図をコピーしたものであるが、メモリアクセスはサイクル一杯の時間が必要であるが、演算器と命令デコードは半サイクルの時間しか必要としないという想定で、これらの資源が遊んでいる時間を薄い灰色に塗っている。図4.1を見ると、濃い灰色のストールと薄い灰色の部分が多く、ハードウェアの利用率が悪いことが分かる。これを、メモリアクセスはパイプラインを2ステージ使用するというパイプライン構造とすると、図4.2のような実行状況となる。
図4.2 メモリアクセスを2ステージ処理とした場合のパイプライン実行状況 |
この図のようにパイプラインを構成すると、ハードウェアが使用されていない灰色の部分が大幅に減少し、また、全体で11サイクルで処理が終了している。図4.1では16サイクル相当の時間(図4.1では8サイクルであるが、図4.1の各サイクルの時間は2倍である)がかかっているので、性能的にも約1.5倍に向上したことになる。
また、図4.2では、命令の読み出しは2サイクル毎となっているが、メモリシステムの内部を前半と後半の2段のパイプラインとして、1サイクル毎に次の命令を読み出すパイプライン構造とすることも可能である。
このように、パイプラインステージ間で何倍も処理時間に差があるような場合は、長い処理を複数段のステージに分割して、各パイプステージの処理時間を均一化することが行われる。また、小さなアンバランスの場合は、長いパイプステージの論理回路を短いパイプステージに移動して処理時間をバランスさせるというようなチューニングが行われる。
このように書くと、処理時間に差がなくても、全部のパイプステージをどんどんと細分化していくと、どんどんとサイクルタイムが短くなり、クロック周波数が上げられるのではないかという疑問を持たれた方もおられるのではないだろうか。
この答えは、実は、かなりの程度、Yesである。しかし、パイプラインの処理時間は、次の図4.3に示すように、処理を行う論理回路(この図ではArithmetic Logic Unit: ALU)の遅延時間Taluに、ステージを区切るFlip Flop(FFと略す)のクロックエッジから出力までの遅延時間Td、クロックより前に信号が到着する必要のあるセットアップ時間Tsetup、そしてクロックのずれのTskewが加わる。つまり、サイクルタイムTcycle > Talu+Td+Tsetup+Tskew(同じかそれ以上)という関係が存在する。
図4.3 サイクルタイムを構成する遅延要素 |
そして、ALUのパイプステージを2つに分解したとしても、図4.4に示すようにTd+Tsetup+Tskewが2回含まれることになり、サイクルタイムは半分(=クロック周波数は2倍)にはならない。
図4.4 ALUを2分割した場合の遅延要素 |
しかし、2分割で2倍にはならないとしても、パイプラインを細分化することによりクロックを上げることは可能で、IntelのNetburstマイクロアーキテクチャでは、30段程度のステージを持つ長いパイプラインを用いて15~20段程度のパイプラインを持つ他社のプロセサより30~50%高いクロック周波数を実現していた。
パイプラインの細分化は、クロック周波数を上げるという点では一定の効果があるが、30段のパイプラインで毎サイクル命令を発行したとすると、1サイクルに最大30個の異なる命令が実行されていることになり、それらの命令の間で構造的ハザードやデータハザードが発生する可能性があるということである。また、分岐方向が確定し、分岐先の命令をフェッチできるまでのコントロールハザードのサイクルも多くなる。つまり、パイプライン段数が増えると、これらのハザードが増え、平均的に1サイクルで実行できる命令数が減少し、クロックあたりの性能は低下する。
さらに問題なのは、全部のパイプラインステージを半分に分割すると、FFの数が2倍になり、更に、クロック周波数が2倍になるので、FFとそれを駆動するクロックの消費電力は4倍に増加してしまう。ALUの消費電力はクロックの向上分の2倍であるが、通常、ALUなどの組み合わせ回路の電力よりもFFとクロックの電力の方がずっと大きいので、パイプラインの細分化により消費電力は大幅に増加してしまう。これがNetburstアーキテクチャのPentium 4がどんどんクロックを上げて性能向上させることができなくなり、Coreアーキテクチャのプロセサに取って代わられてしまった理由である。