後藤弘茂のWeekly海外ニュース

64bitは苦手なCore Microarchitecture




●EM64T Long Modeではマイクロアーキテクチャ上の制約がある

 PCアプリケーションでは圧倒的に優れたパフォーマンスを誇るIntelの「Core Microarchitecture(Core MA)」。消費電力も低く、モバイルでも強力なアーキテクチャだ。Core MAは、Intelの切り札となりそうだが、完璧というわけではない。影もある。それは64bit時のパフォーマンスだ。

 Core MAの場合、マイクロアーキテクチャ上の理由で、64bit時には性能が32bit時より落ちてしまう可能性が高い。少なくとも、同じステップ数のコードを走らせるなら、理論上は64bitの方が性能が落ちてしまう。もちろん、ベースのパフォーマンスが高いため、あくまでも32bit時と比較した場合の話だ。

 Core MAのこの問題は、現在のCore MAマイクロアーキテクチャの実装上の問題であるが、根源的にはx86/x64命令セットアーキテクチャの制約が影響している。

 どうしてCore MAの64bit時の性能が問題になるのか。

Optimizing for Instruction Quene - I

 まず、現在のCore MAの実装では、64bit OSの動作モードである「EM64T Long Mode」の時に、Core MAの売り物である「Macro-Fusion」が効かない。Macro-Fusionは、2個のx86命令を1個のCPU内部命令(uOPs)に統合するテクニック。Core MAのパフォーマンスを押し上げているキーテクノロジの1つだが、それが64bitでは働かない。

 Macro-Fusionを使うと、命令帯域を1スロット分増やし、さらに、分岐の実行を1サイクル速めることができる。分岐の多い汎用コードでは、パフォーマンス面では有効な手法だ。しかし、EM64T Long Mode時にはMacro-Fusionはサポートされないため、この利点は得られないことになる。


Optimizing for Instruction Fetch and PreDecode - III

 もう1つの問題は、EM64Tの「REX」プリフィックスを使うと、Core MAでは命令プリデコードの効率が落ちる可能性があること。

 x64と総称されるEM64TとAMD64の両64bitアーキテクチャでは、レジスタ空間を増やしている。汎用レジスタは32bitから64bitになると同時に、8本から16本に。SSEレジスタも8本から16本になった。しかし、追加されたレジスタへのアクセスのために、REXと呼ぶ命令プリフィックスをオペコードの前につけている。EM64Tの利点をフルに活かして性能を上げようとすると、REXプリフィックスが命令に加わることになる。

 しかし、現在のCore MAの実装では、REXプリフィックスを使うと性能が落ちる可能性があるという。キャッシュからの命令フェッチ幅の制約があるため、REXで命令長が伸びる分、プリデコードの効率が落ちる。その結果、命令デコードの効率も下がる可能性がある。

 こうした、命令フェッチ&デコード段階での制約は、現在のCore MAの64bit性能をある程度損なう可能性がある。Core MA自体のパフォーマンスは高いものの、アーキテクチャを見る限り、理論上、64bit時には32bit時ほどの性能は達成できないことになる。

