図7●64ビットWindowsは,WOW64上に32ビットWindowsのすべてのシステムDLLを載せている
図7●64ビットWindowsは,WOW64上に32ビットWindowsのすべてのシステムDLLを載せている
[画像のクリックで拡大表示]
表2●x64アーキテクチャのCPUが備える動作モード
表2●x64アーキテクチャのCPUが備える動作モード
[画像のクリックで拡大表示]
図8●x64アーキテクチャのCPUが備えるレジスタ・セット<br>64ビット・モードでのみ,拡張されたレジスタを利用できる
図8●x64アーキテクチャのCPUが備えるレジスタ・セット<br>64ビット・モードでのみ,拡張されたレジスタを利用できる
[画像のクリックで拡大表示]
図9●ベンチマーク・テストPanorama Factory&lt;br&gt;64ビット・アプリケーションの場合は21枚の写真をつなげて1枚のパノラマ写真を作れた(上)。32ビット・アプリケーションではメモリー不足で9枚までしか処理できなかった(下)。使用したシステムは,CPUがAMD Athlon 64 FX-55。主記憶容量は1Gバイトである。
図9●ベンチマーク・テストPanorama Factory<br>64ビット・アプリケーションの場合は21枚の写真をつなげて1枚のパノラマ写真を作れた(上)。32ビット・アプリケーションではメモリー不足で9枚までしか処理できなかった(下)。使用したシステムは,CPUがAMD Athlon 64 FX-55。主記憶容量は1Gバイトである。
[画像のクリックで拡大表示]
図10●64ビットWindowsで32ビット・アプリケーションを動かすと,4Gバイトのメモリーすべてをユーザー領域に使える
図10●64ビットWindowsで32ビット・アプリケーションを動かすと,4Gバイトのメモリーすべてをユーザー領域に使える
[画像のクリックで拡大表示]

Part2◆x64の巧みさ
32ビットの実行性能がよい秘密

 Windows XP Professional x64 EditionおよびWindows Server 2003 x64 Editionは,既存の32ビット・アプリケーションを,前述のようにWOW64(Windows on Windows 64)と呼ぶ仕組みで動かしている。WOW64は,Windows 2000やWindows XPなどのNTカーネルを採用した32ビットWindowsが16ビット・アプリケーションを動かすために備えているWOW(Windows on Windows)と,その概念はほぼ同じだが実現手法は多少異なる。

 WOWは,既存の16ビット・アプリケーションを32ビットWindowsで動作させるための仮想DOSマシン(NTVDM)とWindows 3.1相当のモジュールで構成されている。つまり,32ビットWindows上に仮想的なハードウエアを作り出し,その上でWindows 3.1相当を動かしているわけだ。Windows on Windowsという文字通り,32ビットWindows上に16ビットWindowsを実装していることになる。

 それに対してWOW64は,64ビットWindows上に32ビットWindowsを実装している点はWOWに似ているが,32ビットのカーネルAPIのエミュレーションによる実装だという点が異なる。WOWのように,32ビット・アプリケーションが呼び出すWin32 APIは,x64 Editionが備える32ビットのDLLで処理される。だが,カーネル・モードでの処理(システム・コール)が必要になったときに,WOW64が32ビットWindowsのカーネルのふりをする。すなわち,WOW64が32ビットの仮想アドレス空間から64ビットの仮想アドレス空間への変換などの処理をし,64ビットのシステム・コールを発行する(図7[拡大表示])。このような仕組みによって32ビット・アプリケーションが実行される点は,IPF(Itaniumプロセッサ・ファミリ)用の64-Bit Editionと同じである。

 x64 EditionがIPF版と異なるのは,それが動作するCPUが既存の32ビット・コードにネイティブ対応している点である。IPFはx86と,CPUが直接実行するマシン語命令に互換性がない。そこでIPF版の64ビットWindowsでは,WOW64でマシン語命令を変換して32ビット・アプリケーションを動かす。ただし,これではオーバーヘッドが大きく,性能が出ないので,現在ではIA-32 Execution Layerと呼ぶドライバを使って,x86命令をIPF命令に変換し,より高速に動かすようにしている。だが,変換が必要なことには変わりないので32ビット・マシンで動かしたときに比べて動作速度が大幅に落ちてしまう。

 x64 Editionが動作するCPUの64ビット命令は,32ビット命令と互換性がある。x64 EditionのWindowsは,アーキテクチャ上IPF版との互換性を保つため,WOW64でx86(32ビット)命令をx64(64ビット)命令に変換したうえで処理する実装になっている。しかし,ほとんどのx64命令はx86と,マシン語の処理内容を示すオペコードが共通なので,オーバーヘッドが最小限で済む。処理内容にもよるが,同じハードウエアで比べると,32ビットWindowsで動かしたときと同等の速度で動作可能だ。さらにx64 EditionのOS内部の処理性能が32ビットWindowsに比べて向上しているので,32ビット・アプリケーションでさえ,場合によっては32ビットWindowsで動かしたときよりも速くなる可能性がある。ここでは,x64対応CPUやWOW64の仕組みを解説し,x64 Editionでアプリケーションの実行性能がよい秘密を解き明かしていこう。

