DEC Digital FX!32の構成図中央上部に「ランタイム&エミュレータ」が置かれていることと、中央下部に「バイナリー・トランスレータ」が置かれていることに注目。単純なAOTコンパイラではなく、JITコンパイラに近い考え方を取り入れた、複合構造のエミュレータ兼バイナリコンパイラであった。

これは64bit化の布石か? ~Android 4.4の新ランタイムART~

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

by [2013年12月02日]

Google Nexus 5
Android 4.4(KitKat)を標準搭載して出荷された最初の機種であり、それゆえARTランタイム搭載の初号機でもある。

Nexus 5へのプリインストールを皮切りにNexusシリーズなどで一般ユーザーが手にすることが可能となった、Androidの最新版であるAndroid 4.4 コードネーム「KitKat」。

この新しいOSでは、「メモリ容量512メガバイトのマシンでも従来より快適に動作する」と豪語するなど内部的に様々なブラッシュアップによるコンパクト化が行われ、さらに綺麗に撮れることに主眼を置いたカメラ機能の強化など、様々な新機能の搭載が伝えられています。

そうした新機能の中で、目立たないながらも重要なものの一つに、新ランタイム「ART」の搭載があります。

Dalvikがあるのに何故新ランタイム?

そもそも、現在のAndroidでは、アプリは原則的にJava言語で書かれたソースコードを一旦Javaバイトコードと呼ばれるJava仮想マシン(Java Virtual Machine:JVM)用の中間言語コードに変換した後、Android SDKに含まれるコード変換ツールによってDalvik Executable(DEX:Dalvik実行可能形式)と呼ばれる専用の中間言語コードに最適化・再変換の上でパッケージ化されて提供されています。

こうすることで、OS側は必ずDalvik VMなどの専用ランタイムを搭載せねばならないものの、プログラマは慣れたJava言語でプログラムをコーディングでき、しかも特に意識することなくスマートフォンやタブレットなど搭載メモリ量の制約の厳しいマシンに最適化されたDEXコードに変換されるため、通常のJVM環境よりもコンパクトかつ高速な実行性能を得られる、というメリットがあります。

Android OSの内部階層構造図
Dalvik VM上で動作する.dexコードと各プロセッサのネイティブコード(機械語)の2種の全く異なる命令セットに従って書かれたアプリを同様に実行可能とするため、複雑な階層構造を採る。

またこのDalvik VM自体は、Androidが動作する各マシンに搭載されているCPUのアーキテクチャごとにそれぞれ固有の命令セットで定められた機械語(と一対一の対応関係にあるアセンブリ言語)を用いてダイレクトに書かれています(※それゆえ、Dalvik VMそのものはARM、MIPS、x86といった現在のAndroidがサポートする各CPUアーキテクチャごとに専用のものが個別に最適化の上で作成されています)。

そのため、アプリのプログラマが特別な対応を行わなくても、全く命令セットもアーキテクチャも異なる複数のCPU環境で、アプリが高速かつ同等の動作を得られるようになっているのです。

このDalvik VMは現状で既にJust-In-Timeコンパイラ(JITコンパイラ:実行時コンパイラ)と呼ばれる変換方式での極限に近い性能を実現しており、これそのものは行き過ぎるほどのチューンが祟ってこれ以上ほぼ手を入れられない状況(※なお、現行のAndroidはx64やARM-v8などの64ビット命令セットに対応していませんが、これはこのDalvik VMの移植がネックになっていると推測できます。また、そのコーディングの性格上このVMはマルチCPUコア環境におけるスレッド分散処理が苦手で、搭載マシンのCPUコア数増加にも十分対応できていない面があります)になっています。

そのため、今後64ビット命令セットに対応する多コアの新CPUアーキテクチャが導入されるのが火を見るよりも明らかな状況(※ライバルであるiOSがiPhone 5sでARM-v8準拠の64ビット命令に対応した以上、Androidも今後の64ビット化を避けられません)であることも考慮すると、それそのものの移植性と動作時のアプリ実行速度の高速化を両立させた新ランタイムが(将来的に)必要だ、ということになります。

