― 連載 ―
ゲーマーにとって,CPUとは何か

 CPUとはCentral Processing Unit(中央演算処理装置)の略で,各種計算やデバイスの制御を行う装置のこと,というのは,本誌読者の中でも知っている人は多いだろう。ゲームをプレイするに当たっては,"速い"CPUが望ましいのは言うまでもない。
 では,「速いCPU」とは何だろうか? とくに「ゲームで速いCPU」は,どういったCPUなのだろう?
 これについて,ちょっとまじめに考えてみよう,というのがこの企画である。第1回では,ゲームにCPUがどう関わっているのか,そして,現在のCPUがどういう構造になっているのか,といった側面から,速いCPUとは何かを考えていきたい。

 そもそもCPUとは何なのか。これをどこまで掘り下げるかは難しいところで,例えばバベッジの計算機械(階差機関)までさかのぼったら,さすがに誰も読む気をなくすだろうし,あるいは「んじゃ原理的に」ということで,ブール代数の話を始めても,やっぱり読まれなくなることは明白だ。あるいは,「では電気の基礎から」と,半導体についての解説や真空管の動作原理から始めたら,きっと編集部から怒りの鉄槌が下されてしまうだろう。
 というわけで,こういった昔の話や基礎の基礎についてはざっくり割愛して,ゲームとCPUの関わり合いについて話をしていきたいと思うが,ゲームを動作させるとき,CPUが行うべき処理はきわめて多岐にわたっている。具体的には,以下のような処理を同時に行わねばならない。

  • マウスやキーボード,ジョイパッド/ジョイスティックなどが操作されたことを検出し,「何がどの程度操作されたか」を確認して,OS経由でゲームなどのプログラムに伝える
  • ユーザーの操作に合わせて,自分の位置や状況を計算する
  • プレイヤーキャラクターの位置や状況に合わせて「それ以外のものがどうあるべきか」の計算をする
  • プレイヤーキャラクターやそれ以外のものがどう表示されるべきかを計算した結果に従って,計算結果に合った画面を合成し,それを画面へ出力できるようにしてグラフィックスドライバに送り出す
  • グラフィックスドライバが受け取ったデータを,グラフィックスカードに合わせた描画命令に変換して送り出す
  • OSそのものを動かす

 PCの場合,どんなに高性能のグラフィックスカードであっても,それ自体が勝手に描画を行ったりはしない。また,どんなに高性能のHDDであっても,勝手に読み書きをしたりはしない。こうした「デバイス」(周辺機器)と呼ばれるものは,いずれも命令が来るのをひたすら待っており,命令が来たらそれに従って動作する。そして,CPUが唯一,これらのデバイスに命令を下す立場にある。CPUがPCの要とか中枢とか言われるのは,こういうわけだ。
 こうなると,CPUが高速に処理できればできるほど,PC全体はきびきびと動く。PC全体を一つの大邸宅と見なした場合,CPUというのはその邸宅の管理を任された執事だと思えばいい。そして,その下にはメイドさんとか庭師とか料理人とか,さまざまな人間がいるわけだが,これらは各デバイスに相当すると考えてほしい。このとき,執事がのろのろと指示を出していたら,お屋敷の維持は全然できなくなってしまう。まずは執事の能力ありきというわけである。

 ところで,執事の能力,もといCPUの能力を語るときに付き物なのが「動作クロック」だが,この正体について触れておこう。  動作クロック――正確にいうと「動作周波数」だが,4Gamerでは動作クロックと呼ぶ――とは,簡単にいえば「どのくらいのスピードで命令を処理できるか」を表す数値で,通常「Hz(ヘルツ)」という単位を使って示される。ラジオの周波数とか,電源コンセント(AC100V)が富士川を挟んで東西で周波数が違うとかいうときにも使う,あのHzである。
 例えば「50Hz」といえば「毎秒50回」の意味。「動作クロック50HzのCPU」なら,毎秒50回の命令処理を行うCPUということになる。  CPUの場合,外部から動作速度を決めるための信号を入れてやる必要がある。この信号は英語で「Clock Signal」あるいは「Clock Source」と表記し,「クロック」と一言で終わらせる場合も多いが,本稿では以下「入力クロック」とする。
 ただし,この入力クロックは,必ずしも動作クロックとイコールではない。というか,IntelやAMDといった,本誌読者に関係の深いメーカーのCPUで考えると,(入力クロック:動作クロック)=(1:1)だった例は,「Intel 486DX/50」という,相当昔のCPU(Pentiumより昔である)の50MHzまでさかのぼる必要があるのだ。Intel 486DX/50では,50MHz(「M」は100万を示す値なので,5000万Hzということになる)の入力クロックで,50MHzの動作クロックにて動作した。しかし,これ以降は(入力クロック:動作クロック)=(1:1以上)という関係になり,例えば2005年10月現在において,最も動作クロックが高いIntel製CPU,Pentium 4 670/3.80GHzの場合,入力クロックが200MHz,動作クロックは3.80GHz(「G」は10億を示す値であり,「1GHz」は「10億Hz」の意味になる)なので,動作クロックが3.80GHzというのは,毎秒38億回の速度で処理をしているということになる。入力クロックの200MHzを19倍して,3800MHz=3.80GHz動作しているわけだ。

