mruby v1.3

mruby v1.3 がリリースされましたね。

趣味mrubyウォッチャーとしてv1.2からv1.3で何が変わったのかを、個人的にまとめてみたいと思います。

注目すべきは、やはりmatzのcommit数。

もちろんmerge commitも含みますが、約半数のcommitがmatzのcommitになっています。

なぜmatzがここまでmrubyに力を入れるのか聞いてみたいところですね。

それではmruby v1.2 からv1.3への変更で何が変わったのか、ザックリ見ていこうと思います。

リリースノート

http://mruby.org/releases/2017/07/04/mruby-1.3.0-released.html

1年以上あった割には、表向きにはそこまで変化はない感じ? わりと最新のCRubyの文法やメソッドも入っていたりしますね。

Contributions

https://github.com/mruby/mruby/graphs/contributors?from=2015-11-17&to=2017-07-04

v1.2が出た日からv1.3が出た日にしているので若干正確ではないのですが、やはりmatzのcommit数はダントツですね。

Many bug fixes

やはり注目すべきはShopifyからの大量のbug報告と、これら全てを丁寧に対応されたmatzの修正の応酬でしょう。

https://github.com/mruby/mruby/issues?q=is%3Aissue+author%3Aclayton-shopify

SEGVの報告。free後のメモリや、確保した領域外のメモリなど、触れてはいけないメモリを触れてしまっている部分の修正。GCのバグ修正。意図しない無限ループの修正。諸々含めて約200のissueが上げられ、閉じられています。

shopifyとmrubyの関係はbovi氏のblogが詳しい。

The 500.000$ release - mruby.sh

こちらからの目線での印象としては、正直「そんな重箱の隅まで……。」というケースもあったのですが、 ユーザーにコードを書いてもらって実行するようなシステムだと、「ユーザーにシステムを止められるようなコード書かれると困る」というのは分かる話。

おかげでmruby本体が原因でSEGVが起きるようなケースは、重箱の隅を含めてもそう滅多なことでは起こらないようになったんじゃないでしょうか。

mrb_yieldでbreakできない問題

折角なのでどういうbug fixがあったのかひとつ抜き出してみましょう。

この問題が修正されたのは1.3が出る直前のことでした。

v1.2では、実は以下のようなコードはうまく動きません。 breakしているのに、ループが終わらないのです。っていうかSEGVします。

$ mruby-1.2.0
"aaa\nbbb\nccc\n".lines do |line|
  p line
  break
end
#=> "aaa\n"
#=> "bbb\n"
#=> "ccc\n"
[2]    72458 segmentation fault  mruby-1.2.0

これは、Cで実装されたメソッドでmrb_yield系が使われていた場合にbreakを利用すると発生していました。

breakreturnとほぼ同じ扱いにしているので、rubyで書かれたブロックならbreakで以降のコードは飛ばせるのですが、 C側のコードは引き続き実行してしまうのでループを止められないという問題があったようです。

Rubyコード上はbreakしているのに、C側のコードは止められないので不整合が起こり、SEGVしているものと思われます。

この問題はbreakを例外扱いすることでlongjumpし、Cのレベルでもメソッドのコードを飛ばせるように修正されています。

Allow `break` from a block called by `mrb_yield`; close #3359 · mruby/mruby@d4d99dd · GitHub

パフォーマンス

「パフォーマンスは早くなったの?」

ということで、mrubyに添付されているbenchmarkスクリプトで計測してみました。

buildの設定はfull-coreにしただけでその他は初期値です。(OSX 10.12.5 clang v8.1.0)

$ time mruby-1.2.0 benchmark/bm_ao_render.rb > /dev/null
mruby-1.2.0 benchmark/bm_ao_render.rb > /dev/null  20.22s user 1.44s system 98% cpu 21.942 total

$ time mruby-1.3.0 benchmark/bm_ao_render.rb > /dev/null
mruby-1.3.0 benchmark/bm_ao_render.rb > /dev/null  19.74s user 0.11s system 98% cpu 20.134 total

$ time mruby-1.2.0 benchmark/bm_fib.rb > /dev/null
mruby-1.2.0 benchmark/bm_fib.rb > /dev/null  12.32s user 0.03s system 99% cpu 12.387 total