現時点でGoogleは開発意図を明らかにしていないのですが、時期と状況を考えると恐らくはそんな将来を見据えた計画の下に開発されたのが、この新ランタイム「ART」ということになりそうです。

ARTの仕組み

新ランタイム「ART」は、JITコンパイラを搭載しているDalvik VMとは異なり、Ahead-Of-Timeコンパイラ(AOTコンパイラ:事前コンパイラ)と呼ばれる方式を採用しています。

この方式の特徴は、JITコンパイラがアプリの実行時に中間言語コードをリアルタイムで各マシンのCPUに理解可能な機械語コードに変換して処理している(※ただし、キャッシュが用意されているため、頻繁に利用される中間言語コードは2度目以降の変換処理をパスできます)のに対し、アプリが実行される前、インストール時などに事前に中間言語コードを機械語コードに変換処理して保存しておき(※Android 4.4ではストレージ内のアプリ保存領域に、Dalvik VM用の.dex形式の中間言語コードファイルと共に.oatという変換済みのネイティブ機械語コードファイルがアプリの初回起動時、あるいはランタイム切替操作に伴う最適化処理時に作成されます。また、ソースコードの記述から、今後.dex形式だけでなく、この.oat形式で事前にコンパイル済みのコードをGoogle Playで配信することも考慮されているようです)、実際にアプリを実行する際にはこの機械語コードが用いられる点にあります。

つまり、このARTは「基本的には仮想マシンではない」(※ただし、.dex形式の中間コードをリアルタイムに解釈・実行するためのインタプリタも一応搭載されている模様)のです。

Dalvik VMの場合、中間言語コードで書かれたアプリを動作させるには常にコード変換を行うVMがランタイムとして動作していなくてはならないのですが、ARTの場合は事前に変換済みのためこのランタイムはアプリ動作時には直接.oatファイルを呼び出すだけで、これがAndroid NDKで書かれたネイティブコードのアプリと同様の動作をします。

このため、コード変換を行うVMが常時動作しないで済むため、その分だけ消費電力が低減され、またアプリの実行速度も変換に伴うロスがないため、理屈上はDalvik VM使用時より高速化が期待できます。

なお、現状ではこのARTは「experimentally 」つまり試験的な実装であるとされ、「Dalvik must remain the default runtime or you risk breaking your Android implementations and third-party applications.(Dalvikは変わらずデフォルトのランタイムのままであり、さもなくばあなたのAndroidの実装やサードパーティ製アプリケーションを壊す危険性があります。)」とも明言・警告されています。

Introducing ART(Android公式サイト内の紹介記事)

ちなみに、このART、現状ではAndroid 4.4搭載マシン各種での動作レポートなどを見る限り、Dalvik VMと大差ない性能で動作しているようなのですが、そのソースコードをざっと眺めてみた限りでは機械語でゴリゴリにチューンされたDalvik VMと同程度の性能を、C++で、それも割とざっくりとした「とりあえず動けばいい」レベルのコードで書かれたARTが出している(※ただし、現状では正常動作しないアプリも少なくないようですが)あたり、現状での完成度はともかく技術としての素性の良さは明らかでしょう。

もっともこのART、現状では最適化されていないコードを吐き出していて、.oat形式のファイルは.dex形式の場合よりもかなり大きなサイズになっている(※特にターゲットとなるCPUがRISCアーキテクチャのARMやMIPSの場合、ネイティブのコードは他のアーキテクチャよりもサイズが大きくなる傾向があります)ようです。

