Sep 11, 2008

Chromeのevalは遅い? (cont)

Ogawa::Buzz: Chrome のevalは遅い?の追記というか解答編。

test3は以下のように書けば一行で済む:

eval('(function(){' + code + '})()');

というのはさておき。

test2がJITコンパイルのオーバーヘッドで遅いというのには無理がある。

まず、test2が遅くなるのはV8に限った話ではない。IE7でもFirefox3でも遅くなるが、V8の基本性能が高いためにChromeの速度低下が著しいように見えるだけである。もっと手っ取り早く確認したければ、test2のループカウントを増加させながらプロットしてみればいい。カウントの値のほぼ定数倍の実行時間がかかる(=JITコンパイル時間が無視できる)ことが分かるはずだ。

そうではなく、単純にプロパティアクセスが速い場合と遅い場合があるためと考えるのが自然である。つまり、

  • test1では、コアループで使用するプロパティ(i, result)は、test1というfunction(オブジェクト)の固定オフセットに格納されるので、高速にアクセスできる。
  • test3では、コアループで使用するプロパティは、calcEvalというfunctionの固定オフセットに格納されるので、高速にアクセスできる。
  • test2では、コアループで使用するプロパティは、test2のコンパイル時にはアロケートされない(字面上アロケートされるかどうか判別できないから)。したがって、実行時にeval内で動的にアロケートするコストがかかる上、functionの固定オフセットでアクセスすることはできないので高速なアクセスも望めない。

さてここで、test2を若干修正して、eval時ではなく、このfunctionのコンパイル時にresult, iをアロケートし、そのプロパティを使ってeval内の計算を行うようにしてみる。

function test2_prealloc() {
    var code = [
        'result = 0;',
        'for(i = 0; i < 1000000; i++){',
            'result += i;',
        '}'
    ].join('\n');
    var date = new Date();
    var result = 0;
    var i = 0;
    eval(code);
    print((new Date() - date).toString());
}

test2が約1200msecかかっていたのに対して、test2_preallocは約600msecで済む。高速化されたのは、メジャーな要因としてはevalでのアロケートのコストの削減、マイナーな要因としてはプロパティアクセスのオーバーヘッドの一部の削減、による効果と推定できる。こんなに速くなるのはアロケータの実装も寄与している可能性がある。記憶域をハッシュテーブルで実現しているような処理系ではここまでの高速化は望めないのが一般的だろう。

しかし、まだ20msecには程遠い。なぜかと言えば、どうやらevalによって作られたコンテキストからダイレクトにtest2_preallocの固定オフセットを使って高速にプロパティにアクセスする方法がないから、のようだ。想定できる状況としては2つあり、その一方または両方の問題があると思われる。

まず、test2_preallocのevalで使用するプロパティが、eval内新規にアロケートすべきプロパティか、test2_preallocでアロケート済みのプロパティか(あるいは他のところでアロケート済みのプロパティか)を判別する必要がある。そのため、スコープの内側から順にresult, iがアロケート済みかどうかルックアップして、なければアロケート、あればそれを使うという処理が必要になる。これは固定オフセットを使ってアクセスするのに比べて低速になる。ただし、この判定はevalが呼ばれるたびに一度だけ行えば済むはず。もしプロパティアクセスごとに検査しているようならそれは実装が悪い。ああ、Thread-Safeにする目的があるのなら実装が悪いとは言い切れないね。いつかはJavaScriptのスレッドモデルがまともに拡張される可能性がまったくないわけではない。

もうひとつは、evalが作るコンテキスト(活性レコードと言ってもいい)から外側のコンテキストに高速にアクセスする方法が提供されていない可能性を疑ってもいいかもしれない。両者のスコープは通常の静的スコープに従うのだから(そうだよね?)、呼び出し元のコンテキストに静的リンクを辿るなりディスプレイを参照するなりして比較的小さいオーバーヘッドでアクセスできるはず。もしそうじゃないならそれは実装が悪いと思うが、私が見落としている問題があるかもしれない。

以上。evalは慎重にね。

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com