Ruby
Rails

Ruby/Railsでの高速化の際に使うgem達

More than 1 year has passed since last update.

1. ベンチマーカー

プロファイルすると、プロファイル自体に時間がかかるので正しく速度が測れない。そのためベンチマーカーも使うと良い。
ただし、ベンチマーカーはどこが遅いか等の解決の糸口は教えてくれない。

2. プロファイラ

実際に速度のボトルネックを見つける際に使う。

  • stackprof
    • どのメソッドに多くの時間を費やしているかがわかる
    • これを入れても速度にさほど影響がない
  • rblineprof
    • 行ごとにかかっている時間を出してくれる
    • peek-rblineprofを使うとブラウザで結果が見れる
    • ただしプロファイリングに結構時間がかかる

(3. NewRelic)

実際、これらのことを手元でやらなくても、特にstackprof的なことや、どこのページやどのSQLクエリが特に遅いかなどは、 New Relic がやってくれます。お金を払うと結構詳細な部分も見れます。ここでは、これの詳細を書くのはやめてドキュメントへのリンクだけ貼っておきます。

https://docs.newrelic.com/
https://github.com/newrelic/rpm

stackprofの使い方

設定

gem 'stackprof'

して、bundle install

config.ru
...

# Settings of StackProf
is_stackprof         =  ENV['ENABLE_STACKPROF'].to_i.nonzero?
stackprof_mode       = (ENV['STACKPROF_MODE']       || :wall).to_sym
stackprof_interval   = (ENV['STACKPROF_INTERVAL']   || 1000).to_i
stackprof_save_every = (ENV['STACKPROF_SAVE_EVERY'] || 1).to_i
stackprof_path       =  ENV['STACKPROF_PATH']       || 'tmp/stackprof/'

use StackProf::Middleware, enabled:    is_stackprof,
                           mode:       stackprof_mode,
                           raw:        true,
                           interval:   stackprof_interval,
                           save_every: stackprof_save_every,
                           path:       stackprof_path

...

を追加。

この設定の後

ENABLE_STACKPROF=1 rails s

を起動し、計測したいところにアクセスする。
そうすると、pathで指定したtmp/stackprof/以下にダンプファイルが生成される。

オプションの詳細

https://github.com/tmm1/stackprof#all-options

  • mode : サンプリングモード.主に使われているのは,:cpu, :wall
  • interval : サンプリングレート.デフォルトは1000[μs]
  • raw : --flamegraph--stackcollapseオプションを使う場合はtrue
  • save_every : サンプリングの刻み
  • path : ダンプファイルが出力されるディレクトリー

プロファイリング結果を見る

stackprof [dump file(s)]  # プロファイルの結果を見る
stackprof [dump file(s)] --method <メソッド名>  # メソッドごとのプロファイル結果を見る

全体の結果

$ bundle exec stackprof tmp/stackprof/stackprof-wall-*.dump

Kobito.Lejmgs.png

Methodごとの結果

$ bundle exec stackprof tmp/stackprof/stackprof-wall-2628-1450242581.dump --method "Jpmobile::Resolver#query"

Kobito.U0PWkK.png

(peek-)rblineprofの使い方

設定

gem 'peek'
gem 'peek-rblineprof'
gem 'pygments.rb', require: false # Syntax highlitingが欲しい場合

して、bundle install

config/initializers/peek.rb
Peek.into Peek::Views::Rblineprof
app/assets/javascripts/rblineprof.js.coffee
#= require peek
#= require peek/views/rblineprof
application.scss
@import "rblineprof"
app/assets/stylesheets/rblineprof.css
//= require peek
//= require peek/views/rblineprof/pygments

.highlight pre {
  white-space: pre;
  overflow-x: scroll;
  word-wrap: normal;
}

.peek-rblineprof-modal {
  width: 1200px;
  width: 90%;
  margin-left: -45%;
}

このCSSのrequire以外の部分は、本来は必要ないはず。ただ、自分の環境では既存のCSSとコンフリクトし、各行と時間の表示位置がずれることが起きていたので改めて設定しなおした。

プロファイリングオプション

URLのパラメータでオプション指定ができる

  • lineprofiler : プロファイリングの範囲
    • app : Rails.root/(app|lib)以下のコード
    • views : Rails.root/app/views以下のコード
    • gems : Rails.root/vendor/gems以下のコード
    • all : Rails.rootのすべてのコード
    • stdlib
  • lineprofiler_mode : モード
    • cpu : CPU Timeでプロファイリング
    • wall : Wall-clock Timeでプロファイリング

結果の見方

http://localhost:3000/your/slow/page?lineprofiler=al&lineprofiler_mode=wall

にアクセス。以下の様な形で結果が見れる

Kobito.RYuUh3.png

ちなみに、lineprofiler_mode=cpuだと、cpu timeとidle timeの2つの値が出力される

Kobito.kCxdmS.png

Spetial Thanks

ここに書いてあることのほとんどは、@cryeoがインターンで調べてくれました。これはその時IssueとプレゼンでまとめてくれたものをQiitaにまとめ直したものです。ありがとう!