●Intelが64bitを強調しなくなった理由

 こうした背景を見ると、IntelがCore MAでは、あまり64bitを強調しなくなった理由がよくわかる。Intelは、一時は、AMD64への対抗で、NetBurstでのEM64Tを前面に押し出した。しかし、最近はあまりIntel側からは64bitを強調しなくなっている。32bitの性能に最適化された今の実装で、64bitを強調するのは得策ではないと判断したのかもしれない。

 もっとも、Microsoftも、当初の予想と異なって「Windows Vista」ではあまり64bitを前面には押し出していないからバランスは取れているとも言える。MicrosoftはIntelのマイクロアーキテクチャの情報をかなり早い段階で手に入れているはずで、Core MAの弱点を知ったからこそ64bitをトーンダウンした可能性もある。

 対AMDでは、64bit性能が決定的な要因とならないPCサイドでは、この件は当面は大きな障害にならない可能性が高い。しかし、64bitが大きなドライブ要因になっているx86サーバーでは、この問題がIntelにとって不利に影響する可能性はある。

 ただし、Intelもマイクロアーキテクチャの改良を続けているため、次の世代では64bit時と32bit時の性能差がない実装になる可能性もある。

 この件が示唆することは、Core MAのEM64Tへの対応も、それほど完全ではないということだ。NetBurstのPrescott(プレスコット)でのEM64Tサポートは、32bitの整数演算ユニットを2パイプ設けることで実装している。それに対して、Core MAはもっとスマートな実装をされると予想されていた。しかし、今のCore MAも64bitでは制約があるのは、Core MAの開発時期とEM64Tのスペックの確定時期に関係があるのかもしれない。

 もともと、Intelのオリジナルの64bit拡張「Yamhill(ヤムヒル)」は、レジスタ拡張を含まない、アドレス拡張だけのテクノロジだったと言われている。それが、現在のEM64T(Clackamas:クラカマス)に変わった2003年後半の段階で、AMD64互換となりレジスタ拡張が入ったと言われている。CPU開発サイクルは4〜5年なので、時期的には、その時点ではCore MAの上流設計は終わり、すでに物理設計が進んでいたはず。EM64Tとのすり合わせが途中から行なわれたとしても不思議ではない。

●Core MAの要となる命令フェッチ&プリデコード

 Core MAのEM64Tの問題は、Core MAの命令フェッチ&デコードの部分に由来する。Core MA全体で、Intelがもっとも苦労したと思われるのが、この命令フェッチ&デコードの部分だ。ここでは、命令キャッシュからx86命令を読み出し、内部命令(uOPs)にデコードする。流れとしては、命令フェッチ→命令プリデコード→命令キュー→命令デコードとなる。特に重要なのは、フェッチとプリデコードだ。

 Core MAは、4個のx86命令を同時デコードして実行ユニット群に発行できる、広いパイプライン帯域を誇る。しかし、CISC(Complex Instruction Set Computer)であるx86命令セットアーキテクチャ(ISA)の場合、4命令をデコーダにコンスタントに供給するのは容易ではない。だが、デコーダに十分に命令を供給できないと、せっかくの広い内部パイプラインも、実行する命令がなく遊んでしまうことになる。そのため、命令フェッチ&プリデコードは、Core MAの要となるパートだ。

 命令フェッチ&プリデコードのステージについては、これまであまり詳しく説明されて来なかった。しかし、Intelはサーバー向けのCore MA CPU「Xeon 51xx(Woodcrest:ウッドクレスト)」の発表後に、その概要を明かし始めた。日本で6月に行なわれた「インテルHPCデベロッパー・カンファレンス」では、コード最適化に関連して、命令フェッチ&デコード部分の概要と、その弱点が説明された。

 下がCore MAのブロックダイアグラムだ。32KBのL1命令キャッシュからフェッチユニット(Instruction Fetch Unit)が16bytes単位のアライメントで命令をフェッチする。それをプリデコーダが処理して命令区分をマーキングする。プリデコーダは最大6個のx86命令を1サイクルで処理できる。プリデコードされた命令は、命令キュー(Instruction Queue)に格納される。キューからはデコーダに最大5命令/サイクルで命令が発行される。命令デコーダは4ユニットで、最大4個の内部命令(uOPs)を1サイクルでアウトプットできる。

Core Architecture Block Diagram
(別ウィンドウで開きます)
PDF版はこちら

IntelのBob Valentine(ボブ・バレンタイン)氏

 命令フェッチ&デコードステージ群の全体の構造としては、上が広くて下が狭い構造になっている。IntelのBob Valentine(ボブ・バレンタイン)氏(Senior Architect, Intel Architecture Group)は「ジョウロのように、入り口をより広くとって、パイプラインに注ぎ込むイメージだ。上にヘッドルームを持たせないと、4個のデコーダに十分に命令を供給できないからだ」と説明する。



●プリデコーダは複雑なx86命令の頭をマーキング