最終的に完成の域に達すれば恐らく全般的にDalvik VMより高速かつ低消費電力での動作が期待できそう(※理屈上、コーディングでよほどへまをしない限りは必然的にそうなります)ですが、その場合でも.dex → .oat変換に伴うアプリサイズの増大と性能向上がトレードオフの関係となるため、当分の間(少なくとも64ビットCPU対応版Androidが提供されるまで)は特にストレージ容量の厳しい機種の多いスマートフォンの場合、Google自身も言っているようにDalvik VMをデフォルトのランタイムとしておくのが賢明と言えそうです。

実は結構古いAOTコンパイラ

DEC Digital FX!32の構成図
中央上部に「ランタイム&エミュレータ」が置かれていることと、中央下部に「バイナリー・トランスレータ」が置かれていることに注目。単純なAOTコンパイラではなく、JITコンパイラに近い考え方を取り入れた、複合構造のエミュレータ兼バイナリコンパイラであった。

入力されたソースコードを変換して実行形式のバイナリを吐き出す一般的なコンパイラ(これもAOTコンパイラの仲間になります)はともかくとしても、中間言語コードや他のアーキテクチャの機械語コードで書かれたアプリを事前変換して実効速度の引き上げを図るAOTコンパイラ技術の考え方は、実は決して新しいものではありません。

例えば、DEC(Digital Equipment Corporation)が開発したAlpha(Alpha AXP)と呼ばれる64ビットRISC CPU(※発表当時「世界最高速のプロセッサ」と謳われました)のために、同社がAlphaに対応していたWindows NT 4.0(Service Pack 3以降。およびBeta 3までのWindows 2000)上でバイナリ互換性のない(しかし市場に大量に出回っている)x86用プログラムを動作させるために1996年に開発・提供開始したDigital FX!32というバイナリコンパイラは、当初、JITコンパイラのように実行対象となるアプリのx86命令で書かれたコードを逐次ブロック単位でAlphaのネイティブコードに変換しつつ実行するのですが、変換されたブロックも順次保存し、最終的には全体が変換されてファイルに保存されて以後はそちらのネイティブコードで動作する、というJITコンパイラとAOTコンパイラの良いところ取りをしたような巧妙な設計になっていました。

DIGITAL FX!32:Combining Emulation and Binary Translation
(旧DECからAlphaプロセッサ事業を承継したCOMPAQ社を吸収合併したヒューレット・パッカード社のサイトで今も公開されている、DEC時代のエンジニアによる論文)

x86系プロセッサの動作クロック周波数がまだ200MHzに達するか達さないか、という時期に600MHzを超える超高速駆動が可能なように設計されたAlphaプロセッサ上で動作し、少なくともx86環境と同程度の実効性能を実現した(Microsoft Officeも動作可能にした)このバイナリコンパイラは、残念ながら経営不振によるDECの解体(1997年~1998年)とそれに伴うAlpha開発チームの人材流出・解体、マイクロソフトのWindows 2000におけるAlphaプロセッササポートの中止(1999年)、といった事態を経て最終的に真価を発揮しないままに終焉を迎えました。

このDigital FX!32の示したJITコンパイラとAOTコンパイラの折衷とでもいうべき構成は、今後のARTの発展を考えた場合に様々な示唆と教訓を与えてくれるものです。

AOTコンパイラの場合、どうしても初回起動時あるいは最適化処理の際にネイティブコードへの変換作業で長大な時間を要するという問題があり、実際にもランタイムをARTへ切り変えた場合に最適化処理にかなりの時間を要し待たされたことが報告されています。

その点で、全体を丸ごと一括して変換しようとするのではなく、JITコンパイラと同様に実行中のブロックだけを随時変換し、それを積み重ねてゆくことで最終的に全体の変換完了を目指すDigital FX!32の方法論は、初回動作時の動作速度が遅いという問題があったものの、「極端に長く待たされずに済む」という点で良い解決策でした。

ARTも今後パフォーマンス向上と変換時の時間待ち短縮を両立させるのであれば、このDigital FX!32の手法や考え方を再検討してみる必要があるのではないでしょうか。

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

タグ:
PageTopへ