x86と完全な互換性を備える

 まずは,x64 Editionが動作するCPUについて説明する。

 x64 Editionは,AMD(Advanced Micro Devices)のOpteronやAthlon 64といったAMD64アーキテクチャに対応したCPUと,Intel Extended Memory 64 Technology(EM64T)に対応したXeonとPentium 4の一部のCPUで動作する。これら2つのアーキテクチャは,細かい部分に微妙な違いはあるものの,基本的に互換性があり,Microsoftは2つを合わせてx64アーキテクチャと呼んでいる。ここでもAMD64とEM64Tをまとめてx64アーキテクチャと呼ぶことにする。

 x64アーキテクチャは,x86アーキテクチャとの完全なソフトウエア互換性を保ちつつ,64ビットに拡張されたアーキテクチャである。大きく分けて,2つの動作モードを備える(表2[拡大表示])。

 1つは,「ロング・モード」(AMD64の場合)または「IA-32eモード」(EM64Tの場合)と呼ぶ64ビットに拡張されたモードである。AMD64とEM64Tで名称が異なるが,内容は同じである。ここではロング・モードと呼ぶことにする。ロング・モードを利用するには,64ビットのOSが必要である。

 もう1つは,x86アーキテクチャと全く同じ振る舞いをし,既存の32ビットまたは16ビットOSが動作する「レガシー・モード」である。

64ビット機能には64ビットOSが必要

 ロング・モードには,次の2つのサブモードがある。(1)拡張された64ビットの機能が利用できる「64ビット・モード」と,(2)64ビットOS上で32ビット・アプリケーションを動かすための「互換モード」——である。

 64ビット・モードでは,CPU内にある汎用レジスタが64ビットに拡張され,数が16本に倍増されている。さらにSSE(ストリームSIMD機能拡張)命令セットで利用する128ビット長のXMMレジスタも,16本へと倍増されている(図8[拡大表示])。64ビットに拡張された汎用レジスタのうちRAX~RBPまでの8本は,その下位32ビットだけをこれまでの32ビット・レジスタEAX~EBPとして利用できる。さらにその下位16ビットだけ(AXなど)や,その16ビットの上位8ビット(AHなど)と下位8ビット(ALなど)をそれぞれ単独のレジスタとして利用できる点も,x86と同じである。追加されたR8~R15までの8本の64ビット汎用レジスタは,下位8ビットだけをR8B~R15B,下位16ビットだけをR8W~R15W,下位32ビットだけをR8D~R15Dとしても扱える。なお,R8D~R15Dとしてアクセスしたときは上位32ビットが0でクリアされる。

 レジスタ数が倍増されたことは,処理性能の向上に寄与するはずだ。x86アーキテクチャの汎用レジスタは8本しかない。Pentium 4(128本)のように,最近は内部により多くのレジスタを備えるCPUもあるが,命令セット上は8本しか使えない。そのため,いくら最適化しても処理内容によっては,すべての変数をx86命令レベルではレジスタに格納できないことがある。そのような場合には,そのレジスタを別の処理のために空ける必要が生じ,レジスタ内の値をメモリーに待避することになる。この処理は,メモリーへのアクセスを伴うので,処理速度の低下につながる。

 より多くの汎用レジスタを使えるということは,値の待避のためのムダなメモリー・アクセスを極力減らせることを意味する。つまり処理が速くなる。さらにx64 Editionの呼び出し規約では,関数呼び出し時の引数の受け渡しに,第4引数まではレジスタで渡すことになっている。この点でもメモリー・アクセスが減ることになるので,すべての引数をスタック(メモリー)で渡す32ビットWindowsと比べて,処理性能が向上するはずだ。