CPUの基本構造とパイプライン

 いきなり動作クロックの話をしたので,要するに動作クロックが高ければいいのか,と思うかもしれないが,話はそう単純ではない。
 図1は,CPUの構造をとことん単純化したものだ。大別すると,「フェッチ(Fetch)」「デコード(Decode)」「エグゼキュート(Execute)」「ライトバック(Write Back)」という4ステージに分類される。それぞれの機能は大まかにいって以下のとおり。


 図1

CPUの構造を極端に単純化したもの

  • フェッチ(Fetch):メモリもしくはキャッシュから,次に処理するべき命令を取り込む。大邸宅の例でいえば,執事が予定表を見て,次に行うべき処理を確認するようなものだ。
  • デコード(Decode):フェッチした命令を見て,実際に処理すべき内容を確定させる。「庭の手入れ」なら,命令すべく庭師を呼ぶなり,そもそも庭師を呼ぶべく誰か手空きのメイドさんを探すなり,という手順だ。
  • エグゼキュート(Execute):確定した命令を実施するのがここだ。庭師に「庭の手入れをしなさい」と命令するのがこの段階である。一言でいえば,CPUの処理というのは「データの加工※1」なので,多くの場合,処理前には加工前のデータを読み込む必要があり,この段階でデータをレジスタ・キャッシュ・もしくはメモリ(いずれも第2回で解説)から読み出す処理が同時に行われる。
  • ライトバック(Write Back):処理した結果を反映させるのがここである。例えば,「1+1=」という計算問題があるとすると,まず頭で「2」と計算するが,ここまでがエグゼキュート。計算問題に回答するには,回答欄に「2」と書かなければならない。この作業を行うのがライトバックだ。
※1「加工」という表現を分かりにくいと感じるかもしれないが,CPUの処理は基本的に「命令に従って,特定のデータを操作する」というものである。それは1を足すのかもしれないし,2で割るのかもしれない。中には「あるデータの値に基づいて別のデータを処理する」(「メイドさんAが寝ていたら,メイドさんBに叩き起こさせる」ようなもの)場合もあり,単純に「計算」というよりは「データの加工」のほうがしっくりくる。

 さて,初期のCPUはこの4ステージをのんびりと実行していた。フェッチ→デコード→エグゼキュート→ライトバックが各1サイクルで処理できると仮定すると,一つの命令を完全に終了するには4サイクルかかるといったイメージである。
 また新しい言葉が出てきた。「サイクル」は「Cycle」のことで,元々は動作クロックのHzと同じ意味である。かつては「東日本の交流は50サイクル」などと呼んでいた時代もあった。その後,周波数の単位はHzに統一されたため,今では「東日本の交流は50Hz」と呼ぶのが当たり前だが,ではその50Hzの交流の波形1個1個を数えるときには,現在でもサイクルを単位にすることが慣習として残っている。だから上の文章も「一つの命令を完全に終了するには4Hzかかる」と書き換えても間違いではない。ちなみに「サイクルタイム(CycleTime)」という言葉もあり,これは1サイクルにかかる時間,要するに1秒をサイクルで割ったものになる。つまり50Hzの場合,サイクルタイムは1/50秒=20ms(20ミリ秒)だ。


 というわけで,4サイクルはあまりに効率が悪い。そこで考え出されたのが「パイプライン(Pipeline)」という方式である。フェッチ・デコード・エグゼキュート・ライトバックを同時に独立して実行できるようにすると,一度に処理できる命令の数は,パイプライン構造を採っていないとき(図2上)と比べて4倍に増える(図2中)。
 これは,バケツリレーをイメージすると分かりやすい。水を100m運ぶとして,一人でこれを運ぶとなると,運べる量はたかが知れている。ところがこれを25mづつ4区間に分け,4人が25mづつ運ぶようにすれば,運べる量は時間あたり4倍になる。
 もっとも,25mは一人で運ばなければいけないから,まだ高速化の余地がある。100mを100分割して100人連れてくれば,ほとんど歩かずにバケツの受け渡しができるようになるから,運べる量は圧倒的に増えるだろう。こうした具合で,パイプラインをさらに細分化して高速化するのが「スーパーパイプライン(Super Pipeline)」という技法である(図2下)。


 図2