$ time mruby-1.3.0 benchmark/bm_fib.rb > /dev/null
mruby-1.3.0 benchmark/bm_fib.rb > /dev/null  13.33s user 0.05s system 98% cpu 13.529 total

$ time mruby-1.2.0 benchmark/bm_app_lc_fizzbuzz.rb > /dev/null
mruby-1.2.0 benchmark/bm_app_lc_fizzbuzz.rb > /dev/null  37.46s user 0.45s system 98% cpu 38.559 total

$ time mruby-1.3.0 benchmark/bm_app_lc_fizzbuzz.rb > /dev/null
mruby-1.3.0 benchmark/bm_app_lc_fizzbuzz.rb > /dev/null  41.14s user 0.37s system 99% cpu 41.850 total

$ time mruby-1.2.0 benchmark/bm_so_lists.rb > /dev/null
mruby-1.2.0 benchmark/bm_so_lists.rb > /dev/null  5.90s user 0.17s system 97% cpu 6.197 total

$ time mruby-1.3.0 benchmark/bm_so_lists.rb > /dev/null
mruby-1.3.0 benchmark/bm_so_lists.rb > /dev/null  48.57s user 0.53s system 99% cpu 49.492 total

うーん、そこまで劇的な変化はなさそうですね。

やはり、mruby v1.3の目玉は大量のbug fixということでしょうか。

bm_so_lists.rbはCRubyだと1sとかなのでこれは……見つけちゃったかもしれないですね……。

一応報告しておきましょう。

Performance regression for benchmark/bm_so_lists.rb · Issue #3737 · mruby/mruby · GitHub

[追記]なおしました。

Should only check frozen fix #3737 by ksss · Pull Request #3739 · mruby/mruby · GitHub

v1.4……?

keyword arguments

https://github.com/mruby/mruby/pull/3629

実はkeyword argumentsに対応するPRは既に来ています。

が、v1.3には取り込まれませんでした。

リリースノートにもRemaining Bugsとしてこっそり含まれているので、ゆくゆく対応されるのではないでしょうか。

※ここは個人のブログです

個人のブログなので、ここからは自分がやったことをまとめます。

Kernel#caller書いたのオレオレ

Cレベルではほぼ同じ機能があったので、これをRubyの世界でも使えるようにしただけ。

引数の扱いが意外とめんどくさかったりしました。

これでデバッグが楽になる場面が増えたはず……!

Proc#initialize消したのオレオレ

これまでは、Proc#initializeでProcオブジェクトの初期化を行っていたのですが、Proc.remove_method(:initialize)と凶悪なことをすると、Procオブジェクトに必要な値が準備されず、いろいろな部分でSEGVが発生するようになります。

これではCレベルのメソッドでProcオブジェクトを扱う際に、常にProc.remove_method(:initialize)されたことも考慮しないといけなくなってしまいます。

ところでCRubyを見てみると、なんとProc#initializeは定義されていないではありませんか。 つまりこういう問題は、CRubyではProc.remove_method(:initialize)にはProc#initializeを定義しないことによって対策していると判断。

mrubyでもProc#initializeを削除して、Proc.newメソッドを独自に定義するようにしました。*1

Proc.newで初期化するようにすれば、たとえProc.newが消されたとしてもProcオブジェクトが作れないのだけなので問題ありません。

Contributionsの二番目にいるのオレオレ

https://github.com/mruby/mruby/graphs/contributors?from=2015-11-17&to=2017-07-04

mruby-specを使って、mrubyとCRubyの挙動の不整合をひたすら直すということをしてました。 またその際にみつかったバグなども直したり、難しすぎて直せないものはissueで報告などの活動をしていました。

序盤の活動はブログに書いていましたね。

結構Rubyの細かい挙動を知れたりして勉強にもなりました。

shopifyのやつもちょこっとだけ手伝った

Make string embad from shared by ksss · Pull Request #3657 · mruby/mruby · GitHub

例えばこちらのエントリーでは、shopify issueの https://github.com/mruby/mruby/issues/3651 を解決しています。

