Mozilla Flux

Mozilla関係の情報に特化したブログです。

Firefox 3.1で採用される高速化技術

Firefox 3.1では、最新の高速化技術が惜しげもなく投入され、現行のFirefox 3.0.xから体感できるレベルでスピードアップが図られている。今回はその主要な技術を紹介する。

TraceMonkey

TraceMonkeyは、FirefoxのJavaScriptエンジンであるSpiderMonkeyを拡張する技術で、Just-In-Time (JIT) コンパイラという機能によって、JavaScriptの実行速度を大幅にアップさせるものだ。最近では、GmailやGoogleマップのようなJavaScriptを多用するWebサービスが続々と登場しているため、この技術のもつ意義は大きい。コンテンツの表示が目に見えて速くなるのだから。

元になったのは、カリフォルニア大学アーバイン校(UC Irvine)で開発された"Trace Trees"という技術である。もともとMozillaでは、Adobeから寄贈を受けたソースコードをもとに新エンジン"Tamarin-Tracing"を開発していたが、思うようにスピードが伸びなかった。そこで、JITコンパイラ部分のNanojitなどは流用することにし、Trace Treesを取り入れて、JITコンパイラを強化したわけだ。2008年8月下旬にTraceMonkeyが発表されたとき、開発開始から2か月だとアナウンスされていたので、プロジェクトの開始は6月となる。まさに最新の技術といえる。

TraceMonkeyを導入したJavaScriptエンジンは、読み込んだJavaScriptのソースコード(人間が読めるコード)を解釈してバイトコード(中間言語)に変換してから実行する際、条件分岐を監視し、分岐先で一定回数以上ループ処理が行われたら、ネイティブコード(機械語)に再度変換して、以降はそのネイティブコードを実行するのだという。JITコンパイラは、C++のような事前処理型のコンパイラと比べ、実行時の情報を利用できるメリットがあるが、TraceMonkeyはさらに、既存のJITのように関数呼び出しをカウントするのではなく、ループそのものに着目することで、効率よくネイティブコードを生成できるようにした。つまり、闇雲にネイティブコードに変換すると、ネイティブコードを実行することで稼いだ時間よりも、変換にかかる時間が上回ってしまうが、TraceMonkeyはその問題を解決した点に特色がある。

TraceMonkeyの発表からまもなくして、Google Chromeが発表され、そのV8 JavaScriptエンジンにもJITコンパイラが搭載されていたことから、両者の対決が話題になったのは記憶に新しい。9月上旬の時点では、有名なSunSpiderベンチマークによるテストで、TraceMonkeyを導入したFirefoxがGoogle Chromeに僅差で勝利している。

MozillaがTraceMonkeyの開発へシフトする一方、コードを寄贈したAdobeはTamarin-Centralとしてコードの改良を続けていた。その成果はMozilla側でNanojit2と呼ばれ、10月半ばにはTraceMonkeyに統合された。残念ながらそれによって直ちにパフォーマンスが向上するものではなかったが、長期的な基盤になるだろうと見込まれている。今後改善される余地がそれだけ大きいということだろう。

その後もTraceMonkeyの改良は続けられている。ライバルのV8エンジンもそれは同じだ。CNET Newsの記事によれば、12月上旬、Firefox 3.1 Beta 2と正式リリース前のGoogle ChromeでSunSpiderベンチマークを実行したところ、両者はほぼ互角という結果になった。

実は、TraceMonkeyの効果が及ぶのは、コンテンツの表示だけにとどまらない。FirefoxはXULというマークアップ言語でユーザーインターフェイスが記述されているが、そのXULはJavaScriptを取り込んでいる。そのため、TraceMonkeyの導入によって、プログラムの動作速度も上がる。ただ、Firefox 3.1 Beta 2の段階では、TraceMonkeyをコンテンツの表示にのみ適用する設定が標準となっている。インターフェイスに適用するまでには処理が安定していないからだ。

