ブラウザ JavaScr ip t 高速化
JIT バトル最終決戦


12-B-5    森田創
          Co m m u n it y En g in e, In c
          o m o @d o d g so n ...
本日の趣旨
J a va S c r ip t VM に使われている
高速化技法を
紹介します。




                               2
自己紹介

森田創
  勤め先 : Co mm unity Eng ine ( 株 )
●


     オンラインゲームなどの開発や開発支援
     オンラインゲームのミドルウェア販売
    仕事 :↑ らのためにコードを書くこと
●...
参考:
アマチュア野球評論家(イメージ)↓




                4
疑問が3つ。




         5
疑問 1/3

ほんとに
最終決戦とやらが
ホットなのか?




           6
/speedup|optimiz/ の回数
 @Saf ar i JS エンジンの ChangeLog
  50

  45

  40

  35

  30
                                         ...
疑問 2/3

ほんとに
速くなると
うれしいのか?




          8
私家版手動ベンチマーク
 with oprofile


gmail




                         libmozjs
        libxul
gdocs



    0%           20%   40...
疑問 3/3

この話は
皆様にとって
何の役に立つのか?




            10
答え3:蘊蓄の足しになる
蘊蓄を愛でるのは日本人として当然の嗜み




                      11
ブラウザ J a v a Sc r ip t 高速化
J IT バトル最終決戦
観戦ガイド


                  森田創
                  Co m m u n it y En g in e, In c
  ...
これまでのあらすじ
登場人物 VM x3
  V8
●

  f r o m Go o g le Chro m e
  SquirrelFish Extreme
●

  f r o m Ap p le S a f a ri/We b Kit
...
V8 の系譜
    S un から引き抜かれた
●

    La r s Ba k がエース
        S t r o ng ta lk VM
    ●


        J a va Ho t s p o t VM
    ●
...
SquirrelFish Extreme の系譜

    J a va S c r ip tCo r e 高速化バージョン