前知識としてStringオブジェクトは、shared, no-free, embed, normalなどの状態が存在し、今どの状態かによって適切に処理を分岐しないと、最悪SEGVするケースがあります(大抵は破壊的な操作)。

sharedなStringを変更してsharedの関係をやめるときに、これまではnormalなStringとしていたのですが、 issueにあるような一部のコードでは文字列の長さでembedかどうか判断していました。

じゃあこれを適切に場合分けして……とも思ったのですが、normalなのに長さはembed可能な文字列が生成できてしまうせいで、問題が起こっていると判断。sharedなStringを変更するときに、長さが短い場合はembedなStringにしてしまえば、問題も治るしメモリ消費を若干抑えられるしで一石二鳥です。

bugを一つ埋め込んでしまった

MRB_DISABLE_STDIO: String#upto native's mrb_str_upto requires snprintf · Issue #3714 · mruby/mruby · GitHub

で報告されているとおり、mruby-string-ext gemをMRB_DISABLE_STDIOでbuildできなくしてしまいました。。。

MRB_DISABLE_STDIOはその名の通り標準入出力を行う関数を一切禁止するだいぶリソースが厳しい環境向けのオプション。

そんな厳しい環境では標準添付ライブラリなんて使わないよね……。う……これで困る人、許してくれ。。。

mruby v1.3

みんな使ってね!

*1:ちなみに実装は、渡されたブロックのコピーを作っているだけ。

mruby-io-copy_streamつくった

github.com

特に問題意識を持っているわけではないけど、がんばって作ってみた。半月以上かかった。

mruby-io-copy_streamとは、mrubyでCRubyでいうIO.copy_streamが使えるようになるライブラリです。

IO.copy_streamは、ようはcatコマンドみたいなやつ。

ちょっとreadして、ちょっとwriteするので、巨大なIOでも一定のメモリで扱うことができる。

一度 mruby-ioにPRを送ってみたこともあるんだけど、以下の理由から止めた。

  • Rubyで書くなら普通にread/writeループでいいよね感があった。
  • このメソッドに求められる要件としては、やはり速度だと思う。(IO操作のほうが重いとは思うけど)
  • ということは、pread(2)やsendfile(2)を使いたい。
  • ということは、autoconf等を使いたい。
  • Cで書くと500行と大きめ。
  • ここまでくると、PRを送られてもmergeしにくいだろうと予想。
  • mrubyとしては、機能が細かく別れてプラガブルになっていたほうが、アプリケーションに無駄な機能を乗せずに済む(と思う)。

というわけで、ほぼほぼCRubyの移植として作った。 特にsendfile(2)を使えるのが面白いところだと思う。

また、特定のライブラリに依存しないように作った。

IOライブラリは最低限readwriteメソッドがあればいい。

filenoメソッドがあれば、fdを使ってシステムコールを呼ぶようにした。

これにより、mruby-ioはもちろん、mruby-tiny-ioでも、mruby-stringioでも、とにかく引数にオブジェクトを使えば、組み合わせることができるように工夫してみた。

よければ使ってみてください。

OSSMMORPG仮説

僕はゲームをやりすぎて留年したぐらいにはMMORPGをプレイしたことがあるわけだけど、最近OSS活動はMMORPGと似ているんじゃないかと思いはじめてきた。 僕がOSS活動をするのも、ゲームをプレイするような楽しさを感じている。

OSS活動と一口に言っても、様々なジョブのキャラクターが存在する。

issueはクエスト。 PRはクエスト攻略。

自分の成長につながるのならなんだって楽しい。

妄想終わり。

無職の記録

約3週間ほど無職を体験したのでその記録。

健康保険

3週間ほどであれば、国保の切り替えがベター。 保険証の発行が即行われるので、無職期間中に子供を病院に連れて行っても保険証が提示できるのが大きい。

病院では保険証を提示せず後で精算するみたいなこともできなくはないけど、手続きが恐ろしく面倒ということは以前に学んでいる。

任意継続の場合は、申請書類を郵送して、保険証が帰ってくるというリードタイムが若干あるようだった。 即日性を重視したのであまり調べてないけど、長期的にはメリットが有るのだろう。