上(パイプラインを利用していない),中(パイプライン使用),下(スーパーパイプライン)の例。横方向に振ってある数字がサイクルを示す。例えば4サイクルめで比較すると,上ではエグゼキュートしか行えないが,中ではフェッチ・デコード・エグゼキュート・ライトバックの三つを同時に実施できるので,4命令めフェッチが始まっている。さらに下になると,5命令めのフェッチが始まっているのが分かるだろう。パイプラインの存在を加味すると,CPUの動作クロックがCPUの能力を必ずしも意味しないというのも,分かってもらえると思う

CPU性能を大きく左右する
スーパースカラとアウトオブオーダー

 パイプラインを説明したところで,先の大邸宅の話を再び。例えば洗濯物を処理するという仕事を,執事が一人のメイドさんにやらせているとすれば,これはいくら迅速に仕事をさせても限界はある。きびきびやらせたところで,洗剤洗い10秒,ゆすぎ15秒,乾燥10秒……というわけにはいかないし,一度に100kg分洗えというのも無茶な話だ。手すきのメイドさんをあと何人か探し,一緒に仕事させれば洗濯の効率はグンと上がるだろう。このように,並行して実行できる処理を同時に行わせるのが「スーパースカラ(Superscalar,スーパースケーラともいう)」と呼ばれる技法だ。
 もちろん,すべての処理を並列に行わせるわけにはいかない。洗濯した後,ワイシャツには糊付けをするとしよう。この場合,洗濯が終わったものを手分けして片っ端から糊付けしてはマズいわけで,あるメイドさんがまず洗濯物の中からワイシャツを選び出し,それをほかのメイドさんが糊付けするという手順になるはずだ。つまり,スーパースカラが常に実行できるとは限らないわけで,「いかにして作業を同時に実行させられるか」が執事の腕の見せどころとなる。CPUの場合,この処理を行うのは「ディスパッチ(Dispatch)」という機構で,スーパースカラを利用するパイプラインにはこのディスパッチのステージが追加されている(図3左下)。

 図3


