Weitere ähnliche Inhalte
Ähnlich wie Perlと出会い、Perlを作る (20)
Perlと出会い、Perlを作る
- 4. アジェンダ
• gperlの概要と性能評価
• 高速化技術あれこれ
• 高速化のために断念したPerlの仕様
• まとめ
- 5. gperlの概要(Speed)
• 導入済みの高速化技術
– asmベースの2番地コード命令
– Register型VM
– Direct Threaded Codeを用いた
高速関数呼び出し
– 引数オブジェクトの事前構築
– NaN-boxingによる型検査
– アノテーションによるStatic Typingの実現
– JIT Compile
- 6. gperlの概要(Syntax)
• サポートされている文法やデータ構造
– データ型 :
int, double, String, Array(Ref), Hash(Ref), CodeRef, B
lessedObject
– ループ: for, while, foreach
– 条件文: if-elsif-else
– 関数呼び出し(再帰処理可)とクラス作成(package)
– 演算子(一部) : +, -, *, /, +=, -=, ++, --
, <<, >>, <, >, <=, >=, !=, ==
– その他: ローカル変数, 複数変数の宣言と代入など
- 7. 性能評価(1/3)
Fibonacci数列の計算
N=35
Language time(real)[sec] X(倍率)
gperl(JIT) 0.10 X91.2
測定環境
LuaJIT(2.0.0-beta10) 0.12 X76.0
v8(0.8.0) 0.18 X50.6 MacOSX(10.7.4)
2.2GHz Intel Core i7
gperl(StaticTyping) 0.44 X20.7 Memory: 8GB
gperl 0.46 X19.8 Darwin Kernel Version
11.4.0 x86_64
Konoha(1.0) 0.52 X17.5
PyPy(1.9.0) 0.53 X17.2
SpiderMonkey(1.8.5) 2.17 X4.2
Lua(5.2.1) 2.82 X3.2 測れるもの
Ruby(1.9.3) 3.65 X2.5
数値演算速度
Python(2.7.3) 4.32 X2.1 関数呼び出し速度
VM設計の良し悪し
Perl(5.16.0) 9.12 X1.0
- 8. 性能評価(2/3)
たらい回し関数の計算
(x,y,z) = (13, 6, 0)
Language time(real)[sec] X(倍率)
gperl(JIT) 0.29 X102.0
測定環境
v8(0.8.0) 0.41 X72.1
LuaJIT(2.0.0-beta10) MacOSX(10.7.4)
0.46 X64.3
2.2GHz Intel Core i7
gperl(StaticTyping) 1.24 X23.9 Memory: 8GB
Darwin Kernel Version
Konoha(1.0) 1.38 X21.4 11.4.0 x86_64
gperl 1.56 X19.0
PyPy(1.9.0)
4.30 X6.9
SpiderMonkey(1.8.5) 5.70 X5.2 測れるもの
Lua(5.2.1) 5.97 X5.0
複数引数の処理
Ruby(1.9.3) 7.63 X3.9 数値演算速度
関数呼び出し速度
Python(2.7.3) 17.18 X1.7 VM設計の良し悪し
Perl(5.16.0) 29.59 X1.0
- 9. 性能評価(3/3)
binary-trees
N=15
Language time(real)[sec] X(倍率)
v8(0.8.0)
0.32 X35.8 測定環境
LuaJIT(2.0.0-beta10) 1.29 X8.9 MacOSX(10.7.4)
Konoha(1.0) 1.46 X7.9 2.2GHz Intel Core i7
Memory: 8GB
PyPy(1.9.0) 1.98 X5.8 Darwin Kernel Version
Python(2.7.3) 2.25 X5.1 11.4.0 x86_64
gperl(Static Typing) 3.97 X2.9
gperl 4.06 X2.8
Ruby(1.9.3) 5.23 X2.2
SpiderMonkey(5.7.3) 5.73 X2.0 測れるもの
Lua(5.2.1) 7.56 X1.5 GCの速度
Perl(5.16.0) 11.47 X1.0
- 12. 引数オブジェクトの事前構築(2/2)
関数呼び出しスタックの一つ一つに対応して
・・・・
関数呼び出しスタック 引数用の配列を事前に作り、引数はそこに積まれる
スタックの伸びる方向
3
4
5
1 :subf {
2 : my $a = $_[0];
2
3
4
引数用の配列 3 : my$b= $_[1];
4 : my$c= $_[2];
1
2
3
5 : if ($a > 10) {
6 : return 1;
7 : }
8 : returnf(++$a, ++$b, ++$c);
9 :}
関数が呼ばれるとstack_topが一つ上がる 10 :f(1, 2, 3);
関数から抜けると一つ下がる
しかしPerlには、引数が一定数以下に抑えられるという常識が通じない
仕様があるため、一筋縄ではいかない =>後述
- 13. NaN-boxingによる型検査(1/2)
• Perlのような動的型付け言語は、変数の型を保
存する仕組みが必要
– 通常は、値(int, double, boolean)であっても、オブ
ジェクトとして扱い、型情報を持たせる(boxing)
– しかしboxingしてあると、計算の時に毎回オブジェク
トから値を取り出す操作(unboxing)が入るため遅い.
また、全てオブジェクトにするためメモリ効率も悪
くなる
case ADD:
structIntObject { Object *a = reg[0];
Object *b = reg[1];
inttype; //型情報 if (a->type == TypeInt&&b->type == TypeInt) {
intdata; //実際の値 ((IntObject *)a)->data += ((IntObject *)b)->data;
}; } else if (a->type == TypeString&&b->type == TypeString) {
……
}
- 14. NaN-boxingによる型検査(2/2)
• NaN-boxingは、double型のNaN領域に型
情報を埋め込む技術
– unboxingと同じように扱えて、型情報も持た
せられる unboxingされている
case ADD: のに型検査できる
union{ switch (typecheck(reg[0], reg[1])) {
intidata; caseInt_Int:
double ddata; reg[0].idata += reg[1].idata;//データに直にアクセスできる
char *sdata; break;
void *odata; case String_String:
}; …..
}
しかしPerlには、関数呼び出し時に渡される変数は全てリファレンス
として扱われるという仕様があるため、一筋縄ではいかない =>後述
- 15. アノテーションによる
Static Typing/JIT Compileの実現
• 大規模開発を行う場合、型は静的に決定できる
場合がほとんど
– 型安全性が損なわれるとバグのもとに
– そもそも、開発するときに型のイメージはあるはず
• 型を静的に決められるケースが多いなら、その
恩恵を受けようじゃないか
– アノテーションを付加することで、静的型付け用の命
令を生成したり, JIT Compileできるようにする
- 16. アノテーションによる
Static Typing/JIT Compileの実現
• 関数の宣言前に、”#@static_typing” or
“#@jit_safe”と記述することで、静的型付け用の命
令やJIT用の命令が生成される
– #~とすることで、Perlとの互換性を保つ
1: #@static_typing
2: subfib {
型が決まらないと処理できない 3: if ($_[0] < 2) {
命令において、 4: return 1;
初めて処理した時に分かった型 5: } else {
を覚えておき、 6: return fib($_[0] - 1) + fib($_[0] - 2);
2回目からは分かった型用の 7: }
命令で処理する 8:}
9:print(fib(35), "n");
- 19. 1.関数引数にあるリストの展開
• Perlでは, 関数の引数にリストがあるときは, 中
身を展開して一つの配列にしてから関数に渡す
– 配列結合のSyntax SugarがPerlでは(@a, @b)で表現
でき、引数では常に有効になる
subf{
my@args= @_;
print $args[0], "n"; # $args[0] == 1
print $args[1], "n"; # $args[1] == 2
}
my@a = (1, 2, 3);
my @b= (4, 5, 6);
f(@a, @b);
- 20. 1.関数引数にあるリストの展開
• gperlではあらかじめ引数の数を想定して引数ス
タックのサイズを決めているため、引数の数が
多いとスタックを拡張しなければならない
gperl内部では@aも一つの
subf{ 配列オブジェクトとして扱わ
my@args= @_; れているため、そのままだと
print $args[0], "n"; # $args[0] == @a $args[0]の値は@aになり、
print $args[1], "n"; # $args[1] == @b $args[1]の値は@bになって
} しまう
my@a = (1, 2, 3);
my @b= (4, 5, 6);
これを簡単に避けるために、
f(@a, @b);
リストを展開・結合したい場
合は、f((@a, @b))のように呼
び出すルールを決めている
- 21. 2.デフォルトでのスカラー変数の
参照渡し
• Perlでは、関数の引数は全て参照渡しになるの
で、明示的にリファレンスにしなくとも、値の
書き変えが可能
subf{ NaN-boxingではこの挙動を
$_[0] = 3; 再現できないため、
} $_[0]には$aの スカラー変数のデフォルトでの
リファレンスが入っ 参照渡しは未サポート
my $a = 1; ているので、値を書
f($a); き変えると元の値も $aを使ってリファレンスを
print $a, "n”; 書き変わる 渡すことを明示すれば、
そのときにboxingを行って対処する
- 22. まとめ
• VM、GCやJITなど、ベースとなる技術の
設計や実装はできてきた
• 今後の予定 (文法や機能の充実)
– 後置文, 三項演算子, format, 正規表現 ,
map/grep, eval, use/FFI, 継承, 括弧の省略など
– ドキュメントの整備
• 研修時に書いたPerlスクリプトがやっと動く
ように・・
– 本当の意味で研修内容を理解できた・・・!?