IntelのJeffrey D. Gilbert(ジェフリー・D・ギルバート)氏

 命令キャッシュからフェッチされた16bytesのブロックは、プリデコーダでプロセスされる。「プリデコードは、命令ストリームの中のどこに命令があるのか見つけ出してマーキングする。IA-32/EM64T ISAの命令プリフィックスを見分け、命令を分類してデコーダの『Macro-Fusion』に備える。このマシンでは6命令を1サイクルでマーキングできる」とIntelのJeffrey D. Gilbert(ジェフリー・D・ギルバート)氏(Xeon Processor Architect, Architecture & Planning, Digital Enterprise Group, Intel)はHPCカンファレンスで説明した。


Core MA Fetch and Decode
(別ウィンドウで開きます)
PDF版はこちら

 RISCやIA-64の場合は、命令長が固定または少ない種類に定まっており、命令フォーマットも一定に保たれている。ところが、x86の場合は、命令長は1byteから15bytesとやらたとバリエーションが多い。しかも、命令種類を示すオペコードの前に、プリフィックスがつく場合があるため、命令フォーマットも複雑となっている。CPUには、命令キャッシュから取り込んだ命令ストリームの中で、各命令の頭がどこにあるのかが判別しにくい。

 そのため、命令の切り出しをデコード段階で行なうと、デコードに時間がかかってしまい、効率が落ちてしまう。そのため、Core MAでは、プリデコードのステージで、各命令の頭に境界を示すマークをつけている。Core MAでは、これを「命令長マーキング(Instruction Length Marking)」と呼んでいる。

 プリデコーダは、命令ストリームの中からオペコードとプリフィックス部分を検知し、そこから命令長を判定、次の命令の頭をマーキングする。デコーダには、そのマーキングに従ってx86命令を発行する。マーキングは、それほど珍しい方式ではなく、x86の複雑性を軽減するためによく使われるアプローチだ。

●必ずしも6命令はプリデコードできない

 x86系CPUで、命令のデコード幅を広げる場合、最大の障壁は、この命令長マーキングをいかに速く行なうかという点にある。Core MAの場合、最大6個のx86命令を判別してマーキングできる。

 一方、Core MAの命令デコーダは最大4命令をサイクルでプロセス可能で、Macro-Fusionが成り立つ場合には5命令をプロセスできる。デコーダの帯域は4+ 命令/サイクルとなる。それと比較すると、プリデコーダの最大6命令/サイクルは、一見オーバーキルに見えるがそうではない。それは、プリデコーダが常に6命令をプロセスできるわけではないため、平均のプリデコードレートは、最大値より低くなるからだ。

 Gilbert氏は次のように説明する。

 「1サイクルで16bytesのパケットをフィニッシュする。これは非常に速い。しかし、16bytesの中に、多くの短い命令が含まれている場合と、その逆に長い命令が含まれている場合は、プリデコードが遅くなる」

Optimizing for Instruction Fetch and PreDecode - II

 「もし、16bytesの中に6個以上の命令が含まれていたら、プリデコーダは最初の6命令をプロセスし、残りの命令は次のクロックでプロセスする。例えば、8命令が含まれていた場合は、6命令のプロセスで1クロック、残りの2命令で次のクロック、合計で2サイクルが使われる。そのため、平均のプリデコードレートは4命令/サイクルとなる。

 逆に、16bytesパケットに7bytes長の命令が2個、含まれていた場合。プリデコードレートは2命令/クロック程度にまで落ちてしまう」

 理想的には、16bytesブロックの中に5〜6命令が含まれていてば、1サイクルでプリデコードし、デコーダを4+ 命令/サイクルでフルに稼働させることができる。しかし、6よりも多い命令が含まれている場合は2サイクルかかるし、逆に長い命令で占められてしまうと1サイクルでプロセスできる命令数が落ちてしまう。そのため、平均のプリデコードレートは最大値より落ちてしまう。

 プリデコードのレートが落ちても、デコーダにフィードできるように、プリデコードの最大レートを高く取ってあるわけだ。Core MAでは、プリデコーダの下の命令キューを18段と深くとってあり、プリデコードレートにばらつきがあっても吸収できるようにしている。ジョウロのように、というのはこういう意味だ。

 プログラムによって異なるが、x86コードは、平均だと1命令が3bytes程度と言われているので、16bytesのフェッチブロックにちょうど5から6命令が平均的に収まる計算になる。プリデコードの効率をより上げる方法の1つは、命令フェッチ幅を広げることだが、その場合、分岐で破棄される部分が増えるので、フェッチ効率が悪くなるという。

