はじめに
Rubykaigi2017に参加してきましたので、メモを共有しておきます
Keynote
- ゆるふわRuby生活
- デバッグ
- 新機能
- バグ作成
- リポジトリ
- Rubyのgithubはミラーなのであんまり見ない
- 移行コスト(svn to git)
- hashが明確でない(リビジョン番号と比較して)
- gitがwindows非サポート
- issue
- redmine
- mailinglist
- meeting
- (物理で会う場合)バグチケットの棚卸し
- build
- out-of-place-build
- configureのオプション
- baseruby
- ソース生成したりなど
- miniruby
- ビルド時の中間生成物
- 拡張ライブラリ
- 共有ライブラリの非サポート
- 単独で動かせる
- エンコードが固定
- 共有ライブラリの機能が無理
- extconfのビルドが遅い
- 別プロセスでビルドするようにした(2.5以降)
- 依存関係がなければ
- 別プロセスでビルドするようにした(2.5以降)
- ヘッダーや共有ライブラリの位置
- trace_var
- ビルド時に変数の代わり内容をhookする
- out-of-place-build
- bug?
1 2 |
|
- カッコの前にspaceを置く
- キーワード引数の名前を内部的にはラベルと呼称
- parse_ident()
- 小文字で始まってるか識別する
- lavr_ident
- 既に定義済みかチェック
- lvar_definedを外せば多分意図通りになって直るけど・・・
- string.intern(symbol作成)の再定義するとsymbolにならない
- :”#{aaa}”みたいな書き方で、refineでstring.internを上書きしたのだとsymbolにならない
- 2.5にnew featureはないのか?
- rescure inside do-end
- hash,transform_keys
- 議論中
- メソッドオブジェクトを作るためのメソッドみたいなのは議論中
- 右代入(rightward assignment)
Fiber in the 10th year
- suspend/continueはprocはできないけどfiberならできる
- Fiberの応用
- 使うところ
- ブロックの仲で繰り返す
- ブロックの外で制御
- ゲームのキャラクタごとにパラメータ制御
- IOscheduler(none-blockingio)
- timerがない
- ioblockingでも切り替え無し
- 共有データの同期処理を書く必要がおそらく無い
- 使うところ
- 当初、Fiberは任意のFiberに処理を渡すpassというAPIだけを持っていた(coroutineだった)。
- coroutineは強すぎて管理が難しい。
- contextの切替
- thread state
- vm stack
- machine stack
- 昔はコピー
- コードを参考にできた
- 殆どの環境で使える
- スタックが深いと領域が必要で時間かかる
- その次
- nativeのスタック領域を使うように
- 今
- ポインター切替で実行
- 5%早くなった
- 30%メモリ消費減った(但し、局所的)
- ポインター切替で実行
- autofiber
- 既存コード変更不要
- blockimgioを勝手に切り替える(ioblockのみ)
- fiberの指定不要
- 同期処理を書く必要が出て来る
How Close is Ruby 3x3 For Production Web Apps?
- Real Web Appsはproductionで人々に使われていることで、fasterはベンチマークテスト結果を改善
- くりかえしすることを実行
- 通常アクションを記録
- optcarrotでwarmup
- discurseで採取(https://github.com/discourse/discourse)
- Ruby2.0.0からRuby2.4.1で速度はどうなったか。途中でDiscourse自体がv1.5からv1.8に変わってしまったが、同バージョンの中ではRuby Versionが上がるにつれて着実に改善
- DiscourseでのベンチマークではRuby2.0.0 -> Ruby 2.4.1にかけて150%ほど速くなっている
- ウォームアップについて。MRIでもwarmupについれてスループットが改善する。どのRubyバージョンでも同程度。5000
- warmup iterationで5-7%程度の改善。
- firstrequestは2.0.0に比較して30%確実に早くなている
- https://github.com/noahgibbs/rails_ruby_bench
- https://docs.google.com/presentation/d/1tUQpblTufP0IWiZSfnky56y9WvYeqMQF9ve45yIcpYY/edit
Gemification for Ruby 2.5/3.0
- 現状と展望について
- raa
- rubyforge
- gems.github.com
- gemcutter.org
- rubygems.org
- bundler <= イマココ
- 標準添付ライブラリ
- requireしなくても使えるもの
- standard libraries
- svnと一致しているもの
- default gems
- rubyと一致orメンテナがリリース
- bundled gems
- メンテナがリリース
- default gems
- openssl
- githubで開発
- あるタイミングでsvn側に取り込み
- rubyのバージョン違っていても、使える
- psych
- jruby/crubyの互換性確保
- rdoc
- openssl
- bundledgems
- testunit/minitest
- ビルド時にinstallするもの
- rake
- 標準添付する必要があんまりないので
- デメリット
- 開発中のrubyでbundledgemsが動くかも保証もできない
- gemfication
- standaradのもをgemで配布していく
- 標準添付ライブラリをgemとして切り出していく
- 2.5,2.6で追加したものを2.4でも使える可能性ある
- 問題
- 標準添付ライブラリ間の依存関係
- バックポートによるメンテナの負担がヤバイ
- メンテナが古いのでも使えうように頑張る必要でてくる
- 1.8.7のサポート対応
- rubygems/rubygems.org
- サイト
- rubygems/rubygems
- ライブラリ周り(bundlerチーム)
- rubyfication
- rubygems上に名前空間周りでバッティングして調整して上書き
- 3.0へ向けて
- bundlerはデフォルトgemになる
- 標準添付は全てgemにしておきたい
- 標準ライブラリのバージョン周りでもしかしたらバージョンの不具合起きるかも
- Bundler がないと RubyGems 2.7 の動きが怪しい
Development of Data Science Ecosystem for Ruby
- 現在
- Rubyだけで頑張る方法
- データ処理部分
- 併用する方法
- メイン処理に関わる箇所でmデータの受け渡し処理
- 2重変更が必要(データ処理とメイン処理)
- pythonやrを呼び出すとデータ交換コストが高く、データ形式の変更時などは両方に変更が必要
- rubyからpythonを呼び出す方法
- rails上でpandasで表示
- パフォーマンスに問題ありそうだけど、pandas呼べてる
- rubyからpythonを呼び出すことに不自然ではない
- 先入観では?
- RPy2みたいなものも存在している
- 大体のことがPythonでできるから、Pythonになっている
- issue登録が欲しい
- Rubyだけで頑張る方法
- 将来への展望
- 未来を見据えてPycallでないようにしたい
- 一つの言語では完結しない
- pysparとはいえ、spark自信はscala,java
- apache arrowを例にとっても、bindingを作っておけば将来apache arrowが流行れば使われるようになる
- red data toolsに参加してもらいたい
- pycallにissue/prが欲しい
Ruby Committers vs the World
- 型注釈、結局コミッターはどう思ってるのか?
- 全体的に「別にあってもいいんじゃないの」って空気感
- 右代入?
- matz右代入ありなんだけど、いい記号がない。。。
keynote
Matzによるkeynote
- 言語愛が最大の要因
- プログラミング言語面白い
- 例外なくプログラミング言語が好き
- 他の言語を貶めることは無い
- simula(一番最初と言われるオブジェクト指向言語)
- inheritance
- 差分プログラミング
- simulaからではなくlisp, smalltalkから影響を受けているのでsimulaから直接ではない
- super classは2つでは?
- roleは複数持ってるのでは?
- 単一継承ではなく多重継承
- Lisp(flavors)の世界から
- 自然な拡張だが、複雑化しやすい
- daiamond継承など
- c3 linialization algorizm(線形化アルゴリズムで、継承順序を決定する)
- mix-in
- lisp内ではflavorsと呼ばれる
- バニラアイスに、チョコチップやミントの味を追加するみたいな意味
- アイスクリームはインスタンスにできるが、チョコチップはできない
- 混ぜた味(ミントアイスクリーム)はインスタンスにできる
- バニラアイスに、チョコチップやミントの味を追加するみたいな意味
- モジュールはmixinの単位
- Rubyではグループ分けの単位として使われてる
- Net::HTTPのNetなど
- singletonとしても使われている
- FileUtilsなど
- メソッドや機能の集まりとして使われている
- Mathモジュールなど
- includeすると直接使えるようになる(モジュールファンクション)
- メソッドをコピーしてオブジェクトに注入
- Mathモジュールなど
- メソッド結合としての単位
- alias method chain
- メソッドの別名をつけて、置き換えることができる
- module prepend
- dynamicに変更することができなくなる
- 最初は入れる気がなかったが考える事で入れるようになった
- lispのメソッドコンビネーション
- classにおけるaround hook
- aspect思考からも影響
- alias method chain
- refinement
- open classの機能はあった
- monkey patching機能(昔はgerilla -> gorilla -> monky)
- ActiveSupport
- グローバルに影響与える
- selector namaspaceも候補にあった
- usingを都度書く必要があるので、イマイチ使われていない?
- スコープを区切ったmonkey patch
- レキシカル
- 使い方
- C#のエクステンション
- 既存のメソッドを置き換える
- ローカル里バインディングがない
- 想定外に置き換わることもない
- open classの機能はあった
- structural signature
- type check
- Javaのインターフェースでは?
- まだ導入されていない
- type check
- lisp内ではflavorsと呼ばれる
- performanace
- Benchmark suite
- MJIT
- Rubex
- concurrency
- fiber
- autofiber
- guild
- static analytics
An introduction and future of Ruby coverage library
- 型システムだけではなくカバレッジ方面でも活躍していく
- カバレッジ
- コード
- 未テストのコード検出
- テストスイートの良さ体語
- function coverage
- 簡単可視化しやすい
- 関数の中はみないので指標として弱い
- line coverage <= Rubyはこちらのみサポート
- 簡単可視化しやすい
- 関数の中はみないので指標として弱い
- 後置ifなど見落としやすい
- branch coverage
- 網羅的に検証できている
- 可視化が難しい(多くのツールでサポートできてない)
- 更に細かいcondition coverageがある
- C0/C1/C2の指す内容については人によって異なる可能性あるので注意
- 理解してつかっていくには
- よいテストスイートは?
- 仕様を満たしているかは取れない
- 設計に対する網羅性はない
- 間違えてたしてもテストコードがありカバレッジがあるとないとでは大違い
- カバレッジは指標なので、100%を目指してもダメ
- 仕様を満たしているかは取れない
- 未テストを理解
- テストデザインを考える
- 特に観点が重要
- どれくらい網羅性があれば?
- 重要なものに関しては100%を目指す(ぐらいの温度感)
- 費用対効果も考慮に入れて考える
- ioとかテストしにくいものは、割に合うか考えてやる
- よいテストスイートは?
- ライブラリの現状と展望
- simplecov
- coverage.soのラッパー
- htmlで結果出力
- テストの一番最初に呼ばないと、それ以前に呼ばれたものは測定対象にならないことに注意
- 関数定義も実行対象になってしまうので、意味が無いことに注意(メソッドが呼ばれてない場合)
- concov
- 時系列カバレッジ
- 追加されたコードに対してテストがされているかのチェック
- other lang
- C/c++
- gcov/lcov
- java
- covertura emma, clover, jacoco
- C/c++
- simplecov
- 今後の計画と展望
- function / branch coveargeの測定追加
- issueにコメント欲しい
- 互換性を持って作っている
- 100%既存に互換性
- 他のcoverageツールも参考
- lcovなど
- overhead
- 現状ruby本体だと5倍弱時間がかかる
- railsだと2倍くらい?の見込み
- function / branch coveargeの測定追加
workshop
前日のmrknさんが発表されていたPycallについてのworkshop
リポジトリはこちら
docker runをすることで、workshopの内容が出てきます
Ruby Language Server
mtsmfmさんの発表
- lanugageserver
- エディタの補完
- メソッド定義
- ビルド
- languageserverプロトコル
- ドキュメントの整形
- 今までのものはエディタ向けのもの
- viならvi, emacsならemacs
- msが仕様を公開している
- でもvsコードの拡張プラグイン向け
- Languageserverprotocol
- 汎用と専用がある
- rubyで書くには?
- 基本はnode
- JSON-RPCでアクセスができればOK
- 但し、クライアントがうまくサーバと通信できるようにする必要がある
- gemでlanguage_server-protocolとして公開している
- 内容
- rocodetoolsで補完
- 動的解析に利用、副作用とか到達不能な場合は無力
- インスタンスレベルの補完はできてない(静的解析)
- エラーメッセージは実行して(wcオプション)、正規表現で結果取得
- rocodetoolsで補完
- 将来
- 静的解析の改良
- ドキュメント
- rubocop
- syntax highlight
Compacting GC in MRI
Aaronさんの発表
- copy on write最適化
- 性質や定義に注意
- コピーしたものは、複製元のメモリ上の場所だけを持ってる
- 配列も同じだが、hashはできない
- コピー元に変更があったら、コピー先に掛かれる
- プロセスforkだとコピーしない
- Copy on Writeは何かの変更が起きない限り、コピーを作る必要はなく、必要になったときにはじめてコピーを作る
- unicornは親プロセスをforkしている
- unicornはforkして子プロスを立てるので、Railsが子プロセスで別々に読み込まれてつらい
- 子プロセスは親プロセスのメモリを指してるのでメモリ使用量を減少させることができる
- 子で書き込むとコピーされる
- pagefault(共有メモリの変更が原因 => GC)
- GCのobject allocationでpage faultが起きる。ruby objectのサイズはOSのpageよりも小さいので、object割り当てをするとページまるごとコピーされるし、無駄に使用量がどんどん増える
- オブジェクトのサイズはページサイズより小さいので1オブジェクトの変更でも1ページ分のメモリコピーが行われて非効率
- heap compaction
- two finger compaction(単純なクイックソートアルゴリズム)
- 欠点 ランダムに移動するので遅い
- 利点 他のアルゴリズムよりに簡単に実装できる(下記の2つしかない)
- オブジェクトの移動
- 更新
- two finger compaction(単純なクイックソートアルゴリズム)
- gc
- ヘルパー関数を用意した
- 移動できないビットテーブル
- rb_gc_mark
- lowlevelでC拡張
- GC.compaction
- rb_gc_mark以外が対象
- 難しいもの
- hash key
- 2重参照
- global変数
- rb_class_define
- gcはglobal変数を変更することはできない
- string literalの移動するとbytecode更新が続いているので対応が難しい
- 結局、何も動かせていないような・・・
- とはいえRailsでも46%程度削減できている
- inspect memory
- object_space.dump_all
- rubyのメモリ
- address: 位置
- reference: 参照先メモリ
- size: メモリサイズ
- グラフを作成して変化を追ってみるといいかも tendorlover/heap-utils
- spaps
- pss
- object_space.dump_all
- conclusion
- プロダクションでテスト中
- 小さいものでは全然効かない
Ruby for Distributed Storage System
tagomorisさんの発表
- disk & networkioがボトルネックではなくなってきてる
- storageは最近早いのでネックではない
- networkはクラウド事業者のものが早い
- disk/networkioには、serialization/deseriazationが走る
- 分散ストレージの場合はさらにレプリケーションが発生する
- 検証やネットワークioの非同期化
- これらをこなすためのさらなるThreadなど
- quoram
- 最低2つのレプリカをできればよいというもの
- 短いレイテンシ
- 最後のレスポンスは無視する
- 非同期処理のコストを下げる
- 短いレイテンシ
- 最低2つのレプリカをできればよいというもの
- bigdam(TD)
- データ入力系(pipeline)の見直しのPJ名
- 小さいデータから大きいものまで
- 世界中に配備する
- bigdam-pool
- 分散key-value storage
- buffer pool
- S3は使わなくてもよいように
- MB単位くらいをそうてい
- 追記も可能にする
- 同一データを書き込みできないようにしている
- replicationもする
- 無くなったデータの補充みたいなのは内
- edge locationで一度受けて、center locationに置くうような仕組みを取ってる
- データ入力系(pipeline)の見直しのPJ名
- design bigdom
- mockから先につくたり、IFを全部先に用意
- ここをRubyで実装
- 柔軟なので、作って足りない場合に修正したりしてた
- 手早く
- integration /interface test
- hashっぽいものを書くにはjavaは辛い
- さっさとシリアライズ、デシリアライズでサクッと使えて嬉しい
- Rubyだと型がないのでシリアライズ、デシリアライズが書きやすく、Mockやテストが書きやすかった。
- bigdum-pool-ruby
- java版と同じものを用意している
- 非同期networkio
- eventmachine
- cool.io
- celluloid::id
- thread/timer
- javaのほうが若干便利かも
- executerservie(Java)
- monitormixin
- mutexと似ているもの
- resourcecontrol
- try-with-resourceがrubyにはない
- begin_with_rescueが2.5から追加される
- 型
- 型を混ぜてしまうこと(ArrayにIntegerやStringを混ぜるなど)
- 多言語に対応させるときには・・・・
- 型を混ぜてしまうこと(ArrayにIntegerやStringを混ぜるなど)
- アプリケーションサーバ
- Rubyだと基本webサーバしか・・・
- ストレージで動かせるとか汎用があると嬉しい
Bundler 2
0xColbyさんの発表
- bundle addコマンド経由でできるようになる
- plugin機構を取り入れて、事前処理や後処理も追加できる
- エラーメッセージの改良
- 1.16が1.x系最終
- Bundler2は2.3以上
- sourceの名前付けをショートカットさせる(:githubみたいな指定)
- gem ‘rack’ github: ‘user/repo’
- ブロック指定もできる
- bundle infoやbundle gemの情報が出て来る
- bundle packageがbundle cacheに変更
- bundler 1.xとの後方互換製ない
- bundlerは今後1年ごとにメジャーリリース(メジャーバージョンアップという意味ではなく)
- ruby2.5ではruby側に同梱
- bundler2でGemfile.lockが解釈できるが逆はできない(だったかな)
Memory Fragmentation and Bloat in Ruby
nateberkopecさんの発表
- 512MBのDYNOでRails動かしてる場合は50%くらい(?)はMemory-constrained
- Rubyでのメモリ確保の挙動はレイヤーが深くて難しい、みたいな話をしてる。Ruby Code自体/Ruby Runtime/Allocator/MMU/実メモリ配置
- Rubyコード自体からランタイム、アロケーター、MMU、RAM構造まで考えること沢山
- freeは本当にfreeするわけではない。OSに領域を返すわけではない.初期化コストかかるのでガバッと拾ってしまってる
- web request allocation pattern
- http requestが終われば関連するメモリ全部捨てられる
- 確保したメモリを更に小分けにして、リクエストごとに割り当ててレスポンスが終わったらまとめてfreeして再利用
- 全てのオブジェクトには40ByteのRVALUEが与えられている。また、実際にmallocされて割り当てられた実際のオブジェクトデータへのポインタを持つ
- 文字列も短いとRVALUEに入り大きければmallocで確保された場所へのポインタ
- GC.statの:heap_live_slotsでスロット数が、:heap_eden_pagesでページ数が取れる。GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT]でページごとの上限が取れる
- eden_pages * slots_per_pageで確保できるオブジェクトの上限が取れる。live_slotsをこれで割れば使用率が出せる
- PUMAはUnicornより多くのメモリを使ったり、Sidekiqがリークしたりする。スレッドごとのメモリ領域がメインスレッドのメモリ領域に還元
- スレッドごとにメモリ領域を確保した後、スレッドが終了しても開放されずにメインスレッドのメモリに統合される
- MALLOC_ALENA_MAXを指定すると確保するメモリ領域の上限を制限できるけど、速度とトレードオフになる
Writing Lint for Ruby
p_ck_さんの発表
- ripper
- Rubyのparserはほかにもある。標準のRipper。パースのRubyと実行するRubyが同じバージョンになってしまう問題
- ASTのトラバースでも無視するnilの可能性
- Traverserパターンで解析をする。nodeとvisitorを受け取り再帰的に呼び出していますね。
- node.source で括弧の有無など AST で欠損するソースそのものの情報を入手することができる
- lintの限界
- ローカル変数の中身はparserは知らない
- 要はエラーがあったものを代入して回避なおd
- method呼び出しで定義がわからない
- 静的解析とRubyの相性がイマイチよくない
- monkypatch / params(rails) / evalだとLintではできない
- 実行できないという制約
- ローカル変数の中身はparserは知らない
- 構造が理解ができる
- 全てのケースに対して警告出せる
- 解析時間が短い
- 実行したりしないので
- rubocopは汎用ルールなので、こっち使ったほうが楽
- Rubocop(Lintのルール)の作り方。rakeタスクがある。lintの実装とテストのテンプレートを作ってくれる
- rubocop-plugin(特化したもの)
- Lintはバグ検出に使えるもの
- 解析は、ASTトラバースして見つける
- 静的解析にはいくつか方法はある
終わりに
スピーカー、スタッフの皆様ありがとうございました
久しぶりな方々ともお会いできて、新たな刺激がありました
印象深いのが型、parser周りの話が多かった印象です
来年は仙台なので、広島よりは都内から近いですね