byebugとpry-byebugのbundle updateをしましょう
byebugはRails標準でインストールされるRuby 2.1, 2.2向けのデバッガで、pry-byebugはpry *1 にデバッガの機能を追加するpryのプラグインです。 一昨日から今日にかけて、以下のパフォーマンス改善を含む byebug v8.0.0 と pry-byebug v3.3.0 がリリースされました。
byebugとpry-byebugには、一度byebug
やbinding.pry
を叩くとそれ以降ずっとアプリケーションの挙動が10倍遅くなるという問題がありました。
これが上記の変更により改善されたので、 Railsアプリやgemのデバッグにbyebugやpry-byebugを利用している方はそれらのbundle updateをおすすめします。
binding.pryすると10倍遅くなる問題
Byebugは行の移動やブレークポイントで処理を止めたりするため、Ruby 2.0から導入されたTracePoint *2 *3 というRubyのVMで起きるイベントに処理をフックさせるためのAPIを使っています。
byebugとpry-byebugはbyebug
やbinding.pry
を叩いたときにByebug.start
というメソッドの中で必要なTracePointを設定することによってデバッグを可能にしているのですが、 いままでのbyebugやpry-byebugはデバッグ終了後にデバッグ用のイベントフックを無効にしていなかった ため、一度byebug
やbinding.pry
をするとそれ以降どんなアプリでも10倍程度遅くなってしまう状態でした。
なぜそんな状態だったのか
byebugとpry-byebugの作者はこの問題とどうしたら直るかを認識していたのですが、以下の理由により簡単には解決できない状態でした。
- TracePointを無効にするための
Byebug.stop
がバグっていて、使うと大量にテストがfailする - TracePointを複数設定した後それらを無効にすると、freeしたTracePointを参照してしまうRuby自体のバグがありランダムにSEGVする
これらの問題をgdbを使って地道にデバッグを行って原因を特定し冒頭に載せたパッチによって問題が解決したため、デバッグ終了時にByebug.stop
を呼ぶことが可能になりパフォーマンスが大幅に改善されました。なお、Ruby自体のSEGVに関しても原因を特定しパッチを投げています。
注意点
byebugやpry-byebugにはブレークポイントを設定する機能があるのですが、それを設定している間はByebug.stop
しない(したらブレークポイントが動かなくなる)ためブレークポイントを使っていると遅いままになります。解除すればまた速くなります。
なお、Byebug.stop
されているかはアプリケーション上でByebug.started?
がfalse
を返すかを見ることで確認することができます。 false
が返れば高速に動作しています。
所感
直すの結構大変だったので是非最新のbyebugとpry-byebugを使っていただきたい気持ちです。