●オペランドとアドレスのサイズを変えると大きなペナルティ

 こうして見ると、Core MAの命令フェッチ&プリデコードの部分はそれなりにうまく回るように見えるが、そんなに理想的には行かない。プリデコーダの足を引っ張る要素があるからだ。

 その1つは、命令長を変化させる命令プリフィックス「LCP(Length Changing Prefixes)」だ。HPCデベロッパー・カンファレンスでは、Core MAの場合、LCPを挟むと、とたんにプリデコードが遅くなることが説明された。

 オペランドとアドレスのサイズは、CPUの動作モードによってデフォルトの値が決まっている。しかし、x86/x64の場合、プリフィックスでサイズを変えることができる。プリフィックス「66H」ならデフォルト以外のオペランドサイズに、プリフィックス「67H」ならデフォルト以外のアドレスサイズに変更できる。

 現在のCore MAのプリデコーダは、この2種類のプリフィックスを検知すると、そこでLength Decoding Algorithmを変える。問題は、このペナルティがかなり大きいことだという。

 「プリフィックス66Hがあると、プリデコードの際に命令マーキングを行うアルゴリズムを変えなくてはならない。もし、あなた(のコード)がオペレーションの途中でアルゴリズムを変化させると、それは大きな代償をともなう。LCP 66Hプリフィックスを使って、命令がイミディエイトを持つ場合、1から(最大で)6クロックのペナルティとなる。このマシンは、6クロックで24命令を(デコード段階で)プロセスできる。だから、これは代償をともなうプリフィックスとなってしまう。きっと、あなた方は、私が何を推奨するか推測できるだろう。それは、LCPプリフィックスを使うなということだ」

 つまり、Core MAのプリデコーダは、通常は、動作モードでデフォルトとなっているオペランドとアドレスに従って命令長マーキングをしている。そこに、プリフィックス66Hを使ったコードが来ると、そこで命令長のマーキングのアルゴリズムを切り替えなければならない。その時に、アルゴリズムの切り替えだけで1サイクルを費やしてしまう。そのため、66Hが続くと、パフォーマンスがガクっと落ちる可能性がある。これは67Hでも同じようだ。

●命令長を長くするREXプリフィックスも問題

 命令プリフィックスは、x86の頭の痛い問題の筆頭の1つだ。そして、冒頭で触れたように、64bitモードEM64TのREXプリフィックスも、プリデコードを遅くする原因になる。

 「EM64TのREXプリフィックスについても指摘しておくべきだろう。REXでは命令サイズが変化するが、Core MAのプリデコーダは、REXプリフィックスを識別できる程度にはスマートだ。だから、REXはLCPではない。命令長マーキングアルゴリズムのチェンジは引き起こさないし、そのためのペナルティもない。

 だが、これも指摘しておきたい。もし、あなたが(コーディングする際に)EM64Tの16本レジスタが必要なく、8本のレジスタでのオペレーションにフォーカスできるなら、REXプリフィックスを使う必要はない。なぜREXプリフィックスを使わない方がいいのか。それはREXが命令長を長くするからだ。命令が長くなるとプリデコードが遅くなる」

 EM64Tの追加の8本のレジスタを使うと、それだけでプリフィックスの分、命令長が1byteずつ余計に長くなってしまう。そのため、16bytesと限られたフェッチブロックに収められる命令数が余計に減ってしまう。だからプリデコーダがスローダウンする可能性があるというわけだ。LCPプリフィックスほど致命的ではないが、やはり問題だとGilbert氏は説明する。

 しかし、x64でパフォーマンスを上げるためには、せっかく増えたレジスタを使わなければ効果が薄い。より広いレジスタ空間を使えば、命令ステップ数を減らし、キャッシュアクセスを軽減できるため、パフォーマンスを上げることができる。REXを使わない方がいいというのは、かなり問題がある。

 実際にx64に最適化されたコードを走らせると、REXでレジスタを使うことで命令数が減るため、Core MAのペナルティは相殺されるかもしれない。しかし、全く同じステップ数のコードを走らせるなら、理論上は64bitの方が性能が落ちてしまう。