年末年始

3週間のうちはじめの1〜2週間は年末年始だったので、あまり無職感を感じなかった。

年賀状作ったり、親戚の家に行ったり、ポケモンしたりしてた。

インフルエンザ

子供がA型インフルエンザと診断を受けて1週間付き添った。「無職でよかった」と思った瞬間である。

幸い症状は軽めだったけど、自分も37.4℃と微熱。喉が痛かったり体がだるかったり寒気がしたりしていたので、多分感染っていた。

おそらく、予防接種が効いて症状が軽くなったのではないかなあと思う。受けててよかった予防接種。

水族館

そんなこんなしていたら無職期間は残り3日となり、かねてから行きたかったすみだ水族館に一人で行ってきた。

年パスも購入したので、また気晴らしに行きたい。

僕はアカクラゲに興味があった。アカクラゲは映画「アカルイミライ」に登場する。アカルイミライについては以前に恥ずかしい感想を書いているように、僕の一番好きな映画だ。

すみだ水族館蜷川実花氏とのコラボでクラゲをフィーチャーしていた。

テカテカと変わる光と音楽によるクラゲのストレスとかを考えてしまっていまいち楽しめなかった。

ほかにも水槽の前でぼーっとしてみたり、だらけきったペンギンなどを見ていた。

一時間ほどウロウロして帰った。

雑談

あまり外に出なかったので、人と話すこと自体が新鮮だった。

僕は普段そんなに喋る方ではないけど、自分でも驚くぐらい人にどうでもいいことを話しかけた。

「雑談なんですけどこの年パスに写っているクラゲって何クラゲですか?」とか、ランチを食べたあとに「ご飯おいしかったです」とか、コンビニの店員さんに「nanacoカードって何ポイントから使えるんですか?」とか、普段なら黙っているような場面で本当にどうでもいい一言を話したりしていた。

コード

そんなに書いてないけど、mrubyにKernel.#callerメソッドがあると便利かなと思って作ってみた。

github.com

まとめ

無職最終日に何をしたらいいかわからず、とりあえずブログを書いてみた。

おしまい。

第三回mruby-spec進捗確認

すでに本人が飽き気味になっていることは世間から全然反応がないからでありウンヌンカンヌン。

Fix bugs

細かいのが多いので一覧はこちらをどうぞ。

https://github.com/mruby/mruby/pulls?utf8=%E2%9C%93&q=is%3Apr%20is%3Aclosed%20author%3Aksss%20created%3A2016-10-01..2017-01-11%20

所感

mruby-specを回してみて無限ループしているっぽい部分をなおした。 (0..Float::INFINITY)みたいなRangeで無限ループしてほしくない場面で無限ループすることが多かった。 無限Range系のバグはほかにもありそうだ。

最近ではshopifyという会社がmrubyを利用しているらしく、沢山のバグ報告がissueに上がっている。 かなり重箱なものが多い印象(NoMethodError = Fixnumした時にsegvするなど)。 しかしながら再現できる小さいコードがついている事が多いのでちまちま潰していくのに向いている。

これらのバグも、修正したときは念のためmruby-specで回したりしている。

他にも数が多くなおしきれていないので、今Hackし放題ですよ。

おきにいりのPR

https://github.com/mruby/mruby/pull/3369

Rubyでの実装とCでの実装で境界が曖昧な感じがmrubyのヨサな気がする。 Cで書くとパフォーマンスが出せるし、Rubyで書くと短く書けるので、メンテしやすくメモリ系のバグも起きにくい。

Unsupported specs

Opalはいかにしてrubyspecをいい感じにアレしているのか - 近&況

こちらの記事のおかげでmspecにdescription指定でskipする機能があることに気がつけました。ありがとうございます。

というわけで、実装してみた。

github.com

現時点ではどうしてもサポートできないfeatureをskipできるようにした。 落ちたspecのdescriptionをtextファイルにコピペするだけ。 これは、昨今のDSL流行に対するアンチテーゼである。

Repro株式会社にJOINする予定です

https://repro.io/を運営するRepro株式会社にJOINする予定です。

Repro

きっかけはCTOのid:joker1007さんでした。