パイプライン,スーパーパイプライン,スーパースカラ,命令変換,アウトオブオーダー,VLIWのイメージ。赤色矢印は,機能拡張の流れを示している

 ところで今回の話は,CPU一般というより多少「x86」(エックスハチロク)系CPUに特化した話になっている。x86の概要についてここで深く述べることは避けるが,現在,エンドユーザー(=本誌読者)が使うPC用として流通しているIntelやAMDのCPUはすべてx86系CPUである。
 一般にx86系CPUと呼ばれるものは,1995年に登場したIntel製CPU「Intel 80386」がもとになっている。ただそのIntel 80386は,もともと1978年にIntelが発表した「Intel 8086」の上位互換を保っており,このIntel 8086のおおもとになったのが,1968年に登場し,世界最初のマイクロプロセッサと呼ばれている「Intel 4004」である。
 いきなり歴史の話を持ってきて何がいいたいかというと,現在のx86系CPUは,こうした大昔の設計を引きずっている関係で,(プログラムの書きやすさ/書きにくさはともかく)ハードウェア的には非常に高速化しにくい命令体系となっているのである。メイドさんが実は全員外国人で,「いつものアレ」とご主人様が日本語で言ってもさっぱり分からない,といった具合。執事は「いつものアレ」を「ワインセラーから○○というワインを出して,栓を抜いてワイングラスに注いで持ってこい」と言い換えなければ,用件はまったく伝わらないのだ。
 これが実際の大邸宅だと「ちゃんと言葉のわかるメイドを用意しろ」という,至極もっともな話になるが,CPUの世界では,実は「命令変換」(図3中央下で,デコードとエグゼキュートの間に挟まっているトランスレート(Translate)がそれだ)という形で翻訳してあげたほうが効率がよかったりする。なんというか,言葉が分かるメイドさんはいずれも鈍重で,分からないメイドさんは機敏に動くから,翻訳の手間をかけても機敏に動くメイドさんを使ったほうがトータルでは早いという感じだろうか※2。


※2だんだん設定がわけ分からなくなってきた。メイドさんを出したのは失敗だったか?

 ちなみにCPUの世界では,前者(言葉のわかる鈍重なメイドさん)を「CISC(Complex Instruction Set Computer,複合命令セットコンピュータ)」,後者(言葉のわからない機敏なメイドさん)を「RISC(Reduced Instruction Set Computer,縮小命令セットコンピュータ)」と呼ぶ。なぜRISCが高速かというと,大きな要因は,処理する命令を単純なものに限ることで,デコードを高速に行えるようになっている点にある。複雑な命令を解釈できるようにすると,どうしても回路規模は大きく複雑になり,結果としてメイドさんはいちいち辞書を引きながら命令を解釈しなければならないから,機敏に動けなくなる。だから,執事側で翻訳して命令を簡潔にしてやればすぐ理解できて動けるというのは,メイドさんもCPUも同じなのである(本当か?)。

 この翻訳に合わせて,「アウトオブオーダー実行」(Out of order execution,以下アウトオブオーダー,図3右下)と呼ばれるメカニズムも導入された。ここまで説明してきた方式はいずれも「インオーダー実行」(In order Execution,以下インオーダー)と呼ばれており,「結果が出てから次の処理に取りかかる」を原則としている。メイドさんに皿洗いと掃除と洗濯をさせる場合,まず「皿洗いをしろ」と命じ,「皿洗い終わりました〜」の報告を受けて「次は掃除を行え」と命令,その完了報告を受けて次に洗濯の命令という具合で,毎回毎回,処理がちゃんと終るのを待って次の命令を下すやり方がインオーダーだ。これに対しアウトオブオーダーでは,「皿洗いと掃除と洗濯をやれ」とまとめて命じておき,それをどういう順番で処理するかはメイドさん任せになる。
 ここで応用が利かないメイドさんの場合,素直に皿洗いをして,終ったら掃除をして,それが終ったら洗濯にかかるという具合で,スピードアップの効果はない。しかし,応用が利くメイドさんなら,まず洗濯機を動かしておき,洗濯&ゆすぎが終るまでの間に皿洗いなり掃除なりを並行して行えるだろう。洗濯物が大量にあって,何回かに分けて洗う必要があれば,まず洗濯機を動かしながら皿洗いをし,次に今度は洗濯機を動かしながら掃除といった感じで,完全に並行して行える。
 このように,複数の処理を同時に行えるのがスーパースカラである。このとき,執事は後で「皿洗いと掃除と洗濯終りました〜」とまとめて報告を受けるようになっており,それがどういう順で行われたかに関与する必要はない。
 もっとも,前述したように,メイドさんの手際が悪いと,かえって時間が掛かってしまうから,利用するさいにはうまく並行処理できるような命令を与えてやる必要がある。そういうわけでx86ではたいてい,アウトオブオーダーはスーパースカラや命令変換と一緒に利用される。

 ちなみにこの命令変換効率を徹底して追求したのが,Transmeta(トランスメタ)製CPU「Crusoe」(クルーソー)「Efficeon」(エフィシオン)である。こちらは独自の「CMS(Code Morphing Software)」という仕組みでx86命令を独自命令に変換したうえ,さらに「VLIW」(Very Long Instruction Word,図3右上)と呼ばれる方式を使って高効率化の実現に成功した。ただ,これに続くメーカーはまったくなく,かつTransmeta自体がビジネスの方向性を転換。CPU事業のほとんどを香港のCulture.com Technologyに売却することを決定してしまっている。実際には,一部のメーカーに対してEfficeonの提供を続けていくが,本誌読者としては,もはや追いかける必要はないだろう。

