より高いクロック周波数を達成するにはパイプラインの段数を深くすればよいが、その分、分岐による初期化ペナルティは大きくなる。
「パイプライン」というと、石油を運ぶための長い管を想像するかもしれない。人によっては、サーフィンとかエレキ・ギターを連想するに違いない。しかしここでいう「パイプライン」とは、もちろんプロセッサのパイプラインのことだ。だがYahoo!で「パイプライン」を検索したら、プロセッサのパイプラインの記事は上位でヒットしなかった(残念)。というわけで、冒頭でお断りしておく。今回は、プロセッサのパイプラインと、動作クロックの関係に迫ってみる。
今度のPentium 4は20段パイプライン(正確にいえば、さらに段数が増える)という話が聞こえてきて、筆者はのけぞってしまった。20段、トンでもない段数である。まぁ、3段、4段なら普通だが、5段、6段を超えるとかなり複雑になる。10段になると、ビックリという感じ。ちなみに、Pentium IIIは10段だった。
ご本家、石油のパイプラインが長い筒(パイプ)の先から原油などを流し込むと、順次末端から流し込んだものが出てくるものであることは、皆さんご存じだろう。サーフィンのパイプラインは大波が崩れるときのパイプ状の空間をサーフすることからきたらしく、さらにサーフィン音楽(?)ということで、そのイメージは未だに来日して全国ツアーを展開している往年の名バンド「ベンチャーズ」を超えて、かの「チューブ」にまで連なっているようだ。プロセッサのパイプラインもせんじ詰めれば、石油のパイプラインと発想は同じである。ただ、こちらには音楽にまで連なるイメージがないのが残念なところ。多分、それはプロセッサのパイプラインというものが、機械語命令(インストラクション)というものを飲み込み、搬送していく概念であり、クロックにより駆動(ドライブ)されるサイバー(?)な存在であるためだろう。
プロセッサのパイプラインの概念そのものは、そう難しいものでもない。順番に理解していただくために、まず、パイプラインではないプロセッサというものを考えてみることにしよう。だいたいプロセッサのやるべき仕事というのは決まっている。まず機械語命令をフェッチ(メモリから取り出す)し、次に命令をデコードし(命令の意味するところを解釈する)、最後に実行する、という具合だ。「実行」の部分をもう少し細かく説明すれば、まず演算に必要なデータを読むこと、演算(計算)すること、結果(データ)を書くことの3つに分けることができる。深く考えなければ、それほど難しいことではない。
パイプラインではないプロセッサというのは、まず第1のクロックでフェッチをして、第2のクロックでデコードをし、第3のクロックでデータを読んで、第4のクロックで演算をし、第5のクロックでデータを書く、という具合に動作するものをいう。次の命令を処理するのは第6のクロックからだ。つまり、この例だと5クロックかかって、1つの命令を処理することになる。
これに対して、パイプライン化されたプロセッサでは、第1のクロックで第1の機械語命令をフェッチ、第2のクロックでは第1の機械語命令をデコードしつつ、第2の機械語命令をフェッチ、第3のクロックでは第1の機械語命令のデータを読み出して、第2の機械語命令をデコード、第3の機械語命令をフェッチ……。切りがないのでここまでにするが、こんな具合に動くプロセッサである。これを実現するには、フェッチだけを行う装置と、デコードだけを行う装置、読み出しだけを行う装置、演算だけを行う装置、書き込みだけを行う装置をおのおの独立させ、それぞれの入り口と出口をつなげておけばよい。ほうら、どんどん機械語命令が読み込まれて順次送られていく、パイプラインがイメージできただろう。パイプラインというよりも、むしろ工場のベルトコンベアの方が、次々に加工されて送られるので、イメージが近いかもしれない。
ここで大事なのは、1つの命令を処理する時間に限っていえば、上述の例の場合、パイプライン化されていないプロセッサでもパイプライン化されたものでも、5クロックという同じ時間がかかっているにもかかわらず、パイプライン化されたものでは毎クロック1命令の処理を開始(あるいは完了)できる点だ。パイプライン化されていないものでは5クロックに1命令しか処理できないので、ある一定の時間で比べれば、パイプライン化されたプロセッサは、そうでないものより5倍の数の命令が処理できることになる。これだけでもパイプラインの効能が分かるだろう。
さらにパイプラインには、また別の効能がある。パイプラインを深くする(段数を増やす)ことで、同じテクノロジ(製造技術)を使って、より高いクロック周波数を達成できることだ。上の例であれば、1クロック当たり5倍の命令を処理できるのに加えて、1クロックの時間自体が短くなる。
その理由はこうだ。プロセッサは、詰まるところ論理回路であり、論理回路は「ゲート(gate)」と呼ばれる基本論理素子からできている。テクノロジにより、基本論理素子の動作速度、つまり1つのゲートの入力から出力までの遅延時間は決まっている。ここで簡単にするため、仮に1ゲートに1ns(10億分の1秒などというと非常に速いように思えるが、半導体業界の現状からすれば非常に遅い素子だ)かかるとして、あるデータが100ゲートを次々に通り抜けるような回路を組んだとしよう。100nsの時間がこの回路を動作させるために最低限必要な時間ということになる。100nsは1/100ns=10MHzだ。つまり、この回路は最大10MHzのクロックで駆動できる。
ところが、この回路を10段のパイプライン構成にしたとしよう。10ゲートごとに、クロックによって記憶する素子を挿入し、前後を切り離すことにする。記憶素子の挿入によるオーバー・ヘッドをとりあえず無視すれば、10ゲートは10nsである。つまり、この回路は100MHzのクロックを与えても動作する。これでクロック速度が10倍になった。もちろん、1つのデータは100ゲートを通り抜けるので100nsかかるのだが、毎クロックあたり10nsごとに別のデータが処理できるようになるから、100nsの期間を見れば10個のデータが処理されることになる。
このように、パイプラインというのは近代的なプロセッサ設計において、高速化のために必須の手法なのである。しかし、当然、パイプラインを深くした場合のペナルティも存在する。最も大きなものは、分岐によるパイプラインの初期化ペナルティである。
パイプラインは、その名のごとく次々と命令が流れている状態で最高の性能を発揮する。しかし、命令をデコードし始める初期状態では、パイプラインは空だからパイプラインの深さ(長さ)だけのクロックが経過しないと、その命令は完了しない。こうした状態は、プロセッサの始動時だけでなく、分岐(ジャンプあるいはブランチ)が発生したときにもパイプラインが初期状態に戻されるために起きる。もちろん、リセットというのもあるが、これは特殊な分岐といえる。
分岐があると、プロセッサはパイプラインをフラッシュ(空の状態にする)して、新たな番地から新たな命令をフェッチして、またパイプラインに詰め込む作業を再開する。パイプラインが深ければ深いほど、分岐してから結果が出始めるまでに時間がかかる。やっかいなことに分岐は結構頻度が高い。一般的なソフトウェアでは、数十%ということもある(10個のうち数個が分岐命令である、ということ)。それでは10段ものパイプラインを作ったら、なかなかパイプラインが詰まった状態にならないことになる。
このため、近代的なプロセッサ設計では、分岐を分岐にしないための工夫をあれこれ重ねることで、このペナルティを隠ぺいすることに奔走してきた。分岐予測というのがその代表である。これは、分岐先を実行前に予測して、分岐先になると予想した方の命令をパイプラインに詰め込んでしまうというテクニックだ。予測が当たればパイプラインはフラッシュされずに詰まっていく。しかし、予測が外れればペナルティからは逃れられない。まぁ、10回のうち9回も予想が当たれば、十分な効果があるといえるだろう。2回に1回ならば、コインを投げた方がよさそうだ。
このようにペナルティを隠ぺいするための工夫は数多い。しかし、これがまた別なペナルティを作り出す。それは「複雑度」というペナルティである。複雑な設計は、設計が難しくなるだけでなく、回路規模を増大させる。先ほどの例でいえば、100段のゲートを連ねれば作れた回路が、2倍の200段のゲートを連ねないとそれらの工夫を盛り込めなくなるということである。結果、同じパイプライン段数では、半分の動作周波数でしか動かなくなるかもしれない。
プロセッサ設計の神髄は、このような相反する要素間のトレード・オフを行うことにある。パイプラインを深くすれば動作周波数は上げやすい。しかし、ペナルティも大きくなるので隠ぺい工作が必須になる。その工作が周波数の足をひっぱり、という悩みの中で解を見つけ出すわけだ。歴代のPentiumがどのように解を出してきたか見てみよう。
初代のPentiumは、フェッチ、デコード、デコード、実行、書き戻しという先ほど例に挙げたものに近い、5段パイプラインである。さらに、2個の命令を同時に実行できる、x86初のスーパースカラーでもあった。しかし、何でも2命令同時に実行できるわけではなく、その組み合わせには制限があったほか、実行前の準備にちょっと時間がかかっていた。ただ、2命令同時実行といっても、実行順序は機械語命令の並びどおり(イン・オーダー)であったから、シンプルなパイプラインで済んでいる。
Pentium Pro以後、Pentium II/IIIの系統、あるいはAMD-K6、Athlonといったプロセッサ群は、いずれもx86命令をRISCオペレーションなどと呼ぶ、より単純な細かな命令に変換してから実行するようになった。これは、同時により多くの命令を実行する並列度を追求したためである。そのため、初代Pentiumではデコードして、2個のペアを作るかどうかを準備する程度であったデコードの過程が複雑化し、ステージ(パイプラインでの各処理段階)が増えている。また、アウト・オブ・オーダー(命令の並びどおりではない)な実行をするようになったため、レジスタ・リネーミングのステージ(同一レジスタを使用する複数命令をパイプラインで同時実行可能にする技術)や、命令発行順序を整理するためのステージなどが増えて、10段という深いパイプラインを持つようになっている。
まもなく登場するPentium 4では、上のPentium IIIの方法は踏襲しつつ、主としてAMD製プロセッサとの最高動作周波数競争に前述の原理で差をつけるためと考えられる、一気に20段という「ハイパー・パイプライン」構造を導入した。ざっくり10段対20段、段数的にはPentium IIIの各段を2段に分割した形であるから、単純に考えれば2倍の周波数で動くはずである。実際には、段数が増えることで発生するオーバーヘッドもあるだろうから、せいぜい50%増しくらいかと思うが、それにしてもクロック周波数は格段に伸びるだろう。プロセスの進化を考えれば、2倍にもすぐ手が届きそうだ。
ただしPentium 4では、単純にPentium IIIのパイプライン構造を半分に分割したのではなく、段数を多くしたなりの最適化を行った様子がうかがえる。その一番に挙げられるのが、1次キャッシュにデコード済みの命令を格納するようにしたことだ。このため、本来のx86命令のフェッチとデコードは1次キャッシュにロードする過程で行われ、主となる命令実行のパイプラインからは切り離された。このことから分かるように、Pentium 4のパイプラインは、Pentium IIIのパイプラインの後半のみを20段に細分化し、最適化したものともいえるのだ。また、もう1つの注目点は、近年、半導体設計上の最大の障害となっている配線遅延(チップ内の配線を信号が伝わっていくのにかかる時間)の問題に対応しており、長い距離の信号の伝播のために、新たなステージを持たせていることである。ほかにも、ALU(Arithmetic and Logic Unit:数値演算などを処理する回路)は2個しかないにもかかわらず、命令によってはそれぞれ1ステージで2個の演算が可能なので、合計4命令を同時演算できるなど、いろいろな工夫をしていて凄い。
いやー、浜の真砂(まさご)は尽きるとも、世にパイプラインの工夫の種は尽きまじ。
日本では数少ないx86プロセッサのアーキテクト。某米国半導体メーカーで8bitと16bitの、日本のベンチャー企業でx86互換プロセッサの設計に従事する。その後、出版社の半導体事業部を経て、現在は某半導体メーカーでRISCプロセッサを中心とした開発を行っている。
「頭脳放談」
Copyright© Digital Advantage Corp. All Rights Reserved.