# HG changeset patch # User Takahiro SHIMIZU # Date 1530020486 -32400 # Node ID 32e35be2ce712777813b547f5f5bc269fef3d2a5 # Parent 8972d59ad904b1046cd16beec61970509fe5f361 auto-Update generated slides by script diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/05/memo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/05/memo.txt Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,56 @@ +MoarVMが実際にインタプリタとして走っているのはMVM_interp_runという関数らしい. +これはスレッド毎に用意されるらしい + +定義自体は `src/core/interp.c`に書かれている + + MVMInstancとかいう構造体に全ての情報が入っている + + MVM_cu_map_from_fileでスレッド情報とファイルから生成した結果をMVMCompUnit構造体として生成している + + DISPATCHでNEXT_OPを判断している,これはオペランドリストとswitch文が同じオーダーで書かれているので + 最適化しやすいらしい + + MVM_interp_runの後DISPATCHというマクロでNEXT_OPというマクロに応じて処理を行っているが + これがMoarVMのバイトコードを一対一対応しているので5000行のcase文が生成されている + + --- + +- Ruby のJITはunreadableなので,とりあえずCbCで実装しても良いのでは +- ()の中にいるなどの情報 +- コンパイラをデーモン化してオブジェクトファイルなどを共通化 +- パースの並列化 + - パースに当てられる箇所 +- gccのパスは50個くらい,その内の1つがパーサーっぽい + +- FileIOを食う例題とFileIOを食わないでCPUを食う例題 + - HTMLジェネレーターとかでも良いのでは + +- Perl5 to Perl6的なのは無い? +- Rustのメモリ管理周り + +- Perl5との互換性? + - JIT + - MoarVM ByteCode + +- 実測する!!! +- Perl5からMoarVMに変換するスクリプトを作成する!? + - JIT + - 並列処理 + - パイプライン処理(コンパイラ) + - 前段の処理を止めないといけない + - 1つのコンパイラがCPUを異常に使うと帰って遅くなるのでは?? +- ローカルな作業を分割しても全体としては遅くなるのでは? +- JIT + +- アプリケーションをCbCで書く +- それが早くなるまでチューニングする + - 最初はコンパイルしちゃって良いのでは? + - いきなりCbCを吐く感じにする +- (いかに早い正規表現を書くか) + +- 作った文だけメモリをallocateして返却しない(linear memory) + - 一旦メモリを保存させて渡す(OBject table, OBlist) + - Copying GC conversation + - incrementalに出来ない為,中途半端にコピーされた状況になる可能性がある + - 1MBのファイルを読み込んで処理するレベルではGCがそんなに走らないので無視しても良いのでは…!? + - GC memory allocate diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/05/slide.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/05/slide.md Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,56 @@ +title: CbCによるMoarVMの改良 +author: Takahiro Shimizu +profile: +lang: Japanese + + +# 研究目的 +- Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. +- Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. +- 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. +- さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. +- この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う +- CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する + +# 今週の進捗 + +* 仙台行ってきました +* Perl6のプロファイラと巨大なcase文を発見しました + + +# RubyKaigi + +* Rubyの言語自体の話が多かったです +* 型とJITと処理系のトークが多かったです + * ついにRubyもASTを操作出来る用になりました + * Ruby3ではGuildという実装でより簡単な並列化もサポートしていくそうです +* JITに関してはRubyのJITは一度Cに変換するらしいです + * Cコードで拡張を書いてJITするよりRubyをJITした方が現段階では早いらしい + * C language is dead +* ぱるすさんと宮國さん(gongo)さんとエンカウントしました +* Rubyのコードも比較で読んでいます + + +# プロファイラ + +nqpで実行する際に `--prpfile` を指定するとhtmlでプロファイル結果が生成される + +- `./nqp --profile examples/hello_world.nqp` + - 最適化 +- `./nqp --profile-compile examples/hello_world.nqp` + - 最適化される + +# MoarVMの処理 + +- MVMInstancとかいう構造体に全ての情報が入っている +- MoarVMが実際にインタプリタとして走っているのは`MVM_interp_run`という関数らしい. + - これはスレッド毎に用意されるらしい +- 定義自体は `src/core/interp.c`に書かれている +- `MVM_interp_run`の後DISPATCHというマクロで`NEXT_OP`というマクロに応じて処理を行っている + - これはオペランドリストとswitch文が同じオーダーで書かれているので最適化しやすいらしい +- これがMoarVMのバイトコードを一対一対応しているので5000行のcase文が生成されている +- 状態遷移自体はgotoで書かれているがかなりの量を動いており探しづらい + +# OSC + +* **特に何もしてない!!** diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/05/zip.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/05/zip.txt Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,187 @@ +2018-05-29---- + ❯ lldb -- /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar nqp.moarvm examples/hello_world.nqp [13:52:54] +(lldb) target create "/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar" +Current executable set to '/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar' (x86_64). +(lldb) settings set -- target.run-args "nqp.moarvm" "examples/hello_world.nqp" +(lldb) b add_bb_facts +Breakpoint 1: where = libmoar.dylib`add_bb_facts + 32 at facts.c:362, address = 0x0000000000118540 +(lldb) c +error: invalid process +(lldb) run +Process 8479 launched: '/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar' (x86_64) +Process 8479 stopped +* thread #2, stop reason = breakpoint 1.1 + frame #0: 0x00000001001bb540 libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:362 + 359 MVMint32 i, is_phi; + 360 + 361 /* Look for instructions that provide or propagate facts. */ +-> 362 MVMSpeshIns *ins = bb->first_ins; + 363 while (ins) { + 364 /* See if there's deopt and logged annotations. Sync cur_deopt_idx + 365 * and, for logged+deopt-one, add logged facts and guards. */ +Target 0: (moar) stopped. +(lldb) bt +* thread #2, stop reason = breakpoint 1.1 + * frame #0: 0x00000001001bb540 libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:362 + frame #1: 0x00000001001bb503 libmoar.dylib`MVM_spesh_facts_discover(tc=0x0000000100802e30, g=0x0000000100f4efe0, p=0x0000000100f514d0) at facts.c:659 + frame #2: 0x00000001001b4eb7 libmoar.dylib`MVM_spesh_candidate_add(tc=0x0000000100802e30, p=0x0000000100f514d0) at candidate.c:61 + frame #3: 0x00000001001cf991 libmoar.dylib`worker(tc=0x0000000100802e30, callsite=0x00000001006c9150, args=0x0000000000000000) at worker.c:16 + frame #4: 0x000000010014e8e2 libmoar.dylib`invoke_handler(tc=0x0000000100802e30, invokee=0x0000000102014840, callsite=0x00000001006c9150, args=0x0000000000000000) at MVMCFunction.c:9 + frame #5: 0x00000001000e8494 libmoar.dylib`thread_initial_invoke(tc=0x0000000100802e30, data=0x0000000100802050) at threads.c:59 + frame #6: 0x00000001000aefee libmoar.dylib`MVM_interp_run(tc=0x0000000100802e30, initial_invoke=(libmoar.dylib`thread_initial_invoke at threads.c:50), invoke_data=0x0000000100802050) at interp.c:93 + frame #7: 0x00000001000e7a35 libmoar.dylib`start_thread(data=0x0000000100802050) at threads.c:87 + frame #8: 0x00007fff7b9fe661 libsystem_pthread.dylib`_pthread_body + 340 + frame #9: 0x00007fff7b9fe50d libsystem_pthread.dylib`_pthread_start + 377 + frame #10: 0x00007fff7b9fdbf9 libsystem_pthread.dylib`thread_start + 13 + +(lldb) n +Process 8479 stopped +* thread #2, stop reason = step over + frame #0: 0x00000001001bb579 libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:370 + 367 MVMSpeshAnn *ann_deopt_one = NULL; + 368 MVMSpeshAnn *ann_logged = NULL; + 369 MVMint32 is_deopt_ins = 0; +-> 370 while (ann) { + 371 switch (ann->type) { + 372 case MVM_SPESH_ANN_DEOPT_ONE_INS: + 373 ann_deopt_one = ann; +Target 0: (moar) stopped. +(lldb) +Process 8479 stopped +* thread #2, stop reason = step over + frame #0: 0x00000001001bb620 libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:385 + 382 } + 383 ann = ann->next; + 384 } +-> 385 if (ann_deopt_one && ann_logged) + 386 log_facts(tc, g, bb, ins, p, ann_deopt_one, ann_logged); + 387 + 388 /* Look through operands for reads and writes. */ +Target 0: (moar) stopped. +(lldb) l + 389 is_phi = ins->info->opcode == MVM_SSA_PHI; + 390 for (i = 0; i < ins->info->num_operands; i++) { + 391 /* Reads need usage tracking; if the read is after a deopt point + 392 * relative to the write then give it an extra usage bump. */ + 393 if ((is_phi && i > 0) + 394 || (!is_phi && (ins->info->operands[i] & MVM_operand_rw_mask) == MVM_operand_read_reg)) { + 395 MVMSpeshFacts *facts = &(g->facts[ins->operands[i].reg.orig][ins->operands[i].reg.i]); +(lldb) l + 396 facts->usages += facts->deopt_idx == cur_deopt_idx ? 1 : 2; + 397 } + 398 + 399 /* Writes need the current deopt index and the writing instruction + 400 * to be specified. A write that's on a deopt instruction bumps + 401 * the usage too. */ + 402 if ((is_phi && i == 0) +(lldb) n +Process 8479 stopped +* thread #2, stop reason = step over + frame #0: 0x00000001001bb65b libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:389 + 386 log_facts(tc, g, bb, ins, p, ann_deopt_one, ann_logged); + 387 + 388 /* Look through operands for reads and writes. */ +-> 389 is_phi = ins->info->opcode == MVM_SSA_PHI; + 390 for (i = 0; i < ins->info->num_operands; i++) { + 391 /* Reads need usage tracking; if the read is after a deopt point + 392 * relative to the write then give it an extra usage bump. */ +Target 0: (moar) stopped. +(lldb) p MVM_SSA_PHI +error: use of undeclared identifier 'MVM_SSA_PHI' +(lldb) nexr +error: 'nexr' is not a valid command. +error: Unrecognized command 'nexr'. +(lldb) n +Process 8479 stopped +* thread #2, stop reason = step over + frame #0: 0x00000001001bb677 libmoar.dylib`add_bb_facts(tc=0x0000000100802e30, g=0x0000000100f4efe0, bb=0x0000000102115e00, p=0x0000000100f514d0, cur_deopt_idx=-1) at facts.c:390 + 387 + 388 /* Look through operands for reads and writes. */ + 389 is_phi = ins->info->opcode == MVM_SSA_PHI; +-> 390 for (i = 0; i < ins->info->num_operands; i++) { + 391 /* Reads need usage tracking; if the read is after a deopt point + 392 * relative to the write then give it an extra usage bump. */ + 393 if ((is_phi && i > 0) +Target 0: (moar) stopped. +(lldb) p is_phi +(MVMint32) $14 = 0 +(lldb) p ins +(MVMSpeshIns *) $15 = 0x0000000102115e60 +(lldb) p *ins +(MVMSpeshIns) $16 = { + info = 0x00000001005757c0 + operands = 0x0000000000000000 + prev = 0x0000000000000000 + next = 0x0000000000000000 + annotations = 0x0000000000000000 +} +(lldb) p *ins->info +(MVMOpInfo) $17 = { + opcode = 0 + name = 0x00000001002def92 "no_op" + mark = { + [0] = ' ' + [1] = ' ' + } + num_operands = 0 + pure = '\0' + deopt_point = '\0' + logged = '\0' + no_inline = '\0' + jittivity = '\0' + uses_hll = '\0' + operands = ([0] = '\0', [1] = '\0', [2] = '\0', [3] = '\0', [4] = '\0', [5] = '\0', [6] = '\0', [7] = '\0') +} + + +* profilingの箇所を見ていく + +* perlスクリプトをperl6に移植する +* markdownのparserみたいなのを書き換えてみるなど +* タイトループを早くするのか,ここのハッシュを早くするのか,オブジェクトのオペレーションを早くするのか… +* 手近な場所をとにかく見ていきたい + +* native codeをやるのかvmをやるのか + +* bytecode interpureter, gc関連を書き直すという手もある + +* gcc vs clang + +* llvm側でtail coll呼び出す時はフラグを見ている + * code grarであるというフラグを渡している感じ + +* script言語--> 上手く並列化出来ない + +* targetとしてCbCのコードを吐く + * 継続コード(meta level) + * 継続コードを見て計算結果を見て変えていく + * MoarVMのJIT,nqpのコンパイラにcbcを生成する部分を入れる + * perlccみたいなものをいれる + * targetのアプリケーション...whileでstring matchをする部分を最適化する + +* 正規表現の箇所をターゲットとして書くのも手…!? + * fileをmmapを使うかどうかなど +* 並列のgrep + * 早くなるには早くなる + * cache prefetchの処理でも高速化出来る + + +---------- +2018-06-05---- +MoarVMが実際にインタプリタとして走っているのはMVM_interp_runという関数らしい. +これはスレッド毎に用意されるらしい + +定義自体は `src/core/interp.c`に書かれている + + MVMInstancとかいう構造体に全ての情報が入っている + + MVM_cu_map_from_fileでスレッド情報とファイルから生成した結果をMVMCompUnit構造体として生成している + + DISPATCHでNEXT_OPを判断している,これはオペランドリストとswitch文が同じオーダーで書かれているので + 最適化しやすいらしい + + MVM_interp_runの後DISPATCHというマクロでNEXT_OPというマクロに応じて処理を行っているが + これがMoarVMのバイトコードを一対一対応しているので5000行のcase文が生成されている + + +---------- diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/12/memo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/12/memo.txt Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,29 @@ +javaのreflection + +explation handling + +* 自分がどこにいるのかわかるためにサブルーチンコール +* とっかかりは見つけたい +* MoarVM自体のパフォーマンスが問題では...!? + +* Javaの高速化Inline展開 +* Javaverで動かしてみる? + +* コンパイラ書く時 + +--- +* squick + * small talkの再実装 +* golang +* code-segmentをnqpで書いてみるという手もある +* Cのサブルーチンコールを最適化しても上手くはたらかないのでは...!? +* 膨大なライブラリの共有問題 +* 言語のライブラリを共有的にロードするデーモンを作成するという手もありそう + * アムダールの法則 + * Lantime Server or Language Server +* GraalVM + + +--- +* bytecode ではないので可読性がある +* CbCへのJITコンパイルを書くという手もある diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/12/slide.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/12/slide.md Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,69 @@ +title: CbCによるMoarVMの改良 +author: Takahiro Shimizu +profile: +lang: Japanese + + +# 研究目的 +- Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. +- Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. +- 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. +- さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. +- この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う +- CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する + +# 今週の進捗 +* Perl5のプロファイラを用意 + * ついでにPerl5もlldbで追ってみていました +* nqpのメソッド一覧を発見しました +* nqpでプログラミングの為にテキスト読んでいます + +# nqp +* [Opcode list](https://github.com/perl6/nqp/blob/master/docs/ops.markdown)を見つける + * 謎だったメソッド周りが定義 + * `nqp::`にメソッドが生えているのでこれを使う + +# Perl5 + +## Profiler +* 最近は `Devel::NYTProfile` が良いらしい + * `cpanm Devel::NYTProfile` + +``` +perl -d:NYTProfile hoge.pl +nytptofhtml --open +``` + +## lldb + +* git clone git@github.com:Perl/perl5.git +* ./Configure -DDEBUGGING=-g -Doptimize=-O0 +* 中々難解であまり良くわからなかった… + +# NQP +* moarVMのプロファイラを利用可能 + * 他のプロファイラに関しては[Wanted Modules](https://github.com/perl6/perl6-most-wanted/blob/master/most-wanted/modules.md)にも書かれているのでおそらく無い… +* `nqp::time_n()`でnqpで時間が計測出来るのでこれを使うのも単純には良さそう +* 残りは[スライド](http://edumentab.github.io/rakudo-and-nqp-internals-course/slides-day1.pdf)読み勧めてました + +# NQPの文法 + +* Perl6のベースなので制約がわりと多い +* 基本束縛で変数を定義していく + * `my $hoge := "foo";` +* 配列のpop/pushは専用のメソッドを経由して行う + +``` +my @hoge := ('1','2','3'); +nqp::push(@hoge,4); +``` + +# 今週のTODO + +* 評価用のプログラムを作成 + * 極力モジュールを使わない +* NQPで一回書くかどうか +* CbCをJITで吐き出したいのでJITの調査 + * 確かLuaJitを使っていたような… + * [YouTube](https://www.youtube.com/watch?v=N5_drt7TEqE) + * [Controlled Stack Hacking for the MoarVM JIT Compiler](http://brrt-to-the-future.blogspot.com/2018/06/controlled-stack-hacking-for-moarvm-jit.html) diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/14/memo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/14/memo.txt Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,24 @@ +RakudoのBuild + + +./Configure.pl --prefix=/Users/anatofuz/workspace/cr/Basic/build_perl6 --backends=moar --with-nqp=//Users/anatofuz/workspace/cr/Basic/build_perl6/bin/nqp + +謎のシェルスクリプトが生成されている + +``` +#!/bin/sh +/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar --execname="$0" --libpath="." --libpath="blib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" /Users/anatofuz/workspace/cr/Basic/perl6/MoarVM_basic/rakudo/perl6.moarvm --nqp-lib=blib -e ' +say "=" x 96; + +say "This is Rakudo Perl 6 running in the LLVM debugger, which often allows the user to generate useful back-\ntraces to debug or report issues in Rakudo, the MoarVM backend or the currently running code.\n"; + +unless $*VM.config { say "The currently used MoarVM backend is not compiled with debugging symbols, you might want to\nreconfigure and reinstall MoarVM with --debug enabled.\n" } + +say "This Rakudo version is $*PERL.compiler.version() built on MoarVM version $*VM.version(),"; +say "running on $*DISTRO.gist() / $*KERNEL.gist()\n"; + +say "Type `bt full` to generate a backtrace if applicable, type `q` to quit or `help` for help."; + +say "-" x 96;' +lldb /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar -- --execname="$0" --libpath="." --libpath="blib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" /Users/anatofuz/workspace/cr/Basic/perl6/MoarVM_basic/rakudo/perl6.moarvm --nqp-lib=blib "$@" +``` diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/23/slide.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/23/slide.md Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,28 @@ +title: CbCによるMoarVMの改良 +author: Takahiro Shimizu +profile: +lang: Japanese + +!SLIDE +## SSID + +`perl-entrance` + +## PW + +`metacpan` + +# 研究目的 +- Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. +- Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. +- 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. +- さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. +- この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う +- CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する + +# 今週の進捗 +* foo + * puyohoge + +# 来週の予定 + diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/26/memo.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/26/memo.txt Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,14 @@ +JIT読むなら + +byte codeからネイティブを生成してメモリにかきこむところ + +データ領域のものを実行するのはOSが禁止しているのでそこを得部分 + +JITがはしった後VMに戻ってくる箇所 +(おそらくreturn) + +fpr フローティングポイント + +コード生成し終わった後に呼び出す箇所をリンクしているのでは139 + +enter_code diff -r 8972d59ad904 -r 32e35be2ce71 slides/2018/06/26/slide.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/slides/2018/06/26/slide.md Tue Jun 26 22:41:26 2018 +0900 @@ -0,0 +1,319 @@ +title: CbCによるMoarVMの改良 +author: Takahiro Shimizu +profile: +lang: Japanese + + +# 研究目的 +- Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. +- Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. +- 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. +- さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. +- この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う +- CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する + +# 今週の進捗 +* 暑くて死んでました +* OSCの資料をwebにあげました +* Perl6のコンパイルとJITのトレースをしました +* 院試対策し始めてます + +# お知らせ + +* [並列研の公式page](http://www.cr.ie.u-ryukyu.ac.jp/)にスライド置き場を作りました +* CSS力はなかった + + +# Perl6のbuild + +* JITのトレースがしたかったのでPerl6をbuildしました + +./Configure.pl --prefix=/Users/anatofuz/workspace/cr/Basic/build_perl6 --backends=moar --with-nqp=//Users/anatofuz/workspace/cr/Basic/build_perl6/bin/nqp + +# Perl6-lldb-m + +* `Perl6-lldb-m`というデバッグ用のスクリプトが生成されていた + +``` +#!/bin/sh +/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar --execname="$0" --libpath="." --libpath="blib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" /Users/anatofuz/workspace/cr/Basic/perl6/MoarVM_basic/rakudo/perl6.moarvm --nqp-lib=blib -e ' +say "=" x 96; + +say "This is Rakudo Perl 6 running in the LLVM debugger, which often allows the user to generate useful back-\ntraces to debug or report issues in Rakudo, the MoarVM backend or the currently running code.\n"; + +unless $*VM.config { say "The currently used MoarVM backend is not compiled with debugging symbols, you might want to\nreconfigure and reinstall MoarVM with --debug enabled.\n" } + +say "This Rakudo version is $*PERL.compiler.version() built on MoarVM version $*VM.version(),"; +say "running on $*DISTRO.gist() / $*KERNEL.gist()\n"; + +say "Type `bt full` to generate a backtrace if applicable, type `q` to quit or `help` for help."; + +say "-" x 96;' +lldb /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar -- --execname="$0" --libpath="." --libpath="blib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" --libpath="/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" /Users/anatofuz/workspace/cr/Basic/perl6/MoarVM_basic/rakudo/perl6.moarvm --nqp-lib=blib "$@" +``` + +# JITのトレース + +* 何も実行しないとBreakpointに引っかかる + +``` + $ ./perl6-lldb-m +================================================================================================ +This is Rakudo Perl 6 running in the LLVM debugger, which often allows the user to generate useful back- +traces to debug or report issues in Rakudo, the MoarVM backend or the currently running code. + +This Rakudo version is 2018.04.1 built on MoarVM version 2018.04.1, +running on macosx (10.13.5) / darwin (17.6.0) + +Type `bt full` to generate a backtrace if applicable, type `q` to quit or `help` for help. +------------------------------------------------------------------------------------------------ +b (lldb) target create "/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar" +Current executable set to '/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar' (x86_64). +(lldb) settings set -- target.run-args "--execname=./perl6-lldb-m" "--libpath=/Users/anatofuz/workspace/cr/Basic/build_perl6/share/nqp/lib" "--libpath=/Users/anatofuz/workspace/cr/Basic/build_perl6/share/perl6/lib" "--libpath=/Users/anatofuz/workspace/cr/Basic/build_perl6/share/perl6/runtime" "/Users/anatofuz/workspace/cr/Basic/build_perl6/share/perl6/runtime/perl6.moarvm" +(lldb) b MVM_jit_compiler_init +Breakpoint 1: where = libmoar.dylib`MVM_jit_compiler_init + 20 at compile.c:17, address = 0x00000000001e4d54 +(lldb) run +Process 4185 launched: '/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar' (x86_64) +Process 4185 stopped +* thread #2, stop reason = breakpoint 1.1 + frame #0: 0x0000000100287d54 libmoar.dylib`MVM_jit_compiler_init(tc=0x000000010084db80, cl=0x0000700007fa1c60, jg=0x000000010345ca7a) at compile.c:17 + 14 static const MVMuint16 MAGIC_BYTECODE[] = { MVM_OP_sp_jit_enter, 0 }; + 15 + 16 void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitGraph *jg) { +-> 17 MVMint32 num_globals = MVM_jit_num_globals(); + 18 /* Create dasm state */ + 19 dasm_init(cl, 2); + 20 cl->dasm_globals = MVM_malloc(num_globals * sizeof(void*)); +Target 0: (moar) stopped. +``` + +# JIT用のコード + +``` +#!/usr/bin/env perl6 +use v6; + +my @hoge = (1..300); + +sub foo(@a){ + @a[0] = @a.elems; +} + +say foo(@hoge); +``` + + +``` +(lldb) run jit.p6 +Process 4223 launched: '/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/moar' (x86_64) +Unhandled exception: Bytecode stream corrupt (missing magic string) +Process 4223 exited with status = 1 (0x00000001) +``` + +* Bytecode stream corruptのエラーが発生する + +# missing magic string + +* `src/core/bytecode.c` 135行目で定義されているエラーらしい + +``` + /* Dissects the bytecode stream and hands back a reader pointing to the + * various parts of it. */ + static ReaderState * dissect_bytecode(MVMThreadContext *tc, MVMCompUnit *cu) { + MVMCompUnitBody *cu_body = &cu->body; + ReaderState *rs = NULL; + MVMuint32 version, offset, size; + + /* Sanity checks. */ + if (cu_body->data_size < HEADER_SIZE) + MVM_exception_throw_adhoc(tc, "Bytecode stream shorter than header"); + if (memcmp(cu_body->data_start, "MOARVM\r\n", 8) != 0) + MVM_exception_throw_adhoc(tc, "Bytecode stream corrupt (missing magic string)"); + version = read_int32(cu_body->data_start, 8); + if (version < MIN_BYTECODE_VERSION) + MVM_exception_throw_adhoc(tc, "Bytecode stream version too low"); + if (version > MAX_BYTECODE_VERSION) + MVM_exception_throw_adhoc(tc, "Bytecode stream version too high"); + + /* Allocate reader state. */ + rs = (ReaderState *)MVM_calloc(1, sizeof(ReaderState)); + rs->version = version; + rs->read_limit = cu_body->data_start + cu_body->data_size; + cu->body.bytecode_version = version; + + /* Locate SC dependencies segment. */ + offset = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET); + if (offset > cu_body->data_size) { + cleanup_all(tc, rs); + MVM_exception_throw_adhoc(tc, "Serialization contexts segment starts after end of stream"); + } + rs->sc_seg = cu_body->data_start + offset; + rs->expected_scs = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET + 4); + +``` + +# エラーの原因 + +* `memcmp(cu_body->data_start, "MOARVM\r\n", 8) != 0` でMoarVMと文字列比較をしているが,この部分でスクリプトすべてが流れ込んでいた + +``` +(lldb) p *cu_body +(MVMCompUnitBody) $1 = { + data_start = 0x00000001007e5000 "#!/usr/bin/env perl6\nuse v6;\n\nmy @hoge = (1..300);\n\nsub foo(@a){\n @a[0] = @a.elems;\n}\n\nsay foo(@hoge);\n" + data_size = 106 + num_extops = 0 +``` + + +# + +``` +(MVMCompUnitBody) $2 = { + data_start = 0x00000001007e5000 "#!/usr/bin/env perl6\nuse v6;\n\nmy @hoge = (1..300);\n\nsub foo(@a){\n @a[0] = @a.elems;\n}\n\nsay foo(@hoge);\n" + data_size = 106 + num_extops = 0 + max_callsite_size = 0 + coderefs = 0x0000000000000000 + num_frames = 0 + orig_frames = 0 + main_frame = 0x0000000000000000 + load_frame = 0x0000000000000000 + deserialize_frame = 0x0000000000000000 + callsites = 0x0000000000000000 + num_callsites = 0 + orig_callsites = 0 + extops = 0x0000000000000000 + strings = 0x0000000000000000 + num_strings = 0 + orig_strings = 0 + string_heap_fast_table = 0x0000000000000000 + string_heap_fast_table_top = 0 + serialized_size = 0 + string_heap_start = 0x0000000000000000 + string_heap_read_limit = 0x0000000000000000 + serialized = 0x0000000000000000 + scs = 0x0000000000000000 + num_scs = 0 + deallocate = MVM_DEALLOCATE_NOOP + scs_to_resolve = 0x0000000000000000 + sc_handle_idxs = 0x0000000000000000 + hll_config = 0x0000000000000000 + hll_name = 0x0000000000000000 + filename = 0x0000000000000000 + handle = 0x0000000000000000 + inline_tweak_mutex = 0x000000010084e040 + deserialize_frame_mutex = 0x0000000101017900 + bytecode_version = 0 + invoked = '\0' +} +``` + +# cuの生成部分 + +* compunit.cの `MVM_cu_map_from_file`から読んでいる`MVM_cu_from_bytes`で生成している + +``` +(lldb) f +frame #4: 0x00000001000d4238 libmoar.dylib`MVM_cu_map_from_file(tc=0x0000000100802100, filename="jit.p6") at compunit.c:64 + 61 } + 62 + 63 /* Turn it into a compilation unit. */ +-> 64 cu = MVM_cu_from_bytes(tc, (MVMuint8 *)block, (MVMuint32)size); + 65 cu->body.handle = handle; + 66 cu->body.deallocate = MVM_DEALLOCATE_UNMAP; + 67 return cu; +``` + +* 問題となっている箇所はこの時点で `block`に記録されている + + +# blockの生成部分 + +``` + 33 /* Loads a compilation unit from a bytecode file, mapping it into memory. */ + 34 MVMCompUnit * MVM_cu_map_from_file(MVMThreadContext *tc, const char *filename) { + 35 MVMCompUnit *cu = NULL; + 36 void *block = NULL; + 37 void *handle = NULL; + 38 uv_file fd; + 39 MVMuint64 size; +(lldb) + 40 uv_fs_t req; + 41 + 42 /* Ensure the file exists, and get its size. */ + 43 if (uv_fs_stat(tc->loop, &req, filename, NULL) < 0) { + 44 MVM_exception_throw_adhoc(tc, "While looking for '%s': %s", filename, uv_strerror(req.result)); + 45 } + 46 + 47 size = req.statbuf.st_size; + 48 + 49 /* Map the bytecode file into memory. */ +(lldb) + 50 if ((fd = uv_fs_open(tc->loop, &req, filename, O_RDONLY, 0, NULL)) < 0) { + 51 MVM_exception_throw_adhoc(tc, "While trying to open '%s': %s", filename, uv_strerror(req.result)); + 52 } + 53 + 54 if ((block = MVM_platform_map_file(fd, &handle, (size_t)size, 0)) == NULL) { + 55 /* FIXME: check errno or GetLastError() */ + 56 MVM_exception_throw_adhoc(tc, "Could not map file '%s' into memory: %s", filename, "FIXME"); + 57 } + 58 + 59 if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) { +(lldb) + 60 MVM_exception_throw_adhoc(tc, "Failed to close filehandle: %s", uv_strerror(req.result)); + 61 } + 62 + 63 /* Turn it into a compilation unit. */ + 64 cu = MVM_cu_from_bytes(tc, (MVMuint8 *)block, (MVMuint32)size); + 65 cu->body.handle = handle; + 66 cu->body.deallocate = MVM_DEALLOCATE_UNMAP; + 67 return cu; + 68 } +``` + +* 54行目 + +# 生成箇所? + +``` + 63 void *MVM_platform_map_file(int fd, void **handle, size_t size, int writable) + 64 { + 65 void *block = mmap(NULL, size, + 66 writable ? PROT_READ | PROT_WRITE : PROT_READ, + 67 writable ? MAP_SHARED : MAP_PRIVATE, fd, 0); + 68 +(lldb) + 69 (void)handle; + 70 return block != MAP_FAILED ? block : NULL; + 71 } +``` + +# 実際に作成している箇所 + +``` +(lldb) l 10 + 10 MVMCompUnit * MVM_cu_from_bytes(MVMThreadContext *tc, MVMuint8 *bytes, MVMuint32 size) { + 11 /* Create compilation unit data structure. Allocate it in gen2 always, so + 12 * it will never move (the JIT relies on this). */ + 13 MVMCompUnit *cu; + 14 MVM_gc_allocate_gen2_default_set(tc); + 15 cu = (MVMCompUnit *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTCompUnit); + 16 cu->body.data_start = bytes; + 17 cu->body.data_size = size; + 18 MVM_gc_allocate_gen2_default_clear(tc); +``` + +``` + 16 MVMObject * MVM_repr_alloc_init(MVMThreadContext *tc, MVMObject *type) { + 17 MVMObject *obj = REPR(type)->allocate(tc, STABLE(type)); + 18 + 19 if (REPR(obj)->initialize) { + 20 MVMROOT(tc, obj, { + 21 REPR(obj)->initialize(tc, STABLE(obj), obj, OBJECT_BODY(obj)); +(lldb) + 22 }); + 23 } + 24 + 25 return obj; + 26 } +```