パイプラインと分岐予測の関係

 パイプラインやスーパーパイプラインが一般的に採用されるようになったことで,パイプライン段数も増えてきた。Pentiumシリーズで見てみると,7〜8段(Pentium)→10段(Pentium II/III)→20段(Willamette/NorthwoodコアPentium 4)→31段(PrescottコアPentium 4)といった感じだ。
 ではなぜ,パイプライン段数が増えてきたのだろうか。


 先ほど説明したCPUのパイプラインは,半導体の主力構成要素である「トランジスタ」という素子を組み合わせて構成されている。
 ここで仮に,図4上のようなパイプラインにおいて,各段がいずれもトランジスタ10個を直列に並べた構造でできているとしよう。このトランジスタが各1ns(1ナノ秒,1ナノは10のマイナス9乗)で動作すると仮定すると,パイプラインの各段はトランジスタ10個分=10nsで処理が完了する。サイクルタイムは周波数の逆数で1ns=1GHzだから,10nsは100MHz。この構成では,動作クロックを100MHz以上にすると,トランジスタの速度が追いつかないことになる。

 図4



 では,パイプラインを図4下のように分割し,パイプライン各段が5トランジスタで構成されるように作り替えたらどうなるだろう? 各段の処理が終わるまでの時間は5nsに短縮されるから,200MHzまで動作クロックを上げられるようになる。
 この例はあまりに単純化しすぎというきらいはあるものの,実際のCPUとパイプラインの関係はおおむねこんな感じと思っていい。パイプラインの段数が増えると,動作クロックを上げやすくなるのだ。

 なら,ひたすらパイプライン段数を増やせばいいかといえば,パイプライン段数を増やして動作クロックを上げると,副作用も大きい。その最たるものが「パイプラインハザード(Pipeline Hazard)」と呼ばれる現象である。少々難しくなってしまうが,以下の図5に挙げるようなプログラムがあると仮定して説明してみたい。


 図5


 これを,図2に出てきた8段のスーパーパイプラインで実施することを考えてみよう。まず(2)(※図の中では"まる2"だが,機種依存文字になってしまうので,本文では"括弧2"のように表記する)の判断でr30が0でないとき,パイプラインは以下に挙げる図6の左側ようにスムーズに進む。では,r30が0だったらどうなるかというと,図7のようになる。(2)の処理を受けて,(3)が次の命令の飛び先を決めるのは,Execute2のステージだから,スタートしてから8サイクルめになる。この時点でパイプラインには(4)や(5)の命令がすでにロードされており,一方(6)や(7)の命令はロードされていない。この場合パイプラインは9サイクルめに,(4)や(5)の命令をクリアする処理(これを「パイプラインフラッシュ」と呼ぶ)を行い,10サイクルめ以降に改めて(6)や(7)の命令をロードして処理をはじめることになる。結果として,図6では12サイクルで一連の処理が終るのに対し,図7では18サイクルかかる。余分な処理時間が50%分も生じてしまう計算だ。


 図6


 図7

 こうした問題は,段数が増えたりアウトオブオーダーを実装していたりするとさらに深刻で,それだけで数百サイクル消費してしまうケースすらある。加えて,正しい処理先(図7でいうところの(6)や(7))の命令がキャッシュに入っていなかったりすると,その命令をメモリから読み出す必要が出てくるため,遅延は数千サイクルに達しても不思議ではない。  これを一般に,「分岐」によるペナルティという。分岐というのは,今回の例でいうと(3)にあたる処理のこと。(3)で,処理の流れは文字通り2系統に分岐する。どちらに行くのかは条件次第(今回の例ならr30というレジスタの値次第)だから,あらかじめこれを判断しておくのは不可能だ。だから「例えば(3)の次は(4)・(5)と行くはずだ」と思い込んでいて,実は(4)に行かず(6)に飛んだりすると,図7のようなパイプラインハザードが起こるわけである。
 こうした分岐によるペナルティは,とくに最近のCPUでは無視できない。実際,処理時間全体のうちの30%強が分岐ミスのリカバリー,1割強がメモリアクセス待ちに費やされ,純粋にCPUが処理に費やす時間は50%そこそこ,などといった数字もあるほどだからだ。

 以上については,かなり難易度が高いので,またメイドさんにお出まし願おう。邸宅でちょっとしたパーティーが開かれるとする。そこで執事はメイドさんを大量動員して,料理の準備を進めるわけだ。品数も多いので,買出し・下ごしらえ・調理・配膳と分担して,それぞれ何人かのメイドさんを割り当てて作業を行っている。
 さて,食前酒やスープに続いて前菜の処理に取りかかったあたりで,初めて「出席者がベジタリアン集団だった」なんてことが分かったりすると,大騒ぎになるのは目に見えている。とりあえず作りかけの前菜(や,場合によっては食前酒,スープ)を賄い飯にするといった程度で済めば幸せで,ステーキやら鳥料理の下ごしらえは全部無駄になるだろうし,そのベジタリアンが「チーズやバター・卵も駄目」だったりすると,メニュー自体を全部考え直す必要があるかもしれない。こうなると,そもそも買い込んでおいた食材では料理を出せないかもしれないから,急遽メニューを決め直して,買出しを急がないといけない。
 これは小規模のパーティなら「ちょっとしたトラブル」のレベルだが,メイドさん数十人とか数百人とかで準備してきたパーティとなると「大惨事」である。分岐ミスというのはこの場合「メニューの判断ミス」なので,「んなもん事前に調べておけ馬鹿者」とご主人様に怒られるわけだが,CPUがやっかいなのは,これを事前には調べられない点にある。可能なのは「前回はこんな感じのメニューで好評だったから,今回はこれで行こう」と"予測"することだけ。したがって,大惨事を引き起こさないように「どこまで精密に予測するか」が大変重要になるわけだ。

 話を戻すと,こうした大規模な分岐ミスを起こさないよう,分岐命令に関しては「それはどこに分岐するか」を予測して,分岐ミスを減らそうという仕組みが用意されている。この分岐予測のメカニズムは色々あり,単純に「直前の分岐がどちらに向かったか記憶している」レベルのものから,ループ制御(ある条件を満たすまでプログラムの一部を繰り返し実行すること)などを動的に解釈して予測するもの,過去の分岐履歴をずっと記録して判断するものなども存在する。また,分岐ミスしたときにどうやってリカバリを高速化するか,という観点での強化も行われており,これもさまざまな形で実装されている。極端な例だと,(本誌読者にはあまり関係のない)「Itenium」(アイテニウム)というサーバー向けCPUでは,図5の(3)において,分岐方向の結果が出る前に(4)(5)と(6)(7)の両方をパイプラインに乗せておき,間違ったほうを捨てるという強烈な仕様となっている。

  • 1.CPUは,PC内において,グラフィックスカード,ゲーム内プレイヤーキャラクターの動作などに指示を出せる唯一のハードウェアである。
  • 2.「Hz」で表記される動作クロックは,1秒間に何回処理を行えるかを示すもの。
  • 3.主なCPUの高速化手段としては,各ステージを独立して実行できるようにする「パイプライン」「スーパーパイプライン」,並行して実行できる処理を同時に行わせる「スーパースカラ」(と,それに関連する「命令変換」&「アウトオブオーダー実行」)がある。
  • 4.パイプライン段数が増えると,動作クロックは上がりやすくなるが,分岐ミスによる処理の遅延が生じやすくなる問題があり,最近のCPUではこの対策に力が入れられている。
  • 5.要するに,CPUの性能(速さ)を決定する要素は複数あり,動作クロックはその一要素でしかない。動作クロックが高いCPU=速いCPUという図式は,必ずしも成り立たない。

 第2回では,CPUの周辺知識や,2005年秋におけるCPUの最新トレンドを押さえてみることにしよう。