●


        バイトコード化 (“ q uirr e lFis h”
    ●
             ...
TraceMonkey の系譜
    S p id e rMo nke y
●

              +
    Ta m a r in Tr a c ing
    And r e a s Ga l の研究成果
●


      ...
決戦の舞台
    V8
●

    b r a nc he s /b le e d ing _e d g e r1198
    S q uir re lFis h Extre me
●

    t r unk r40447
    Tr...
本題 :JavaScript VM の高速化
J a va S c r ip t は遅い。なぜなら・・・
    昔は実装をさぼっていた。
 ●


        うざいポップアップを出せればよかった。
    ●


        g m...
JSVM 高速化の戦略
    J S 言語固有の面倒をとりのぞき、
●


    既存 VM の高速化技法をとりいれる
●


        J a va , S ma llta lk, Lis p , …
    ●


    ウェブ...
JSVM 高速化の見所3つ
    J S 言語固有の面倒をとりのぞき、
●


    既存 VM の高速化技法をとりいれる
●


        J a va , S ma llta lk, Lis p , …
    ●


    ウ...
JSVM 高速化の見所3つ+1
    J S 言語固有の面倒をとりのぞき、
●


    既存 VM の高速化技法をとりいれる
●


        J a va , S ma llta lk, Lis p , …
    ●


   ...
ここからのあらすじ
    J S 言語固有の面倒 :
●

    クラスがないのをどうにかする話
    既存 VM 技術の応用 :
●

    メソッド呼び出しの高速化の話
    ウェブアプリのツボ :
●

    正規表現の高速化...
ここからのあらすじ
    J S 言語固有の面倒 :
●

    クラスがないのをどうにかする話
    既存 VM 技術の応用 :
●

    メソッド呼び出しの高速化の話ヘ
             ∴ã€


    ウェブアプ...
復習:
クラスがあるとどう嬉しい?

class Point {
public:
   int x; int y;
};

Point *p = new Point();
p->x = 10;
p->y = 20;
              ...
こたえ:
クラスがあれば構造がわかる
    クラス=配列
●
    (C+ + , J a va 処理系にとって。 )

    構造=メンバ変数の並び
●




    メンバ変数アクセスが
●

    高速!


         ...
class Point {
public:
   int x; int y; int z;
};
....
Point *p = new Point();
p->x = 10;   // movl $10,   (%eax)
p->y = 20...
Point @ JavaScript

function Point(x0, y0) {
  this.x = x0;
  this.y = y0;
}
…
var p = new Point(10, 20);




            ...
Point @ JavaScript
function Point(x0, has_y, y_or_z) {
  this.x = x0;
  if (has_y) { // 実行時にプロパティが変わる!
    this.y = y_or_z...
JS のオブジェクトはハッシュ表
素朴な




                    ヘ
            ∴ã€




    プロパティアクセス=ハッシュ表検索
●


    ハッシュ表は遅いらしい
●

        ...
ベンチマーク :
配列 vs. ハッシュ表 in C++
int benchmark(bool use_hash) {
  const int NELEM = 100;
  if (use_hash) {
    std::tr1::unord...
ベンチマーク結果
    hash


    array




            0   5   10   15   20   25   30   35   40



短い方が高速(横軸は実行時間)
    7倍遅い!
●


  ...
洞察:
大半はいつも同じだよね?

function Point(x0, has_y, y_or_z) {
  this.x = x0;       ↑ こんなことしないよね?
  if (has_y) { // 実行時にプロパティが変わる!
...
アイデア:
仮のクラスを割り振ってみる
var p = new Point();
p.x = 10;
p.y = 20;




                       ※ クラスが構造を知っている
                   ...
別の構造には別のクラスを・・・




var q = new Fullname();
q.first = “Jose”;
q.middle = “Luis”;
q.last = “Carol”


                      ...
同じ構造には同じクラスを・・・
var p1 = new Point();
p1.x = 10;
p1.y = 20;

var p2 = new Point();
p2.x = 10;
p2.y = 20;




             ...
途中で構造が変わったら?

…
var p1 = new Point();
p1.x = 10;
p1.y = 20;

var p2   = new Point();
p2.x =   10;
p2.y =   20;
         30...
あとから新しいクラスが派生




                37
JSVMs には
仮のクラスを類推するしくみがある
プログラム実行時に
  同じ構造のオブジェクトに同じクラスを
●


  違う構造のオブジェクトに違うクラスを
●


割り振る。→オブジェクトの構造がわかる

    構造が変わるとクラスも...
各 VM 上での名前
    V8 では
●

    Hidden Class
    Tr a c e Mo nke y では
●

    Shape Inf erence
    S q uir re lFis h Extre me で...
VM 実装毎のこまかな違い
    コンストラクタは違うけど
●

    プロパティが同じときは?
    function A(x0, y0) { this.x = x0; this.y = y0; }
    function B(x0,...
クラスができた。次は・・・




                41
ここからのあらすじ
    J S 言語固有の面倒 :
●

    クラスがないのをどうにかする話 ( 済 )
    既存 VM 技術の応用 :
●

    メソッド呼び出しの高速化の話ヘ
              ∴ã€


  ...
ここからのあらすじ
    J S 言語固有の面倒 :
●

    クラスがないのをどうにかする話 ( 済 )
    既存 VM 技術の応用 :
●

    メソッド呼び出しコードの高速化の話
                  ヘ
  ...
復習 (1/3): JIT て何だっけ?
    高級言語のプログラムを
●

    実行時に機械語へ変換する高速化
        実行時= J us t In Tim e
    ●


    具体的には
●

    J a va S...
JIT 前(インタプリタ)
                   ここがバイトコード
while (true) {
  switch(instructions[pc++]) {
  case OP_XXX:
    do_xxx(); // ほ...
JIT 後(生成された機械語)
do_xxx();
do_yyy();
do_zzz();
....
            生成される機械語の疑似コード




                        46
JIT の利点と制限
インタプリタのオーバーヘッドがなくなる
● while(true)


    instructions[pc++]
●


    break;
●


個々のバイトコード実装は速くならない。
      例:メソッド呼...
復習 (2/3):
JS のメソッド呼び出し
function Greeting() {
  this.hello = function() {
     alert(quot;hello!quot;);
  };
}

var g = new...
復習 (2/3):
JS のメソッド呼び出し
function Greeting() {
  this.hello = function() {
     alert(quot;hello!quot;);
  };
}
            ...
復習 (2/3):
JS のメソッド呼び出し




    ↓ プロパティ取得を速くしたい
      var gh = g.hello;
      gh.apply(g);

                          50
復習 (3/3)
JS は動的型付けの言語
    動的型付けの言語では
●

    プロパティの取得が遅いらしい
    でも
●

    構造がわかれば速いんでしょ?
    仮クラスによって
●

    オブジェクトにはクラスができ...
復習 (3/3) の前に・・・
C++ は静的型付けの言語
    変数にクラスがある。
●



int lengthSquared(Point p) {
  int x = p.x;
  int y = p.y;
  int xx = x*...
クラスがある=構造がわかる
int lengthSquared(Point p)
{
  // pushl %ebp
  // movl %esp, %ebp
  int x = p.x;
  // movl 12(%ebp), %edx ← ...
復習 (3/3)
JS は動的型付けの言語
// x と y がプロパティ
function Point(x0, y0) {
  this.x = x0;
  this.y = y0;
}

// name と x と y がプロパティ
fun...
復習 (3/3)
 JS は動的型付けの言語
                              ?
// p のクラスはなに?
function lengthSquared(p) {
  return p.x*p.x + p.y*p....
動的型付けの言語は
変数にクラス指定がない
    オブジェクトごとのクラスはわかっても
●


    変数のクラスは ( 調べるまで ) わからない
        構造を仮定した高速化ができない
    ●


    動的型付け言語一般...
JS のプロパティアクセスは
素朴な
結局ハッシュ表検索 (+ 配列アクセス)

               // 等価な C++ 風コード
// JS
var x = p.x;   Object* x
                   ...
クラスのハッシュ表から
●

    構造を検索して



    検索結果を使い
●

    プロパティ配列にアクセス




                   58
洞察 :
だいたい同じクラスを使うよね?


function lengthSquared(p) { // 長さの二乗
  return p.x*p.x + p.y*p.y;
}

var pt = new Point(10, 20);
var...
アイデア :
よく使うクラスに特化してみる
               // 等価な C++ 風コード
// JS
var x = p.x;   if (p->klass == PointClass) {
                  ...
コード
           ...


if (p ->k lass = Po in t Class)
                                  p ->Get Pr o p er t y ()
Po in t _G...
コード
     ...


  よく使う型か?
                型を仮定しない
型を仮定した速いコード !    遅いコード
                   ...


    コード
     ...


      ...
予想が間違っていたら?
var pt = new Point(10, 20);
var it = new Item(quot;yakusouquot;, 10, 20);

for (var i=0; i<100; ++i) {
  var p...
元のコードを書き換える !
               // 等価な C++ 風コード
// JS
var x = p.x;   if (p->klass == PointClass
                             ...
コード
      ...


  よく使う型 ' か?
  よく使う型か?
                 型を仮定しない
型を仮定した速いコード !!
型 ' を仮定した速コード     遅いコード
                   ...
JSVMs は
投機的な型付きコードを生成する
  ある型専用のコードを生成しておき、
●


  オブジェクトの型をチェックしてから、
●


  そのコードを呼び出す仕組み
●


適用箇所
  プロパティアクセス
●


  そのあとのメ...
四則演算の例
         // 等価な C++ 風コード
// JS
a + b;   if (ClassOf(a) == IntClass &&
             ClassOf(b) == IntClass) {
      ...
各 VM 上での名前
    V8 , S q uir r e lFis h Ext r e m e では
●

    Po ly m o r p h ic In lin e Cac h in g
        SELF 言語由来
    ...
Polymorphic Inline Caching
    コードの中 (Inline ) に
●

    比較用のクラスを保存する (Ca c hing )
    一つ以上のクラス (Po lym o r p hic ) を
●

  ...
Tracing Tree
    バイトコードを実行しながら (Tr a c ing )
●

    ひとつながりのネイティブコードを生成
        コードがインライン化される
    ●

        ( メソッド呼び出しもインラ...
// 設定切替
                              ベンチマーク
var mono = false;
var n = 10000;
var arr = [];

for (var i=0; i<n; ++i) {
  i...
ベンチマーク結果

V8




SFX                                               mono
                                                  ...
世間並みになった。次は・・・




                 73
ここからのあらすじ
    J S 言語固有の面倒 :
●

    クラスがないのをどうにかする話 ( 済 )
    既存 VM 技術の応用 :
●

    メソッド呼び出しの高速化の話(済)
                  ヘ
  ...
復習 (1/2) :
正規表現ってどう実装するの?
二つのアプローチ
  状態遷移表を作る路線
●


        DFA, NFA, ...
    ●


        g r ep , lex , …
    ●


    インタ...
復習 (2/2):
インタプリタの高速化といえば?
これまでさんざん話してきましたが ...




                       76
アイデア :
正規表現も JIT したら?
最終決戦だし。

    パース→バイトコード→機械語生成
●




                       77
JSVMs には
正規表現の JIT コンパイラがある
ただし
  すべてが J IT されるわけではない。
●

  がんばり具合は各社各様。
        V8 : regexp2000 ブランチがマージされた
    ●


     ...
ベンチマーク結果
sunspider/regexp-dna.js


   V8(JIT)



 V8(NOJIT)



      SFX



       TM

             0   0.5   1   1.5   2 ...
3つの見所まとめ
  クラスがない J S の制限を乗り越える
●

  仮クラス割り振りの仕組み
  既存の VM 技術を適用した
●

  投機的な型付きコード生成の仕組み
  ウェブアプリのホットスポット
●

  正規表現の J IT ...
今日でてこなかった話
    VM っぽい高速化
●


        GC (コピーなんとか、世代なんとか・・・)
    ●


        命令セット(粒度、レジスタ vs スタック)
    ●


        ネイティブコー...
今後の見所
    ブラウザを含めたアプリの総合性能
●


        FF1 1 ベンチ → g m a il ベンチ
    ●


    モバイル機器での性能
●


        消費メモリ
    ●


        A...
観戦 HOWTO
    とりあえずコードを読んでみよう
●



     コア部分は 1 -2 万行程度
    ●


    元ねたの論文を探して読もう
●


     大抵コードよりわかりやすい
    ●


    プロジェクト...
ブラウザ J a v a Sc r ip t 高速化
J IT バトル最終決戦
観戦ガイド



       ご清聴ありがとうございました。
                             84
写真たち
    htt p ://f ic kr.c o m /p ho to s /d c jo hn/2 4 4 0 1 7 8 8 0 1 /
             l
●



    htt p ://f ic kr.c o m...
Upcoming SlideShare
Loading in …5
×

devsummit2009js

3,255
-1

Published on

Published in: Technology, Education
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,255
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
121
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

devsummit2009js

  1. 1. ブラウザ JavaScr ip t 高速化 JIT バトル最終決戦 12-B-5 森田創 Co m m u n it y En g in e, In c o m o @d o d g so n .o r g
  2. 2. 本日の趣旨 J a va S c r ip t VM に使われている 高速化技法を 紹介します。 2
  3. 3. 自己紹介 森田創 勤め先 : Co mm unity Eng ine ( 株 ) ●  オンラインゲームなどの開発や開発支援  オンラインゲームのミドルウェア販売 仕事 :↑ らのためにコードを書くこと ● 主に C+ + ( たまに r ub y, p ytho n, Ac t io nS c r ip t...) ● ウェブとかよくわかんない ● アマチュア J a va S c r ip t VM 評論家 ● ↑ これでよばれた。 3
  4. 4. 参考: アマチュア野球評論家(イメージ)↓ 4
  5. 5. 疑問が3つ。 5
  6. 6. 疑問 1/3 ほんとに 最終決戦とやらが ホットなのか? 6
  7. 7. /speedup|optimiz/ の回数 @Saf ar i JS エンジンの ChangeLog 50 45 40 35 30 Go o g le Chr o me 登場 25 20 S a f a r i J S 刷新 15 S a f a r i リリース “ x”登場 Aja 10 5 0 02 02 03 03 04 05 05 06 06 07 07 08 /0 /1 /0 /0 /0 /0 /1 /0 /0 /0 /0 /1 6 3 0 7 2 9 4 1 1 8 5 2 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 7 1 1 1 1 1 1 1 1 1 1 1 1
  8. 8. 疑問 2/3 ほんとに 速くなると うれしいのか? 8
  9. 9. 私家版手動ベンチマーク with oprofile gmail libmozjs libxul gdocs 0% 20% 40% 60% 80% 100% システムの10− 20% ● •プロセスの3割 9
  10. 10. 疑問 3/3 この話は 皆様にとって 何の役に立つのか? 10
  11. 11. 答え3:蘊蓄の足しになる 蘊蓄を愛でるのは日本人として当然の嗜み 11
  12. 12. ブラウザ J a v a Sc r ip t 高速化 J IT バトル最終決戦 観戦ガイド 森田創 Co m m u n it y En g in e, In c o m o @d o d g so n .o r g 12
  13. 13. これまでのあらすじ 登場人物 VM x3 V8 ● f r o m Go o g le Chro m e SquirrelFish Extreme ● f r o m Ap p le S a f a ri/We b Kit TraceM onkey ● f r o m Mo zilla Fire f o x が、血みどろの戦いを繰り広げていた!!! 13
  14. 14. V8 の系譜 S un から引き抜かれた ● La r s Ba k がエース S t r o ng ta lk VM ● J a va Ho t s p o t VM ● コードにも ● S t r ong t a lk の残骸 GC ● アセンブラ ● 14
  15. 15. SquirrelFish Extreme の系譜 J a va S c r ip tCo r e 高速化バージョン ● バイトコード化 (“ q uirr e lFis h” ● S ) J IT 追加 (“ ● Extre m e ” ) KHTML/KJ S から派生 ● まだあるよ↑ ● 15
  16. 16. TraceMonkey の系譜 S p id e rMo nke y ● + Ta m a r in Tr a c ing And r e a s Ga l の研究成果 ● コードも書いてる ● 16
  17. 17. 決戦の舞台 V8 ● b r a nc he s /b le e d ing _e d g e r1198 S q uir re lFis h Extre me ● t r unk r40447 Tr a c e Mo nke y ● hg .m o zilla .o rg /tr a c e m o nke y 24328 スライド作成時の最新版 ※ すべて未リリース 17
  18. 18. 本題 :JavaScript VM の高速化 J a va S c r ip t は遅い。なぜなら・・・ 昔は実装をさぼっていた。 ● うざいポップアップを出せればよかった。 ● g m a il も zo ho もなかった。 ● 言語仕様も割と面倒。 ● でも最近はがんばっている。 ● 最終決戦ですから ! ● 今日のテーマ 18
  19. 19. JSVM 高速化の戦略 J S 言語固有の面倒をとりのぞき、 ● 既存 VM の高速化技法をとりいれる ● J a va , S ma llta lk, Lis p , … ● ウェブアプリのツボをチューンする ● 19
  20. 20. JSVM 高速化の見所3つ J S 言語固有の面倒をとりのぞき、 ● 既存 VM の高速化技法をとりいれる ● J a va , S ma llta lk, Lis p , … ● ウェブアプリのツボをチューンする ● 20
  21. 21. JSVM 高速化の見所3つ+1 J S 言語固有の面倒をとりのぞき、 ● 既存 VM の高速化技法をとりいれる ● J a va , S ma llta lk, Lis p , … ● ウェブアプリのツボをチューンする ● 競合 VM への追従 ● オープンソース+宣伝熱心 ● ∴ノーガードぱくり殴り合い 21
  22. 22. ここからのあらすじ J S 言語固有の面倒 : ● クラスがないのをどうにかする話 既存 VM 技術の応用 : ● メソッド呼び出しの高速化の話 ウェブアプリのツボ : ● 正規表現の高速化の話 どれも三大 VM すべてが実装している ● 激戦区。 22
  23. 23. ここからのあらすじ J S 言語固有の面倒 : ● クラスがないのをどうにかする話 既存 VM 技術の応用 : ● メソッド呼び出しの高速化の話ヘ ∴〠ウェブアプリ固有のホットスポット : ● 正規表現の高速化の話 23
  24. 24. 復習: クラスがあるとどう嬉しい? class Point { public: int x; int y; }; Point *p = new Point(); p->x = 10; p->y = 20; クラスの例 :C+ + 24
  25. 25. こたえ: クラスがあれば構造がわかる クラス=配列 ● (C+ + , J a va 処理系にとって。 ) 構造=メンバ変数の並び ● メンバ変数アクセスが ● 高速! 25
  26. 26. class Point { public: int x; int y; int z; }; .... Point *p = new Point(); p->x = 10; // movl $10, (%eax) p->y = 20; // movl $20, 4(%eax) .... int *q = new int[3]; // movl $10, (%eax) q[0] = 10; // movl $20, 4(%eax) q[1] = 20; 26
  27. 27. Point @ JavaScript function Point(x0, y0) { this.x = x0; this.y = y0; } … var p = new Point(10, 20); 27
  28. 28. Point @ JavaScript function Point(x0, has_y, y_or_z) { this.x = x0; if (has_y) { // 実行時にプロパティが変わる! this.y = y_or_z; // y プロパティができる } else { this.z = y_or_z; // z プロパティができる } } オブジェクトにクラスがない ● =プロパティに制限がない =構造が事前に決まらない 28 配列にはできそうもない・・・ ●
  29. 29. JS のオブジェクトはハッシュ表 素朴な ヘ ∴〠プロパティアクセス=ハッシュ表検索 ● ハッシュ表は遅いらしい ● 29
  30. 30. ベンチマーク : 配列 vs. ハッシュ表 in C++ int benchmark(bool use_hash) { const int NELEM = 100; if (use_hash) { std::tr1::unordered_map<int, int> obj; for (int i=0; i<NELEM; ++i) { obj[i] = i; } for (int i=0; i<NELEM*NELEM*NELEM; ++i) { int x = obj[i%NELEM]; touch(x); } } else { int obj[NELEM]; for (int i=0; i<NELEM; ++i) { obj[i] = i; } for (int i=0; i<NELEM*NELEM*NELEM; ++i) { int x = obj[i%NELEM]; touch(x); } } } int touch(int x) { volatile int y = x; } 30
  31. 31. ベンチマーク結果 hash array 0 5 10 15 20 25 30 35 40 短い方が高速(横軸は実行時間) 7倍遅い! ● クラスがないオブジェクトはハッシュ表 ● →なんとかしたい。 31
  32. 32. 洞察: 大半はいつも同じだよね? function Point(x0, has_y, y_or_z) { this.x = x0; ↑ こんなことしないよね? if (has_y) { // 実行時にプロパティが変わる! this.y = y_or_z; } else { this.z = y_or_z; } } 32
  33. 33. アイデア: 仮のクラスを割り振ってみる var p = new Point(); p.x = 10; p.y = 20; ※ クラスが構造を知っている 33
  34. 34. 別の構造には別のクラスを・・・ var q = new Fullname(); q.first = “Jose”; q.middle = “Luis”; q.last = “Carol” 34
  35. 35. 同じ構造には同じクラスを・・・ var p1 = new Point(); p1.x = 10; p1.y = 20; var p2 = new Point(); p2.x = 10; p2.y = 20; 35
  36. 36. 途中で構造が変わったら? … var p1 = new Point(); p1.x = 10; p1.y = 20; var p2 = new Point(); p2.x = 10; p2.y = 20; 30; // 仮クラスの構造にあわない! p2.z = 36
  37. 37. あとから新しいクラスが派生 37
  38. 38. JSVMs には 仮のクラスを類推するしくみがある プログラム実行時に 同じ構造のオブジェクトに同じクラスを ● 違う構造のオブジェクトに違うクラスを ● 割り振る。→オブジェクトの構造がわかる 構造が変わるとクラスも変わる。 ● J S プログラマからクラスはみえない。 ● 高速化のトリック。 ● 38
  39. 39. 各 VM 上での名前 V8 では ● Hidden Class Tr a c e Mo nke y では ● Shape Inf erence S q uir re lFis h Extre me では ● Structure Chain どれもだいたい同じもの。 ● 歴史の長さは TM > V8 > S FX ● 39
  40. 40. VM 実装毎のこまかな違い コンストラクタは違うけど ● プロパティが同じときは? function A(x0, y0) { this.x = x0; this.y = y0; } function B(x0, y0) { this.x = x0; this.y = y0; } オブジェクトリテラルの扱いは? ● function make_a(x0, y0) { return { x:x0, y:y0 }; } 40
  41. 41. クラスができた。次は・・・ 41
  42. 42. ここからのあらすじ J S 言語固有の面倒 : ● クラスがないのをどうにかする話 ( 済 ) 既存 VM 技術の応用 : ● メソッド呼び出しの高速化の話ヘ ∴〠ウェブアプリ固有のホットスポット : ● 正規表現の高速化の話 42
  43. 43. ここからのあらすじ J S 言語固有の面倒 : ● クラスがないのをどうにかする話 ( 済 ) 既存 VM 技術の応用 : ● メソッド呼び出しコードの高速化の話 ヘ ∴〠JIT が生成する ウェブアプリ固有のホットスポット : ● 正規表現の高速化の話 43
  44. 44. 復習 (1/3): JIT て何だっけ? 高級言語のプログラムを ● 実行時に機械語へ変換する高速化 実行時= J us t In Tim e ● 具体的には ● J a va S c r ip t VM のバイトコードを 機械語に変換すること 44
  45. 45. JIT 前(インタプリタ) ここがバイトコード while (true) { switch(instructions[pc++]) { case OP_XXX: do_xxx(); // ほんとはインライン break; case OP_YYY: do_yyy(); break; .... } } 45
  46. 46. JIT 後(生成された機械語) do_xxx(); do_yyy(); do_zzz(); .... 生成される機械語の疑似コード 46
  47. 47. JIT の利点と制限 インタプリタのオーバーヘッドがなくなる ● while(true) instructions[pc++] ● break; ● 個々のバイトコード実装は速くならない。 例:メソッド呼び出し 遅い命令を速くする工夫が必要。 ● 実行時にコードを出力できる ● 実行結果を利用した高速化ができる ● 47
  48. 48. 復習 (2/3): JS のメソッド呼び出し function Greeting() { this.hello = function() { alert(quot;hello!quot;); }; } var g = new Greeting(); g.hello(); 48
  49. 49. 復習 (2/3): JS のメソッド呼び出し function Greeting() { this.hello = function() { alert(quot;hello!quot;); }; } / / プロパティをとりだして / / t h is つきで呼ぶのと同じ。 var g = new Greeting(); g.hello(); var gh = g.hello; gh.apply(g); 49
  50. 50. 復習 (2/3): JS のメソッド呼び出し ↓ プロパティ取得を速くしたい var gh = g.hello; gh.apply(g); 50
  51. 51. 復習 (3/3) JS は動的型付けの言語 動的型付けの言語では ● プロパティの取得が遅いらしい でも ● 構造がわかれば速いんでしょ? 仮クラスによって ● オブジェクトにはクラスができた 51
  52. 52. 復習 (3/3) の前に・・・ C++ は静的型付けの言語 変数にクラスがある。 ● int lengthSquared(Point p) { int x = p.x; int y = p.y; int xx = x*x; int yy = y*y; int ret = xx + xx; return ret; } 52
  53. 53. クラスがある=構造がわかる int lengthSquared(Point p) { // pushl %ebp // movl %esp, %ebp int x = p.x; // movl 12(%ebp), %edx ← 構造がわかるから 1命令でアクセスできる int y = p.y; // movl 8(%ebp), %eax // leave int xx = x*x; // imull %edx, %edx int yy = y*y; // imull %eax, %eax int ret = xx + xx; // addl %edx, %eax return ret; // ret 53 }
  54. 54. 復習 (3/3) JS は動的型付けの言語 // x と y がプロパティ function Point(x0, y0) { this.x = x0; this.y = y0; } // name と x と y がプロパティ function Item(name, x0, y0) { this.name = name; this.x = x0; this.y = y0; } 構造の違う二つのコンストラクタがあって・・・ 54
  55. 55. 復習 (3/3) JS は動的型付けの言語 ? // p のクラスはなに? function lengthSquared(p) { return p.x*p.x + p.y*p.y; ? } var pt = new Point(10, 20); var ptlensq = lengthSquared(pt); var it = new Item(quot;yakusouquot;, 10, 20); var itlensq = lengthSquared(it); 55
  56. 56. 動的型付けの言語は 変数にクラス指定がない オブジェクトごとのクラスはわかっても ● 変数のクラスは ( 調べるまで ) わからない 構造を仮定した高速化ができない ● 動的型付け言語一般の問題 ● J a va S c r ip t だけじゃない。 ● 56
  57. 57. JS のプロパティアクセスは 素朴な 結局ハッシュ表検索 (+ 配列アクセス) // 等価な C++ 風コード // JS var x = p.x; Object* x = p->getProperty(X_NAME_ID); ... Object* Object::getProperty(int id) { Hash* h = this->klass->m_propHash; int index = h->lookup(id); Property* p = this->prop_array; return p[index]; } 57
  58. 58. クラスのハッシュ表から ● 構造を検索して 検索結果を使い ● プロパティ配列にアクセス 58
  59. 59. 洞察 : だいたい同じクラスを使うよね? function lengthSquared(p) { // 長さの二乗 return p.x*p.x + p.y*p.y; } var pt = new Point(10, 20); var it = new Item(quot;yakusouquot;, 10, 20); // こっちが大半で for (var i=0; i<100; i++) { var point_len = lengthSquared(pt); } // こっちはたまにだよね? var item_len = lengthSquared(it); 59
  60. 60. アイデア : よく使うクラスに特化してみる // 等価な C++ 風コード // JS var x = p.x; if (p->klass == PointClass) { // クラスを調べて、 // よく使うクラスなら速く return Point_GetX((int*)p); } else { return p->getProperty(...); } … Object* Point_GetX(int* p) { // 生成する return p[1]; // 構造を知っている! } 60
  61. 61. コード ... if (p ->k lass = Po in t Class) p ->Get Pr o p er t y () Po in t _Get X ((in t *)p ) コード ... 61
  62. 62. コード ... よく使う型か? 型を仮定しない 型を仮定した速いコード ! 遅いコード ... コード ... 62
  63. 63. 予想が間違っていたら? var pt = new Point(10, 20); var it = new Item(quot;yakusouquot;, 10, 20); for (var i=0; i<100; ++i) { var p0lensq = lengthSquared(pt); } // こっちはたまにだよね?こっちがメインだった・・・ for (var i=0; i<100000; ++i) { var p1lensq = lengthSquared(it); ... } 63
  64. 64. 元のコードを書き換える ! // 等価な C++ 風コード // JS var x = p.x; if (p->klass == PointClass ItemClass) { return Point_GetX((int*)p); return Item_GetX((int*)p); } else { return p->getProperty(...); } … Object* Item_GetX(int* p) {// 新たに生成 return p[2]; } 64
  65. 65. コード ... よく使う型 ' か? よく使う型か? 型を仮定しない 型を仮定した速いコード !! 型 ' を仮定した速コード 遅いコード ... コード ... 65
  66. 66. JSVMs は 投機的な型付きコードを生成する ある型専用のコードを生成しておき、 ● オブジェクトの型をチェックしてから、 ● そのコードを呼び出す仕組み ● 適用箇所 プロパティアクセス ● そのあとのメソッド呼び出し ● 四則演算 ● 66
  67. 67. 四則演算の例 // 等価な C++ 風コード // JS a + b; if (ClassOf(a) == IntClass && ClassOf(b) == IntClass) { return ((int)a) + ((int)b); } else if (ClassOf(a) == StringClass && ClassOf(b) == StringClass) return ((String*)a)->concat((String*)b); } else { return SlowAdd(a, b); } 67
  68. 68. 各 VM 上での名前 V8 , S q uir r e lFis h Ext r e m e では ● Po ly m o r p h ic In lin e Cac h in g SELF 言語由来 ● J a va Hotspot VM でも利用 ● Tr a c e Mo nke y では ● Tr ac e Tr ee J a va Hotpath Re s e a r c h VM 由来 ● Tr a c ing 自体は Dynamo VM 由来 ● コアのアイデアはよく似ている ● 実現方法はちょっと違う 68 ●
  69. 69. Polymorphic Inline Caching コードの中 (Inline ) に ● 比較用のクラスを保存する (Ca c hing ) 一つ以上のクラス (Po lym o r p hic ) を ● 保存する if (p->klass == ItemClass) { return Item_GetX((int*)p); } else if (p->klass == PointClass) { return Point_GetX((int*)p); } else { return p->getProperty(...); } 69
  70. 70. Tracing Tree バイトコードを実行しながら (Tr a c ing ) ● ひとつながりのネイティブコードを生成 コードがインライン化される ● ( メソッド呼び出しもインライン化 ) 生成されたコード片は合流しない (Tr e e ) ● if (p->klass == ItemClass) { return [(int*)p][2]; // inlined! } else { ... } 70
  71. 71. // 設定切替 ベンチマーク var mono = false; var n = 10000; var arr = []; for (var i=0; i<n; ++i) { if (mono) { arr.push(new Point(i, i)); mono } else { poly arr.push((i%2) ? new Point(i, i) : new Item(quot;itemquot;, i, i)); } } for (var i=0; i<n; ++i) { for (var j=0; j<n; ++j) { lengthSquared(arr[j]); } 71 }
  72. 72. ベンチマーク結果 V8 SFX mono poly TM 0 10 20 30 40 50 60 70 80 短い方が高速(横軸は実行時間) 72
  73. 73. 世間並みになった。次は・・・ 73
  74. 74. ここからのあらすじ J S 言語固有の面倒 : ● クラスがないのをどうにかする話 ( 済 ) 既存 VM 技術の応用 : ● メソッド呼び出しの高速化の話(済) ヘ ∴〠ウェブアプリのツボ : ● 正規表現の高速化の話 74
  75. 75. 復習 (1/2) : 正規表現ってどう実装するの? 二つのアプローチ 状態遷移表を作る路線 ● DFA, NFA, ... ● g r ep , lex , … ● インタプリタを作る路線 ● 構文木、バイトコード、… ● ライブラリではこっちが主流 ● p c r e, 鬼車 , ORO, JDK , … JS もこっちが多かった (PCRE 採用など ) ● 75
  76. 76. 復習 (2/2): インタプリタの高速化といえば? これまでさんざん話してきましたが ... 76
  77. 77. アイデア : 正規表現も JIT したら? 最終決戦だし。 パース→バイトコード→機械語生成 ● 77
  78. 78. JSVMs には 正規表現の JIT コンパイラがある ただし すべてが J IT されるわけではない。 ● がんばり具合は各社各様。 V8 : regexp2000 ブランチがマージされた ● S FX: 最初から搭載 ● TM: サポート弱め ● 各プロジェクト絶賛開発中 ● 78
  79. 79. ベンチマーク結果 sunspider/regexp-dna.js V8(JIT) V8(NOJIT) SFX TM 0 0.5 1 1.5 2 2.5 3 3.5 短い方が高速(横軸は実行時間) 79
  80. 80. 3つの見所まとめ クラスがない J S の制限を乗り越える ● 仮クラス割り振りの仕組み 既存の VM 技術を適用した ● 投機的な型付きコード生成の仕組み ウェブアプリのホットスポット ● 正規表現の J IT 化 は、3大 VM すべてが実装。でも 実装のがんばりには差がある。 ● 80
  81. 81. 今日でてこなかった話 VM っぽい高速化 ● GC (コピーなんとか、世代なんとか・・・) ● 命令セット(粒度、レジスタ vs スタック) ● ネイティブコード呼び出し ● コンパイラっぽい高速化 ● レジスタ割当 ● 共通部分式の除去 ● ・・・ ● 81
  82. 82. 今後の見所 ブラウザを含めたアプリの総合性能 ● FF1 1 ベンチ → g m a il ベンチ ● モバイル機器での性能 ● 消費メモリ ● ARM CPU 向けの高速化 ● Int e rne t Exp lo re r の動向 ● 今は遅すぎて話題にすらならず。 ● 82
  83. 83. 観戦 HOWTO とりあえずコードを読んでみよう ● コア部分は 1 -2 万行程度 ● 元ねたの論文を探して読もう ● 大抵コードよりわかりやすい ● プロジェクトのブログを読もう ● Mo zilla , We b kit, Chr o m e すべてあり ● 開発者自身のブログもあり ● 開発記録を読もう ● ChangeLog 、 M L 、バグトラッカー ● 新機能もバグトラックで管理するのが定石 ● 83
  84. 84. ブラウザ J a v a Sc r ip t 高速化 J IT バトル最終決戦 観戦ガイド ご清聴ありがとうございました。 84
  85. 85. 写真たち htt p ://f ic kr.c o m /p ho to s /d c jo hn/2 4 4 0 1 7 8 8 0 1 / l ● htt p ://f ic kr.c o m /p ho to s /s ri-h/2 8 6 6 4 5 8 7 4 7 / l ● htt p ://f ic kr.c o m /p ho to s /7 1 5 0 2 6 4 6 @ N0 0 /2 7 7 6 9 0 1 8 2 2 / l ● htt p ://f ic kr.c o m /p ho to s /a llis o nje nning s /2 5 0 3 4 1 0 2 1 3 / l ● htt p ://f ic kr.c o m /p ho to s /g r e e nmys t/1 4 6 8 7 6 0 7 9 1 / l ● 85
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×