●複雑なx86 ISAがCore MAの足を引っ張る

 こうして見ると、Core MAは命令フェッチ&プリデコードの段階で、かなり苦労していることがわかる。しかし、根本的な部分をよく見ると、これはCore MAの実装上の問題というより、x86 ISA自体が大きなハードルであることを意味していることがわかる。命令長にバリエーションがあり、プリフィックスで命令フォーマットが複雑になりすぎているから、こうした問題が発生しているように見える。その背景には、x86が積み重ねに積み重ねを続けてきたCISC命令セットだからという事情がある。

 以前の記事で、Core MAの利点は、パイプラインの中にCISCのいい点を取り込んだことだと説明した。Core MAのuOPsはRISC(Reduced Instruction Set Computer)風ではなく、「シンプルなCISC」(Valentine氏)となっている。そのため、RISC風uOPsだったNetBurstより、実質的により多くの命令を実行できるようになった。しかし、Core MAのuOPsは、固定フォーマットで命令長もおそらく固定かバリエーションが少ないはず。そのため、x86が抱えるような、デコードの難点はない。

 それに対して、x86命令をフェッチ&デコードするフロントの部分は、CISCの呪縛に捕らわれている。命令の判別とデコードが難しく、デコード段階での並列化が難しいという、CISCの難点は、Core MAにも重くのしかかっている。

 この問題は、パイプラインのILP(Instruction-level Parallelism)を高めようとすればするほど大きくなる。デコーダを4ユニットに増やしたら、それに見合うだけの命令長マーキングをしなければならない。Core MAでは、その負担がいかに大きいかが明らかになった。

 NetBurstでは、この問題を、うまく隠蔽していた。NetBurstでは、x86命令デコーダは、命令キャッシュであるトレースキャッシュよりも前にあった。トレースキャッシュは、デコードした後のuOPsを格納していたため、トレースキャッシュにヒットする限りは命令デコードはしなくてすむ。そのため、NetBurstでは命令デコーダは1ユニットで回していた。Core MAのように、多くの命令をマーキングする必要がなかった。

 しかし、uOPsをRISC風に処理しやすい固定長にすると、必然的にx86よりも命令長が長くなってしまう。そのため、同じキャッシュ効率を得ようとすると、キャッシュサイズが大きくなってしまう。その分、ダイサイズ(半導体本体の面積)と消費電力を食い、レイテンシを抑えるための工夫が必要となる。また、デコード自体は遅いため、命令の局在性に依存する率が高くなる。

 Core MAは、こうしたトレードオフを考慮して、現在のアーキテクチャを取ったと推測される。複雑なx86命令でいかにILPを高めるかという難問にチャレンジした結果、今の段階では、まだアラがあるわけだ。

□関連記事
【6月26日】【後藤】「Core Microarchitecture」の速さの秘密は“CISCの美”
http://pc.watch.impress.co.jp/docs/2006/0626/kaigai285.htm
【3月11日】【後藤】明瞭になった「Core Microarchitecture」の全貌
http://pc.watch.impress.co.jp/docs/2006/0311/kaigai249.htm

バックナンバー

(2006年7月18日)

[Reported by 後藤 弘茂(Hiroshige Goto)]


【PC Watchホームページ】


PC Watch編集部 pc-watch-info@impress.co.jp ご質問に対して、個別にご回答はいたしません

Copyright (c) 2006 Impress Watch Corporation, an Impress Group company. All rights reserved.