87726f76bf22892ff6eb07d800b85f90-150x150

グーグル、アップルを巻き込んだスマホ大変革が2015年に起こる根拠(3/7)

  • このエントリーをはてなブックマークに追加

by [2013年8月13日]


第1回目と第2回目では半導体製造と回路設計の両面から、プロセッサの高速化技術を見てきました。第3回目では高速化の障害となる問題について扱います。

第1回 「小さくすれば速くて節電に」 はこちら
第2回 「CPU高速化の秘密」 はこちら
第4回 「速度が出せないなら物量で解決だ」 はこちら
第5回 「64ビット化で大容量メモリを」 はこちら
第6回 「来たるべきプロセッサ」 はこちら
第7回 「未来のプロセッサのもたらすもの」 はこちら

超多段パイプラインは止まるとかなり悲惨

さて、Pentium 4やXeonプロセッサに採用され、その動作クロック周波数の大幅引き上げに大きく貢献した、「ハイパーパイプライン」ことインテルNetBurstアーキテクチャの超多段パイプライン技術ですが、この技術を採用したプロセッサには、一つ大きな問題がありました。

それは「これまでのプロセッサと比べ、動作クロック周波数が大きく上がった割に明らかに実効性能の伸びが悪い」というものです。

実際、筆者も3.2GHz駆動で大容量の3次キャッシュメモリまで内蔵したIntel Xeonプロセッサ(Prestonia-2M:NetBurstアーキテクチャ準拠)を2基搭載したマシンを使用していたのですが、2.4GHz駆動かつ2次キャッシュメモリまでしか持たないAMD Opteron 250(K8アーキテクチャ準拠)を2基搭載したマシンに処理能力でほぼ完敗となったのを見て、絶句した記憶があります。

これは、パイプライン処理の極端な多段化には致命的な弱点が大きく分けて3つあり、NetBurstアークテクチャを採用したプロセッサでは様々な対策を施してもなお、それらの弱点が完全には覆い隠せなかったためです。

超多段パイプラインを止めずに動作させるのは難しい

まず、パイプライン処理の場合、複数の命令が順番に、かつ並行して処理されてゆく訳ですが、この場合、ある命令を実行する際に、先行して実行されている命令の計算結果がメモリなりレジスタなりに書き込まれる前にそのメモリあるいはレジスタを読み込んでしまう、あるいは先行命令がメモリを参照する前に後続命令がメモリに計算結果を書き込んでしまうために、いずれも正しい結果が得られなくなるという障害が発生し得る、という問題があります。

前者は「RAW(Read After Write)ハザード」、後者は「WAR(Write After Read)ハザード」と言い、さらに前後の命令が入れ替わって同じメモリやレジスタに計算結果を書き込むため上書きされて起きる「WAW(Write After Write)ハザード」もあります。

次に、パイプライン処理ではプロセッサ内部での演算ユニットなどの利用効率が大きく向上しますが、その反面、1つしかないユニットを複数の命令が同時に利用しようとする、ハードウェアリソース競合の問題もあります。この現象が起きた場合、競合した各命令はそのユニットが利用できるまで順番待ちとなるため、この場合もまたパイプラインが正しく維持できなくなります。

また、条件分岐、つまり「もし計算式の出力結果が0の場合は処理1を、1の場合は処理2を実行する」といった条件に応じて処理内容が変化するようなプログラムを実行する場合、条件分岐が行われた後にどちらの処理が行われるかが確定していないため、以後のパイプラインへの命令の投入が行えなくなります。

つまり条件分岐命令が含まれる場合、パイプラインは機能せず、漫然と命令を実行する逐次処理並みの速度でしかプロセッサが動作しなくなってしまう、「パイプラインハザード(Pipeline hazard)(※1)」という現象が起きます。このため、特にパイプラインの段数の多いプロセッサではこれらのハザードにより、致命的な打撃を受けることになります。

