2010-08-19
Ruby / Rails のテストが約3倍速になって超快適に!!
parallel_tests 使ったらテストが約3倍速(i7)になって Life Changing すぎる、という話です。
最近かなりちゃんとテストする環境になったんだけど、テスト時間が結構かかって、master にマージ後テストこける -> 修正 -> またテスト、というサイクルだと push まで時間かかってどうにかテスト効率よくならないかなー、と思っていたら
とタクト先生(d:id:t-wada)が面白そうなことをつぶやいており、なんか名前からして並列実行できそうな!!!と思って調べてみたらやっぱりtest/spec/cucumberを並列実行できるライブラリ parallel_tests がありました。これはやばい。
前から自分も fork してテスト走らせればユーザースレッドな Ruby でもマルチコアの恩恵うけれるよなぁ、でも DB のコネクションあるし難しいよな、と思っていたんだけど parallel_tests は hey,you. テスト用 DB 複数作っちゃいな、YP! というその発想は無かった感じでうまくテストが実行できる。
rake parallel:spec[1] # 1プロセスで実行
rake parallel:spec # 2プロセスで実行
rake parallel:spec[4] # 4プロセスで実行
で、実際にギッハブに書かれている通りに設定して Rails アプリで実行したら 4Core の i7 で 140秒弱かかったテストが45秒ほどと4倍とは行かないまでも*1,3倍とちょっぱやに。めちゃくちゃかいてきなんですけど…。なお8プロセスで走らせたらさすがにコア数以上だし、各種テストはforkされて走る訳なのでRailsの起動コストも馬鹿にならないしでかえって遅くなった。
また Rails3 な edge rails でも一行WARNはでるけど、あらかじめテストDBにスキーマを rake:db:setup で作って置いたら普通にうごいた。
bundle install
for i in {1..4};do mysqladmin -uroot -S /tmp/mysql.sock create test$i;done # 4個dbつくる
for i in {1..4};do TEST_ENV_NUMBER=$i RAILS_ENV=test rake db:setup;done #セタップ
rake parallel:prepare
rake parallel:spec[4] #=> 4 processes
というわけでRuby/Rails で使える parallel_tests 使ってちょうかいてきになった、という話でした。タクト++
でも懸念事項も以下のようなことが発生/容易に想定できますのでちゅういです。
- rcov でのコードカバレージ
- テストごとなコードカバレージになってしまうため、実際すべてのテストで網羅していてもカバレージ率が下がってしまって良くないです。どうにかしたい
- DB 以外のロック
- IO で同一ファイル開いて書いたり、AR 以外使ったりするとロックされない/同一DBにつなぎに行っておかしくなる可能性が。ENV['TEST_ENV_NUMBER'] 使ってどうにかするしかなさそう
欲求の理解
grep や ack で絞り込んだ結果を vim で開く
grep や ack なんかでいくつかのファイル名に絞った後 PAGER で見たいとき、いちいちコピペとかめんどくさい。で、vim には起動時の引数 - で stdin から食べれる機能があるので
git grep ooooo # 良い感じに絞れたよ
git grep ooooo | vim -
すると vim が起動して、ファイル開きたいところで gf で普通に開けて便利。行番号にちゃんと飛びたいときは gF すればおk。grep -n とかつけなくても食べれます。
あとは zsh の alias として
alias -g V="| vim -"
と定義すれば
git greo ooooo V
で使えて便利です。なお vimpager.vim や less.sh のような vim そのものを PAGER としてつかう物とは用途は違うます(カーソル下のファイル名を開きたいから)。
*1:これは parallel_tests がファイル単位であらかじめ分割して実行するため、テストのグループによって終了が速かったり遅かったりするため。ある程度インテリジェンスな改善はできそう