いろいろな道について模索している時に「フリーランスになるとどういう感じなのかなあ」というのを誰かに相談したくても、話せる知り合いはあまりおらず、藁にもすがる思いで以前チョットだけ話したことのあるjoker1007さんに思い切って相談してみたというのが始まりです。

joker1007さんは自分の会社の紹介などは一切せず、親身に相談に乗ってくださいました。

ただ一言「よければうちにも遊びに来て下さい」とのことだったので、一度話を聞いてみると「なんだか面白そうだぞ」となっていきました。

実際は並行していくつかの会社の話を聞いていたのですが、その内いくつかのいいお話をいただいたところから、悩みに悩んで11月末にエイヤでReproに決めた感じです。

実はやりたいことって固定してはあんまりなくて、フワッとエンジニアリング全般を見ていけたらなと思っています。

そしていい感じのOSSを作れる機会を虎視眈々と狙っていきます。

OSS

OSSを作るのがライフワークみたいなところがあるので、Reproでも活動をやめるつもりは全くありません。OSSを書くことは自分への投資だと思っています。

mrubyに関する知見もいくらか*1持っているので、もしそれを活かせる面白い話があれば是非やってみたいと思っておりますので連絡お待ちしております!

予定?

今年の自分のテーマは『余裕』。

ということで、折角の機会なのでリフレッシュ休暇として2週間ほどの空白期間を作ってみました。

とはいえ既に予定が入っていて暇なのは4日間ぐらいですが……。積読を消化したりポケモンをやったりしています。水族館でもいこうかな。

目下の悩みは健康保険問題……。役場で相談してきます。。。

*1:130 commitしているくらいには

2016まとめ

2016何したかなーと思ったのでまとめる。

ちなみに去年の。

ksss9.hatenablog.com

Pull Requests

https://github.com/pulls?utf8=%E2%9C%93&q=is%3Apr+author%3Aksss+is%3Apublic+created%3A2016-01-01..2016-12-31

現時点でOpen: 5, Close: 78

ほとんどがmruby本体とその周辺っぽい。

ちなみにmrubyだけでみると、commit数だけならmatzの次に多い。

Contributors to mruby/mruby · GitHub

Breaking changeはなくて、ひたすらCRubyと仕様を合わせたりバグをなおしたりしていた。

Myself Repositorys

https://github.com/search?q=user%3Aksss+is%3Apublic+created%3A%222016-01-01+..+2016-12-31%22+type%3Apr&ref=searchresults&type=Repositories&utf8=%E2%9C%93

13個。去年より少ないと思う。

json-expect-parserはもうひとひねりあると、いい感じになる気がしないでもない。

active_tsvGitHub.comのgraphs/trafficを見ると意外とcloneされているのがおもしろい。(rubygemsから使ってほしいょ……。)

テキストエディタもはじめて作ってみたのは経験になった。

mruby-specは僕としては役に立った。ruby/specの方との交流もいい経験だった。

Talk

東京Ruby会議11で発表した。

動画を見返すとあまりにカチコチで恥ずかしい……。もっとがんばろう。

「発表をした人」というだけでも知らない方との交流の種になって、いまでも自分の財産になっている。本当にいい経験だった。

Books

読んだ本を数えなくなって、あんまり読まなくなった気がする。

途中まで読んで読みきれないみたいな本がすごく多かった。これは来年の課題としよう。

Privates

家を買った。今年の前半はだいたいこの作業だった気がする。家で仕事をすることは多いし、子供に綺麗で広い家ですごしてもらえる。がんばったかいがあった。

働いていた会社を退職した。今年の後半はこれで結構忙しかった。

子供のことで用事ができることも多く、最後の有休消化期間は2日しか残ってなかった。

総括

2016年はプライベートが大変な年だった。

2017年はもう少しオープンな活動を増やしたい。オープンな活動履歴は、自分の資産になるのだ。

ここ最近の自分のテーマが『余裕』なので、来年のテーマもこれとする。これは、「チームが機能するとはどういうことか」の病院での話が元になっている。手術室を増やすのではなく、緊急用に一つ開けておくとワークする的なやつ。

それでは良いお年を。