実際にもNetBurstアーキテクチャのプロセッサの場合、パイプラインを複数束ねて使用することで高速化するスーパースケーラ技術を併用していたため、これら3つの問題は高頻度で発生し、かなり深刻な問題となったのです。もちろん、いずれの問題についても一応は対策が講じられていたのですが、極端に多段化したNetBurstアーキテクチャのプロセッサではそれでは不十分でした。

先に挙げたNetBurstアーキテクチャのXeonが、それも大容量の3次キャッシュメモリを搭載してメモリアクセス性能を引き上げたモデルが、動作クロック周波数だけなら25パーセントも低いK8アーキテクチャのOpteronに負ける程度の性能しか出なかったのは、正にこれら3つの問題の複合によるものだったのです。

  • (※1)パイプラインハザード:以下の三つのハザードにに分類される。異なるステージで、同一の資源(演算器など)を使おうとして起こる「構造ハザード」。複数の命令が入り乱れて処理されるため、演算結果の書き込みや読み出しが、プログラマが機械語で意図した順序とは前後してしまい、期待と異なった結果になったために起こる「データハザード」。分岐命令が未だパイプラインのなかにあり、プログラムカウンタが飛び先番地に設定される前に、次々と後続の命令を呼んでしまうために起こる「制御ハザード」。
  • 回避の難しいRAW・WAR・WAWハザード

    これら3つの問題の内、RAW・WAR・WAWハザードは、確実に解消しなければプロセッサの動作が正しく成り立たなくなるため、特に重大かつ深刻です。

    この問題については、パイプラインの前後の命令間のメモリアクセスの依存関係を監視して、RAW・WAR・WAWハザードが起きた際にパイプラインを止めてでも矛盾が生じない=期待されない結果とならないようにする「パイプライン・インターロック(Pipeline interlock)(※2)」という機構の搭載が行われます。

    しかし、このパイプライン・インターロックはパイプライン処理を強制的に止めて矛盾の解消を図る力業の処理であるため、ハザード発生時におけるプロセッサ全体のパフォーマンス低下は極めて深刻です。

    そのため、NetBurstアーキテクチャをはじめとする超多段パイプラインを実装するプロセッサでは、一般に前の命令の実行途中であっても次の命令が必要とするレジスタの内容を次の命令に参照可能とする、レジスタフォワーディングといった技術が回避策として導入されています。もっとも、この技術は前の命令の処理において、次の命令が必要とする結果が演算終了していないと当然に参照できず利用できないため、根本的にはインターロックを回避できない(参照可能となるまでパイプライン処理が止まってしまう)、ということになります。

  • (※2)パイプラインインターロック:データ依存関係を確認し、ハザードを検出する機構。命令を正しくつなぎ合わせ、正しい結果を保証する機能を持つ。
  • 空命令でインターロックを防いでも効率は上がらない

    なお、パイプライン・インターロック回避のために、「何もしない(NOP:no operation)」という「処理に時間を要するが処理の結果としては何の動作も行わない、いわゆる空命令を問題が出ると判断された命令の間に挿入し、わざとパイプラインで実行させてパイプライン・インターロックが回避できるようになるまで時間稼ぎをする、というテクニックもしばしば利用されるのですが、これとてパイプライン処理を無理に空回りさせるわけですから、結果的にはパイプライン・インターロックが機能した場合と同程度のパフォーマンスしか得られません。

    実際、このNOP命令でパイプラインを充填する策を多用せざるを得なかったNetBurstアーキテクチャのプロセッサは、「確かに高クロック周波数で動作するが、パイプラインはスカスカで実効性能が出ない」(※この対策として、HyperThreadingという遊んでいる内部処理ユニットを活用するためのマルチスレッド処理技術が開発・搭載されていて、一定の効果を発揮したのですが、それでさえパイプラインを充分効率よく動かすには至りませんでした)という陰口をあちこちで叩かれる有様でした。

    力ずくだが回避策があるパイプライン・ハザード

    一方、RAW・WAR・WAWハザードとは異なり条件分岐が原因で起きるパイプライン・ハザードの場合は、根本的では無いにせよ、ある程度までは回避策が存在しています。

    まず、一般に行われるのは、分岐予測を行い、分岐先の処理の内、選択される可能性の高い方を選んで事前にパイプラインに投入して予行的に処理させておく、投機実行あるいは投機的実行(speculative execution)と呼ばれる技術です。

    元々、選択肢の判定が0か1の2値で行われる条件分岐命令では、乱暴に言って5割の予測成功が保証されていることになるため、分岐予測+投機実行を行った場合、行わなければ100パーセントの確率でパイプライン・ハザードが起きるのが、少なくとも50パーセントの確率にまで発生頻度を低下させることができるため、これだけでもかなりの性能向上が得られます。

    さらに、この確率は100パーセントに近ければ近いほどプロセッサの実効性能が上がることになるため、各メーカーは次ライン予測や2レベル適応型分岐予測、局所分岐予測、広域分岐予測、結合分岐予測など、文字通り知恵の限りを尽くして条件分岐予測精度を引き上げるためのアルゴリズムの開発に力を注いでいます。

    95パーセント以上の予測精度の実用化は難しい

    もっとも、この条件分岐予測、どれほど知恵を尽くしても98パーセント以上の予測精度を得ることは非常に難しく、またそれ以上の精度を実現する予測機構の実装に必要な回路の規模は、プロセッサの規模に比して途方もなく大きなものとなってしまいます。

    そのため、一般的な多段パイプライン処理を行うCPUでは、分岐予測の回路規模増大とそれによる予測精度向上と、それ以外の部分の強化による性能向上を天秤にかけて、予測精度を90パーセントから95パーセントの間の適当なところでバランスさせるケースが大半を占めています。

    実際にも、分岐予測回路に割り当てられるトランジスタ数が制限されるため、95パーセント以上の高い予測精度を実現するのは、既に述べたように超多段パイプラインを用いたスーパースケーラ技術を採用し、分岐予測のミスによるペナルティがあまりに巨大なNetBurstアーキテクチャのプロセッサのような差し迫った理由のあるケースや、半導体製造プロセスのシュリンクで他社に先行していて、この機能に割り当てできるだけトランジスタ数に余裕のある最近のインテル製CPUなどに限られているようです。

    条件分岐予測ミスはどこかで必ず起きる

    以上より、少なくともプロセッサ動作中に条件分岐命令について投機実行を行う場合、最良の場合でも2パーセントから10パーセント程度の予測ミスとこれに伴うパイプライン・ハザードの発生が「保証」されている、ということになります。

    もちろん、予測精度100パーセントで条件分岐先を読み切る、というのは百発百中の占いのようなものであっておよそ現実的ではなく、また実用上多用されるシチュエーションでほぼ100パーセントの予測精度が得られるならそれで充分(※使用頻度の低いシチュエーションで予測が外れてもペナルティはそれほど大きくない)、という見方もあるのですが、ともあれ、予測が外れた場合のことを想定すると、パイプライン・ハザードの対策には別のアプローチも必要となってきます。

    パイプラインを保ったまま条件分岐を可能にする条件実行機能

    この分岐予測問題にARMが出した1つの答えが、「命令そのものに条件実行機能を付与する」というアイデアでした。

    これはつまり、パイプライン上で実行される命令の中で条件分岐処理を完結させてしまえば、そもそも複雑な処理を必要とする分岐予測+投機実行は必要なく、パイプライン・ハザードは起きない、という考えに基づくもので、パイプライン処理がパソコンやマイコンなどで用いるプロセッサに採用されるようになった出現した後でアーキテクチャの整備が進んだARMならではの、いわば後出しじゃんけん的な対応策(※パイプライン処理の導入が始まるより前から存在していた、インテルのx86アーキテクチャのような古くて複雑なCPUアーキテクチャの命令セットに、こうした機能を後から追加するのはソフトウェア互換性確保や命令コードの割り当ての観点から非常に困難です)です。

    ただし、ARM系のプロセッサであっても、プログラムの構成上こうした条件実行機能では対応できないタイプの条件分岐も存在するため、それらについては他のプロセッサと同様の状況となります。

    物量作戦で解決可能なハードウェアリソース競合

    最後のハードウェアリソース競合については、必要なトランジスタ数が増える=シリコンチップのサイズが大型化するのを承知の上で、利用が重複して競合状態となるユニットを増設して競合が起きないようにするのが、根本的な解決策となります。

    もちろん、利用頻度の極めて低いユニットを複数搭載するのはクレバーな解決策ではないのですが、命令の実行状況やユニットの利用頻度を統計学的に分析して、使用頻度、つまりニーズに応じて適切にユニット数を増やせば、かなり効果的な性能向上が実現できることになります。

    半導体製造プロセスをシュリンクすれば、その分だけ等価回路を組んだ場合のチップサイズが小さくなりますから、シュリンク前と同程度のサイズを許容できるのであれば、その縮小された面積を演算ユニットなどの増設に振り向けることができるようになります。

    事実、現在一般に量産・市販されているCPUの大半は半導体製造プロセスの縮小の度にこうしたユニットの利用頻度を検討の上で複数搭載の可否が検討されており、改良新型機種の発表時に、そうした搭載ユニット数の増強がセールスポイント、あるいは他の機種との差別化要因として挙げられることも珍しくありません。過去の製造プロセスの縮小が進んでx86系プロセッサで高速化競争が激化した時期には、「○命令同時実行」といった形で、どのような命令を実行しても確実に実行ユニットの利用競合を起こさずにパイプライン処理が行える本数を誇示する事が行われていて、この時期には内部ユニット数(とCPUを構成する回路のトランジスタ数)が急増し、それに応じてプロセッサ性能が劇的に向上した、という経緯があります。

    ユニット共用は性能向上には諸刃の剣となる

    AMD FXシリーズ
    AMDの一般パソコン向けCPUとしてはラインナップで最上位に位置づけられているシリーズ。CPUコア数が4コア・6コア・8コアの製品が存在する。2コア単位で使用頻度の低い演算ユニットなどを共用とすることで、比較的少ないトランジスタ数で最大8コア構成を実現したが、行き過ぎた共用化が足を引っ張って性能が今ひとつ発揮できない、という問題を抱えている。

    トランジスタ数の増大を無視すればリソース競合が防げる、ということは、言い換えれば使用頻度が低く競合が起きにくいユニットは搭載数を減らして最小限としても構わない、ということでもあります。そのため、チップサイズが限られる=シリコンチップの上に形成できるトランジスタ数が厳しく制限される場合には、使われる機会の少ないユニットは、そのユニットを利用する命令を実行した時の性能低下が大きいことを承知の上で、あえて削減される、あるいは複数のパイプラインで共用とするケースがあり、更に極端な例では、AMDの「Bulldozer」と呼ばれるCPUアーキテクチャを採用したプロセッサのように、1CPUコア内だけではなく2つの独立したCPUコアの間で使用頻度の低いユニットを共用化することで、コンパクトなマルチコアCPUを実現しているケースがあります。

    もっとも、こうしたユニット共用化は少ないトランジスタ数でより多くのCPUコアを搭載したいサーバ用CPUなどでは有効な手段ですが、当然ながらパイプラインの高速処理には大きな障害となるわけで、上述のAMD FXプロセッサを筆頭に、共用部分を利用する命令が実行されたとたんに性能が低下するケースが珍しくありません。

    (以下、第4回 「速度が出せないなら物量で解決だ」に続く)

    コメントは受け付けていません。

    PageTopへ