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


## 1. ベンチマーカー

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

- [benchmark-ips](https://github.com/evanphx/benchmark-ips)


## 2. プロファイラ

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

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

## (3. NewRelic)

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

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

## stackprofの使い方

### 設定

```Gemfile
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`
 - `:cpu` : CPU timeとしてサンプリング
 - `:wall` : Wall-clock timeとしてサンプリング
 - RailsアプリケーションではWall-clock timeとしてプロファイリングした方がいい．(http://blog.scoutapp.com/articles/2015/09/16/profiling-rails-with-stackprof)
- `interval` : サンプリングレート．デフォルトは1000[μs]
- `raw` : `--flamegraph`や`--stackcollapse`オプションを使う場合は`true`
- `save_every` : サンプリングの刻み
- `path` : ダンプファイルが出力されるディレクトリー

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

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

#### 全体の結果

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

![Kobito.Lejmgs.png](https://qiita-image-store.s3.amazonaws.com/0/6664/f6f48c2a-7651-9533-8194-34eddbaa6650.png "Kobito.Lejmgs.png")


#### Methodごとの結果

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

![Kobito.U0PWkK.png](https://qiita-image-store.s3.amazonaws.com/0/6664/e5d5b4aa-0eba-fed1-d302-407aa3b30f49.png "Kobito.U0PWkK.png")



## (peek-)rblineprofの使い方

### 設定

```Gemfile
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](https://qiita-image-store.s3.amazonaws.com/0/6664/70d1a1a5-0792-abdb-ae63-fc78d58cc36b.png "Kobito.RYuUh3.png")

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

![Kobito.kCxdmS.png](https://qiita-image-store.s3.amazonaws.com/0/6664/f38bf23d-6f68-05eb-d4c0-451c2289a4c0.png "Kobito.kCxdmS.png")



## Spetial Thanks

ここに書いてあることのほとんどは、[@cryeo](http://qiita.com/cryeo)がインターンで調べてくれました。これはその時IssueとプレゼンでまとめてくれたものをQiitaにまとめ直したものです。ありがとう！