64ビット化で大幅な高速化が可能に

 汎用レジスタのデータ幅が64ビットになったことで,1回の演算の処理単位が2倍になった。これも処理性能の向上に貢献する。

 「一般的なビジネス・アプリケーションなどの処理に必要なデータの大きさは32ビットで,64ビット整数を必要とする処理はほとんどない。つまり64ビット化したからといって処理する単位が変わるわけではないから,速くなるとは考えにくい」——確かにこの考えも正しい。ワープロや表計算といったビジネス・アプリケーションでは,64ビット整数を必要とする処理はほとんどないかもしれない。

 だが,暗号化や圧縮などの符号化処理,メモリーのブロック転送などは,処理単位を大きくすれば速くなる。Microsoftによると,ベータ版の段階でさえ,x64 Editionは32ビットWindowsに比べて,Webでよく使われる暗号化処理であるSSLの性能が50%程度向上したという。

 整数演算処理だけでなく,浮動小数点演算処理についても高速化が望める。x64対応のCPUは必ずSSE命令セットを備えているからだ。FPU(浮動小数点演算装置)命令は一度に1つの値の演算をするが,SSE命令は複数の値を同時に演算するSIMD(単一命令複数データ処理)命令だ。また,FPU命令のレジスタは,先入れ後出しのスタック構造になっている。必ずスタック・トップとの間で演算しなければならず,複数の演算を並列処理することが難しい。それに比べてSSE命令は,レジスタを独立して使えるので複数の演算を並列処理しやすい上,レジスタ数がFPUの倍の16本ある。

 実際,「Panorama Factory」と呼ぶ,複数の写真をつなげてパノラマ写真を作るアプリケーションを用いたベンチマーク・テストの結果は,32ビット・アプリケーションに比べて64ビット化すると最大で57%も速くなる(図9[拡大表示])。さらに,32ビット・アプリケーションでは,使用する写真によっては,メモリー不足(out of memory)で処理が中断することもあるが,64ビット・アプリケーションではメモリー不足に陥ることはない。

 もちろんこのような64ビット・モードの利点を十分に引き出すには,整数演算処理を64ビット単位にするなど,64ビット向けに処理内容を書き換える必要がある。既存の,32ビット単位で処理しているソース・コードを再コンパイルするだけでは,処理性能を十分に引き出せない。ちなみに,64ビット用に書き換えたソース・コードはIPF互換である。再コンパイルするだけで,IPF用アプリケーションになるという副産物もある。

広大な仮想アドレス空間で安定稼働

 64ビット・モードでは,16Tバイト(Windowsの場合)という広大な仮想アドレス空間を利用できる。これは,システムの安定性を向上させることにつながる。

 32ビットWindowsでは,1つのアプリケーション当たりの仮想アドレス空間は4Gバイトである。標準でその4Gバイトを,アプリケーション(ユーザー領域)とシステム(カーネル領域)で,2Gバイトずつに分けて使用する。

 最近の32ビットWindowsは,boot.iniに「/3GB」起動オプションを付けておくと,「4GT RAMチューニング」と呼ぶ,ユーザー領域に3Gバイトを割り当てるモードになる。開発ツールにVisual C++を使う場合はリンカー・オプション「/LARGEADDRESSAWARE」を付けてビルドし,アプリケーションにIMAGE_FILE_LARGE_ADDRESS_AWAREフラグを立てておけば,3Gバイトのユーザー領域が利用できる。

 だが,1つのアプリケーション当たりの仮想アドレス空間は4Gバイトしかないので,ユーザー領域に3Gバイトを割り当てると,カーネル領域が1Gバイトに減ってしまう。結果として,ページ・テーブル・エントリやウインドウ・ハンドル,TCP/IPのソケット・オブジェクトなどを管理しているカーネル領域のメモリー不足を引き起こすことがあり,システムの不安定につながる。最近の,特にサーバー向けアプリケーションでは大容量のデータを処理することが珍しくなくなり,32ビットWindowsでのメモリー不足が深刻化してきた。

 32ビットWindowsにも,Windows Server 2003,Datacenter Editionのように,64Gバイトという大容量の物理メモリーに対応しているものもある。だが,1つのプロセス当たりの仮想アドレス空間は4Gバイトに変わりない。Windowsの*AWE(アドレス・ウインドウ化拡張)を利用すると,アプリケーションから64Gバイトのメモリーにアクセスできるが,仮想アドレス空間が広がるわけではない。64Gバイトの物理メモリー領域の一部に対して,4Gバイトのアドレス空間に作ったウインドウを通してアクセスする。一度に,64Gバイトの領域にアクセスできるわけではない。

 64ビットWindowsならば,無限に等しいメモリー空間を利用できるため,メモリー不足が原因でシステムが不安定になることはない。64ビットWindows上で動作する64ビット・アプリケーションの仮想アドレス空間は16Tバイトで,ユーザー領域に8Tバイトが割り当てられる。カーネル領域も8Tバイトあり,例えば,TCP/IPの同時接続可能最大セッション数が大幅に多くなる。

32ビットにも大容量メモリーの恩恵

 大容量メモリーが利用できるという利点は,64ビット・アプリケーションだけのものではない。既存の32ビット・アプリケーションでも,大容量メモリーを利用できるという64ビットWindowsの恩恵を受けられる。

 64ビットWindowsで32ビット・アプリケーションを動かした場合,仮想アドレス空間は32ビットWindowsと同じ4Gバイトである。だが,この4Gバイトすべてを,ユーザー領域として利用できる点が,32ビットWindowsと異なる。あらかじめ4GT RAMチューニングに対応していさえすれば,アプリケーションに全く手を加えなくても64ビットWindowsで動かすだけで,32ビットWindowsの2倍のユーザー領域を利用できるのである(図10[拡大表示])。