なお、Firefox 3.1では、SpiderMonkeyそれ自体が高速化されていることも見逃せない。8月下旬の時点でFirefox 3と比較して約20%アップという。現在ではもっと速くなっているだろう。

Speculative Parsing

Firefox 3.0.xでは、あるWebページで複数の外部スクリプトファイル(たとえばxxx.jsなど)が指定されている場合、1つのファイルを読み込んでいる間は、他の部分の読み込みや解釈が中断してしまう。これは、そのスクリプト(JavaScriptなど)にページ内の他の個所を表示させない指示が書き込まれている可能性を考慮してのことだが、実際にそのような例はまれだ。

そこで、スクリプトファイルの読み込み中も、他の部分の読み込みや解釈の処理を中断しないようにするのが、このSpeculative Parsing(投機的解釈)という技術だ。現在のところ、別のスクリプトファイルの読み込みを平行して処理するだけで、スタイルシートや画像は対象とされていないが、それでも、多数の外部スクリプトファイルを参照しているWebページでは多大な効果を発揮する。

cairoバックエンドの最適化

Firefoxに搭載のGeckoレンダリングエンジンは、Webページを解釈して細部までレイアウトを決める。が、その先の描画部分はcairoバックエンドと呼ばれるライブラリが担当する。

このcairoのバージョンが、Firefox 3.0.xの1.6.2から、Firefox 3.1では1.8.2に引き上げられている。リリースノートを参照する限り、テキストの処理が強化され、パフォーマンスの最適化も行われているようだ。

また、cairoではpixmanというピクセル操作用ライブラリが使われているのだが、Firefox 3.0.xではMMX最適化どまりだったのに対し、Windows版のFirefox 3.1では、SSE2最適化に対応している。これは、CPUが用意している、マルチメディアデータを処理するための特別な命令セットをどこまで利用するかという話だ。当然Firefox 3.1のほうが新しい命令セットをサポートしており、画像の処理が高速化される。Pentium 4 / Athlon 64以降のCPUを搭載したパソコンを必要とするものの、ネットブックも含め、ここ5年ほどの間に出たパソコンなら大丈夫のはずだ。

DNSプリフェッチ

WebブラウザがWebページを表示させるとき、当然そのページを保管しているサーバーと通信する必要がある。インターネットでは、サーバーの位置はIPアドレスという数字の組み合わせで表されるのだが、そのままだと人間が使いにくいので、ドメインネームという文字に変換している。たとえば、74.125.19.147というIPアドレスは、www.google.comというドメインネームで対応させている。つまり、ユーザーがリンクをクリックするといった形で新しいページを指定した場合、Webブラウザはまずドメインネームサーバー(Domain Name Server)にIPアドレスを問い合わせ、その情報をもとにページが保管されているサーバーにアクセスする仕組みなのだ。

DNSプリフェッチは、以上の仕組みを前提にし、ユーザーがページを見ている間に、リンク先のIPアドレスをあらかじめ問い合わせて貯めておき、ユーザーがページを移動する際にいちいち問い合わせる必要をなくす技術だ。無駄な通信が増える代わりに、体感速度を上げることができる。ただし、回線が非常に高速であれば、その都度問い合わせても支障がなく、ほとんど差は感じられないだろう。

最初にこの技術を実装したのはGoogle Chromeだ。Firefoxでは、Google Chromeのβ版がリリースされた直後から開発が進められ、11月中旬には実装に至っている。Firefox 3.1 Beta 2には既にこの技術が搭載されているわけだ。

(09/01/17追記)
Firefoxの開発にも携わるMakoto Kato氏は、『各ブラウザのDNS Resolver』の中で、次のように指摘している。Firefoxは従来から「DNS<->IPアドレスのマップ」をキャッシュしており、同一ホストへのアクセスは高速化されていた、と。DNSプリフェッチは、別のホストへのリンクがあるときに威力を発揮するものなのだ。