Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

Railsアプリ パフォーマンス比較の方法

どうも、igutoです。

ここ最近、Railsアプリのパフォーマンス改善を担当しています。 パフォーマンス改善のためのコードを書いた後には、改善した箇所についてどれくらい改善できたかを確認したいものです。確認の方法について幾つか試行錯誤して、自分が納得できるものを見つけたので、紹介します。

以前までの方法

以前は、 ブラウザからリクエストを何度も送り、rack-mini-profilerの表示から時間を手でメモして、平均を出す…なんていうことしていました。 この方法では、平均や改善度合いなどを自分で計算しなければなりません。小さな変更を確認するにも、1ページ全体をリクエストし、そのレスポンスを待つ必要があります。

紹介する方法

Rails runnerbenchmark-ips を使います。

Rails runner

Rails runnerは、Railsアプリの一部の処理だけを呼び出すことができるコマンドです。

$ bundle exec rails runner --help
Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>]

    -e, --environment=name           Specifies the environment for the runner to operate under (test/development/production).
                                     Default: development

    -h, --help                       Show this help message.

Examples:
    rails runner 'puts Rails.env'
        This runs the code `puts Rails.env` after loading the app

    rails runner path/to/filename.rb
        This runs the Ruby file located at `path/to/filename.rb` after loading the app

You can also use runner as a shebang line for your executables:
    -------------------------------------------------------------
    #!/usr/bin/env /home/centos/rubymine_projects/ishin-openboard/bin/rails runner

    Product.all.each { |p| p.price *= 2 ; p.save! }
    -------------------------------------------------------------

helpにあるように文字列として指定したコードや、ファイルに書いた内容を実行することもできます。 例えばこんな感じで使えます。

$ bundle exec rails runner 'p User.all.class'
User::ActiveRecord_Relation

benchmark-ips

https://github.com/evanphx/benchmark-ips

時間あたりの実行回数を基に処理速度を算出してくれるベンチマークライブラリ。 実行回数調整のための試行錯誤が必要無い上に、複数ベンチマーク対象を指定した場合は勝手に速度比較までしてくれます。

require 'benchmark/ips'

Benchmark.ips do |r|
  r.report("plus") do
    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
  end

  r.report("multi") do
    1 * 10
  end

  r. compare!
end

上のコードを実行すると、ベンチマーク結果として次のような出力が得られます。

Warming up --------------------------------------
                plus   137.714k i/100ms
               multi   152.615k i/100ms
Calculating -------------------------------------
                plus      5.490M (± 1.0%) i/s -     27.543M in   5.017803s
               multi      9.475M (± 1.1%) i/s -     47.463M in   5.009965s

Comparison:
               multi:  9474980.2 i/s
                plus:  5489593.4 i/s - 1.73x slower

Rails runnner + benchmark-ips

これら2つを合わせて…。下のようなスクリプトを書き、bundle exec rails runner <script path> で実行すれば、毎回毎回ブラウザからページ呼び出しをせずに、改善箇所だけのパフォーマンス改善の確認ができます!

require 'benchmark/ips'

Benchmark.ips do |r|
  customers = Customer.includes(:customer_items).all.take(1000)

  r.report 'normal' do
    customers.each do |customer|
      customer.customer_phases.map(&:scheme)
    end
  end

  r.report 'cache' do
    customers.each do |customer|
      customer.customer_phases.map(&:scheme_with_cache)
    end
  end

  r.compare!
end

おわりに

Railsアプリの一部だけのパフォーマンスの改善量を手軽に測る方法を紹介しました。 これを使うようになってからブラウザの操作や手動での結果確認、計算の手間をなくすことができ作業が快適になりました!