概要
MITライセンスに基づいて翻訳・公開いたします。
- リポジトリ: schneems/derailed_benchmarks
- 原文更新日: 2018/03/25
- 著者: Richard Schneeman(schneems)
- サイト: https://www.schneems.com/
画像はREADMEからの引用です。
Rails: 多機能ベンチマークgem「derailed_benchmarks」README(翻訳)
RailsアプリやRubyアプリのさまざまなベンチマークを取ることができます。
schneems/derailed_benchmarksより
互換性と要件
このgemはRails 3.2以上、Ruby 2.1以上でテストおよび動作確認しています。一部のコマンドはもっと古いRubyでも動くかもしれませんが、すべてのコマンドの動作についてはサポート外です。
一部のベンチマークについては(すべてではありません)、OSでcurl
コマンドが実行できることを確認する必要があります。
$ which curl
/usr/bin/curl
$ curl -V
curl 7.37.1 #...
インストール
Gemfileに以下を追加します。
gem 'derailed_benchmarks', group: :development
続いて$ bundle install
を実行します。
このgemのコマンドを実行するとき、コマンドの前にbundle exec
をつけて実行する必要があるかもしれません。
利用可能なプロファイリング用メソッドをすべて追加するには以下も追加します。
gem 'stackprof', group: :development
ライブラリのインストールにはRuby 2.1以降を使わなければなりません。これより古いバージョンのRubyをお使いの方は何を待っているんでしょうね?
使い方
アプリのベンチマークには2とおりの方法があります。derailed_benchmarksでは、Webアプリを起動してベンチマーク中にリクエストを実行することも、Gemfileにある依存関係の静的な情報を取得することもできます。精度についてはアプリを起動する方法の方が常に高くなりますが、productionローカルでアプリを実行できない事情がある場合は静的情報も役に立ちます。
静的なベンチマーク
このセクションでは、アプリを起動する必要なしにGemfileからメモリ情報を取得する方法について説明します。
このセクションのすべてのコマンドは$ derailed bundle:
で始まります。
メモリとパフォーマンスの関係については、How Ruby Uses Memoryをご覧ください。
require
時に消費するメモリ
プロジェクトにgemを追加するたびに、起動時のメモリ利用量が増加します。gemごとのメモリ使用量を表示するには、以下を実行します。
$ bundle exec derailed bundle:mem
Gemfileにあるgemが読み込まれ、require
されたときに消費するメモリが表示されます。たとえば、mail
gemを使っている場合の出力は次のようになります。
$ bundle exec derailed bundle:mem
TOP: 54.1836 MiB
mail: 18.9688 MiB
mime/types: 17.4453 MiB
mail/field: 0.4023 MiB
mail/message: 0.3906 MiB
action_view/view_paths: 0.4453 MiB
action_view/base: 0.4336 MiB
補足: MiB
は、IEEEやIECでメガバイトを表すシンボルであり、220 バイト / 1024キビバイト(結果は1024バイト)になります。
上の結果からmail
が18MiBを消費していることがわかりますが、その大半はmime/types
で占められています。この情報を用いて、不要な依存関係を取り除けます。また、不要なgemが大量のメモリを消費していることに気がついたら、issueをオープンしてgemの作者に知らせてください(再現手順も添えること)。うまくいけばコミュニティがメモリのホットスポットを特定して影響を軽減できるでしょう。パフォーマンスの問題を修正する前に、問題がどこにあるのかを知っておく必要があります。
デフォルトでは、:default
グループと"production"
グループの結果だけを表示します。他のグループの結果を表示するには以下のように実行します。
$ bundle exec derailed bundle:mem development
CUT_OFF=0.3
のように指定することで、これよりメモリ使用量の大きいファイルだけを表示できます。余分な情報を抑制したい場合に便利です。
メモ: この方法では、Gemfileにある項目だけが表示されます。アプリそのものに含まれているファイルは含まれません。アプリそのものに含まれるファイルのメモリ使用量を表示するには、bundle exec derailed exec mem
を使う必要があります。詳しくは後述します。
複数のライブラリで同じファイルがrequire
されていることがありますが、Railsではファイルのrequire
は一度しか行わないため、そのファイルのコストは、あるファイルを最初にrequire
するライブラリにのみ関連します。この点をわかりやすく表示するため、そのファイルが属しているすべての親で重複エントリを表示します。たとえば、mail
とfog
ではどちらもmime/types
をrequire
しているので、アプリでは次のように表示されます。
$ bundle exec derailed bundle:mem
TOP: 54.1836 MiB
mail: 18.9688 MiB
mime/types: 17.4453 MiB (Also required by: fog/storage)
mail/field: 0.4023 MiB
mail/message: 0.3906 MiB
トップレベルのライブラリ(ここではmail
)を削除してもメモリ使用量が減っていないことがわかりました。出力では最初の2つのエントリ以後は省略されます。
fog/core: 0.9844 MiB (Also required by: fog/xml, fog/json, and 48 others)
fog/rackspace: 0.957 MiB
fog/joyent: 0.7227 MiB
fog/joyent/compute: 0.7227 MiB
fog/core
をrequire
するファイルをすべて表示したい場合は、CUT_OFF=0 bundle exec derailed bundle:mem
を実行してすべてを出力してから手動でgrepすることもできます。
更新情報: 上の例のmime/types
は残念な結果が出ていますが、現在は修正されています。Gemfileの冒頭に以下を追加することでメモリを削減できます。
gem 'mime-types', [ '~> 2.6', '>= 2.6.1' ], require: 'mime/types/columnar'
require
時に作成されるオブジェクト
memory_profilerを使うと、以下を実行することで依存関係がrequire
されたときに作成されるオブジェクトの詳しい情報を取得できます。
$ bundle exec derailed bundle:objects
これによって、依存関係の読み込み時に作成されるオブジェクトの詳しい情報が出力されます。
Measuring objects created by gems in groups [:default, "production"]
Total allocated 433895
Total retained 100556
allocated memory by gem
-----------------------------------
24369241 activesupport-4.2.1
15560550 mime-types-2.4.3
8103432 json-1.8.2
メモリ使用量が甚だしいgemを$ bundle exec derailed bundle:mem
で特定できたら、そのgemを別のGemfileに追加して$ bundle exec derailed bundle:objects
を実行することで詳細な情報を取得できます。この情報は、コントリビュータやライブラリ作者がオブジェクト作成のホットスポットを特定して排除するのに役立ちます。
デフォルトでは、このタスクは:default
グループとproduction
グループの結果のみを返します。他のグループでの結果が欲しい場合は以下のように実行します。
$ bundle exec derailed bundle:objects development
メモ: この方法では、Gemfileにある項目だけが表示されます。アプリそのものに含まれているファイルは含まれません。アプリそのものに含まれるファイルのメモリ使用量を表示するには、bundle exec derailed exec mem
を使う必要があります。詳しくは後述します。
アプリの動的ベンチマーク
このベンチマークでは、Railsアプリを起動してそれに対するベンチマークを試みます。$ bundle exec derailed bundle:*
による静的なベンチマークと異なり、この方法では特定のアプリの情報も取れます。この方法のメリットは、詳細な情報を取得することでアプリコードに潜む問題を特定できることで、デメリットはアプリをローカルでproduction
環境で実行可能にしなければならない点です。アプリによってはローカルでのproduction
環境で簡単に実行できないことがあります。
場合によってはmini-profilerを検討してもよいでしょう。mini-profilerの紹介記事については『mini-profiler walkthrough』をご覧ください。これもよいgemであり、derailed-benchmarkで行えるベンチマークとは少々趣が異なります。
production
環境をローカルで実行する
動的なベンチマークを試みる前に、アプリをproduction
モードで起動できるようにしておく必要があります。production
モードでベンチマークを行う理由は、デプロイ後のパフォーマンスに近づけるためです。本セクションでは、Railsのデファクトのチュートリアルとは異なるヒントをまとめました。
まずはコンソールで実行できるかどうかを試します。
$ RAILS_ENV=production rails console
おそらく、production
のデータベースに接続できないというエラーが表示されるでしょう。この場合、productionデータベースと同じ名前でローカルにデータベースを作成するか、database.yml
のdevelopment
グループの情報をproduction
グループにコピーするかします。
SECRET_KEY_BASE
などのproduction
用環境変数がない可能性もあります。この場合、.env
ファイルをコミットするか(.env
を使っている場合)、以下のように環境変数をコマンドで直接追加します。
$ SECRET_KEY_BASE=foo RAILS_ENV=production rails console
production環境をコンソール起動することに成功したら、今度はサーバーをproductionで起動できるようにする必要があります。
$ RAILS_ENV=production rails server
このとき、SSLの強制やドメインのその他の制限を一時的に無効にする必要があるかもしれません。こうした変更を行ったら、デプロイ前にすべて元に戻すことをお忘れなく(うひゃー!)。
rails_12factor
gemを使っている場合はSTDOUTから、あるいは以下を実行してlog/production.log
から情報を取得できます。
$ tail -f log/production.log
エラーをすべて修正してサーバーをproductionモードで実行できるようになったら、準備はほぼ完了です。
derailed exec
を実行する
アプリに対して$ derailed exec
を実行できるようになりました。この後のいくつかのセクションでは、Rackの設定方法や認証済みリクエストを使う方法についてご紹介します。以下を実行することで利用可能なコマンド一覧を表示できます。
$ bundle exec derailed exec --help
$ derailed exec perf:allocated_objects # outputs allocated object diff after app is called TEST_COUNT times
$ derailed exec perf:gc # outputs GC::Profiler.report data while app is called TEST_COUNT times
$ derailed exec perf:ips # iterations per second
$ derailed exec perf:mem # show memory usage caused by invoking require per gem
$ derailed exec perf:objects # profiles ruby allocation
$ derailed exec perf:mem_over_time # outputs memory usage over time
$ derailed exec perf:test # hits the url TEST_COUNT times
ここでは個別のコマンドについては解説せず、よくある問題とそれを診断するのに最適なコマンドを見ていくことにします。derailed_benchmarksの設定で使えるすべての環境変数については、この後別途セクションを設けて解説します。
アプリのメモリリークを調べる
アプリのメモリ総量が増加し続けていてメモリリークが疑われる場合、それが本当にどこにもバインドされない「リーク」なのか、単にメモリ使用量が予想より大きいだけなのかを最初に検証したいでしょう。真のメモリリークではメモリ使用量が際限なく増加し続けますが、多くのアプリのメモリ使用量増加はある時点で「頭打ち」になります。これを診断するには以下を実行します。
$ bundle exec derailed exec perf:mem_over_time
このコマンドは、アプリを起動してリクエストを送信し、メモリをSTDOUT(および./tmp
以下のファイル)に出力します。出力は次のような感じになります。
$ bundle exec derailed exec perf:mem_over_time
Booting: production
Endpoint: "/"
PID: 78675
103.55078125
178.45703125
179.140625
180.3671875
182.1875
182.55859375
# ...
183.65234375
183.26171875
183.62109375
この結果を見ると、メモリ使用量は増加し続けているものの、183 MiBあたりで横ばいになっています。以下のようにTEST_COUNT=
の値を順次増やしながらこのタスクを実行することもできます。
$ TEST_COUNT=5000 bundle exec derailed exec perf:mem_over_time
$ TEST_COUNT=10_000 bundle exec derailed exec perf:mem_over_time
$ TEST_COUNT=20_000 bundle exec derailed exec perf:mem_over_time
適切な総時間が得られるようにTEST_COUNT=
の値を適宜調整します。メモリ増加が天井知らずになっていれば、まさしくメモリリークです。これらの出力結果をファイルからGoogle Documentsにコピーしてグラフ化すれば、メモリ使用量が上昇する様子をよりよく把握できます。
生成した結果をtmpファイルに出力したくない場合は、SKIP_FILE_WRITE=1
を指定して実行します。
メモリリークが発生していることがある程度確信できるものの、この方法で確認できなかった場合は、後述の環境変数オプションのセクションを参照して、リクエスト送信先のエンドポイントをさまざまに変えながら試してみるとよいでしょう。
メモリリークを解剖する
メモリリークを突き止めることができた場合や、メモリがどこで使われているかを単に知りたい場合は、以下を実行できます。
$ bundle exec derailed exec perf:objects
上のタスクは、アプリにリクエストを送信し、memory_profileを用いてオブジェクトが作成されている箇所を表示します。このコマンドを1度実行した後、TEST_COUNT
の値を増やして再実行すれば、すべての要求ごとにオブジェクトが作成されるホットスポットを最初の実行結果と比較しながら見つけることもできます。
$ TEST_COUNT=10 bundle exec derailed exec perf:objects
この操作はコストが高いので、TEST_COUNT
の値をなるべく低くしておきたいと思うことでしょう。ホットスポットを突き止められたら、「how ruby uses memory」を読んでオブジェクトのアロケーションを減らす方法をお読みください。
このコマンドは$ bundle exec derailed bundle:objects
と似ていますが、実行時に作成されたオブジェクトも出力される点が異なります。そのため、実際のproductionのパフォーマンスをデバッグする場合に非常に有用です。$ bundle exec derailed bundle:objects
の方はライブラリ作者がデバッグするのに向いています。
ヒープをダンプする
ランタイム時のメモリ使用量の問題がまだ解決できない場合は、ヒープダンプを生成してからheap_inspect(heapy)で分析することもできます。
$ bundle exec derailed exec perf:heap
Booting: production
Heap file generated: "tmp/2015-10-01T12:31:03-05:00-heap.dump"
Analyzing Heap
==============
Generation: 0 object count: 209307
Generation: 35 object count: 31236
Generation: 36 object count: 36705
Generation: 37 object count: 1301
Generation: 38 object count: 8
Try uploading "tmp/2015-10-01T12:31:03-05:00-heap.dump" to http://tenderlove.github.io/heap-analyzer/
ヒープダンプからデータを取得する方法の詳細については、以下を実行します。
$ heapy --help
起動時のメモリ使用量が大きい場合
Rubyのメモリ使用量は、増加の一途をたどるのが普通です。アプリ起動時のメモリ使用量が大きい場合、増加することはあっても減少することはないでしょう。$ derailed bundle:mem
で取得した依存関係によって使われるメモリ使用量をデバッグするほかに、自分のファイルがメモリ使用量をどれだけ増やしているかを知りたいこともあるでしょう。
ここでご紹介するタスクも本質的には同じですが、アプリにリクエストを1件だけ送信して、require
が直前の1分間にすべて呼び出されるようにします。これを行うには、以下を実行します。
$ bundle exec derailed exec perf:mem
TOP: 54.1836 MiB
mail: 18.9688 MiB
mime/types: 17.4453 MiB
mail/field: 0.4023 MiB
mail/message: 0.3906 MiB
action_view/view_paths: 0.4453 MiB
action_view/base: 0.4336 MiB
表示するメモリ使用量を足切りしたい場合は、CUT_OFF=0.3
のように指定することで、これよりメモリ使用量の大きいファイルだけを表示できます。余分な情報を抑制したい場合に便利です。
アプリ起動時のコード量が極端に多い場合は、低レベルのオブジェクト作成を$ derailed exec perf:objects
でデバッグすることをご検討ください。
アプリが遅い
他にも何か起きているかもしれません。既にオブジェクトのアロケーション削減を詳細に検討したのであれば、アプリのどのコードの実行量が最も多いかを知りたいと思うことでしょう。それがわかれば、どの最適化に時間をかければよいかもわかります。
ひとつの方法は、stack profilerの「サンプリング」を使うことです。このプロファイリングは、指定の期間内にどのメソッドが実行されているかを調べて記録します。実行が終わったら、それらのメソッドが呼び出された回数をすべてカウントして、実行時間に占める割合をメソッドごとにパーセントで表示します。この手法では、実行時間の調査におけるオーバーヘッドはほとんどありません。Ruby 2.1以上であれば、stackprofというgemを使って行えます。ご想像のとおり、このgemはderailed_benchmarksでも実行できます。Gemfileにgem "stackprof", group: :development
を追加して以下を実行します。
$ bundle exec derailed exec perf:stackprof
==================================
Mode: cpu(1000)
Samples: 16067 (1.07% miss rate)
GC: 2651 (16.50%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
1293 (8.0%) 1293 (8.0%) block in ActionDispatch::Journey::Formatter#missing_keys
872 (5.4%) 872 (5.4%) block in ActiveSupport::Inflector#apply_inflections
935 (5.8%) 802 (5.0%) ActiveSupport::SafeBuffer#safe_concat
688 (4.3%) 688 (4.3%) Temple::Utils#escape_html
578 (3.6%) 578 (3.6%) ActiveRecord::Attribute#initialize
3541 (22.0%) 401 (2.5%) ActionDispatch::Routing::RouteSet#url_for
346 (2.2%) 346 (2.2%) ActiveSupport::SafeBuffer#initialize
298 (1.9%) 298 (1.9%) ThreadSafe::NonConcurrentCacheBackend#[]
227 (1.4%) 227 (1.4%) block in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache
218 (1.4%) 218 (1.4%) NewRelic::Agent::Instrumentation::Event#initialize
1102 (6.9%) 213 (1.3%) ActiveSupport::Inflector#apply_inflections
193 (1.2%) 193 (1.2%) ActionDispatch::Routing::RouteSet::NamedRouteCollection::UrlHelper#deprecate_string_options
173 (1.1%) 173 (1.1%) ActiveSupport::SafeBuffer#html_safe?
308 (1.9%) 171 (1.1%) NewRelic::Agent::Instrumentation::ActionViewSubscriber::RenderEvent#metric_name
159 (1.0%) 159 (1.0%) block in ActiveRecord::Result#hash_rows
358 (2.2%) 153 (1.0%) ActionDispatch::Routing::RouteSet::Generator#initialize
153 (1.0%) 153 (1.0%) ActiveRecord::Type::String#cast_value
192 (1.2%) 143 (0.9%) ActionController::UrlFor#url_options
808 (5.0%) 127 (0.8%) ActiveRecord::LazyAttributeHash#[]
121 (0.8%) 121 (0.8%) PG::Result#values
120 (0.7%) 120 (0.7%) ActionDispatch::Journey::Router::Utils::UriEncoder#escape
2478 (15.4%) 117 (0.7%) ActionDispatch::Journey::Formatter#generate
115 (0.7%) 115 (0.7%) NewRelic::Agent::Instrumentation::EventedSubscriber#event_stack
114 (0.7%) 114 (0.7%) ActiveRecord::Core#init_internals
263 (1.6%) 110 (0.7%) ActiveRecord::Type::Value#type_cast
8520 (53.0%) 102 (0.6%) ActionView::CompiledTemplates#_app_views_repos__repo_html_slim__2939326833298152184_70365772737940
後は個別のメソッドを調べます。
変更の結果パフォーマンスが向上するかをチェックする
コードレベルでのパフォーマンス改善の度合いはマイクロベンチマークである程度見当がつきますが、アプリ全体のスピード向上を知るにはどうしたらよいでしょうか。アプリのパフォーマンス上の変更がどのぐらい有効かを知りたい場合、既存アプリのパフォーマンスと比較できると便利です。そんなときは以下のコマンドが役立ちます。
$ bundle exec derailed exec perf:ips
Endpoint: "/"
Calculating -------------------------------------
ips 1.000 i/100ms
-------------------------------------------------
ips 3.306 (± 0.0%) i/s - 17.000
このコマンドは、benchmark-ips gemを用いてアプリのエンドポイントにリクエストを送信します。1秒あたりの繰り返し(ips: iterations per second)では、値が大きいほどパフォーマンスが高いことを常に意味します。変更後のコードをこの方法を用いて何度も実行し、続いてトータルのパフォーマンス向上を「ベースライン」コードベース(変更なしの場合)を実行します。実行を何度も繰り返して結果を(標準偏差も含めて)記録すればノイズの抑制に役立ちます。ベンチマークは大変な作業であり、この手法も完璧ではありませんが、何もしないよりはずっとよい結果を得られるのは間違いありません。
気になるのであれば、以下のようにipsなしの純粋なベンチマークを実行することもできます。
$ bundle exec derailed exec perf:test
ただし私ならこの方法は使わないでしょう。ipsありのベンチマークの方が測定方法として良好だからです。
環境変数
どのタスクについても、以下の環境変数を使って設定を与えることができます。
TEST_COUNT
: テスト回数の増減
実行回数の多いタスクで、次のようにTEST_COUNT
を使って実行回数を指定できます。
$ TEST_COUNT=100_000 bundle exec derailed exec perf:test
WARM_COUNT
: 測定前にアプリをウォーミングアップする回数
アプリを長時間に渡って測定する場合、特にJITを使っている場合は、測定時間とは別の「ウォーミングアップ」期間をアプリに与えるものです。WARM_COUNT
を用いて、測定開始前のアプリ呼び出し回数を指定できます。
$ WARM_COUNT=5_000 bundle exec derailed exec perf:test
Warming up app: 5000 times
# ...
PATH_TO_HIT
: リクエスト送信先のエンドポイントの変更
デフォルトのタスクでは、ルート/
に対してリクエストを送信します。別のURLにリクエストを送信したい場合は、PATH_TO_HIT
を使います。たとえば、users/new
を叩くには以下を実行します。
$ PATH_TO_HIT=/users/new bundle exec derailed exec perf:mem
この方法では完全なURLも指定できます。たとえば以下はサブドメインのエンドポイントを叩きます。
$ PATH_TO_HIT=http://subdomain.lvh.me:3000/users/new bundle exec derailed exec perf:mem
注意: 完全なURLは、USE_SERVER
変数と併用できません。
HTTPヘッダの設定
次のようにHTTP_<ヘッダ名>
環境変数を設定することで、HTTPヘッダを指定できます。
$ HTTP_AUTHORIZATION="Basic YWRtaW46c2VjcmV0\n" \
HTTP_USER_AGENT="Mozilla/5.0" \
PATH_TO_HIT=/foo_secret bundle exec derailed exec perf:ips
USE_SERVER
: 実際のWebサーバーの指定
すべてのテストは「Webサーバーなし」で実行されます(デフォルトではRack::Mock
を直接使います)。Webサーバーを使いたい場合は、USE_SERVER
にRack::Server互換サーバー(webrick
など)を設定します。
$ USE_SERVER=webrick bundle exec derailed exec perf:mem
pumaも指定できます。
$ USE_SERVER=puma bundle exec derailed exec perf:mem
この指定によってWebサーバーが起動し、メモリ内ではなくcurl
を使ってリクエストを送信します。これは、パフォーマンスの問題がWebサーバーに関連すると考えられる場合に便利です。
メモ: この方法では指定のWebサーバーをRackに直接接続するため、設定済みのpuma.config
ファイルなどは使われません。設定ファイルを使いたい方からのアイデアやプルリクをお待ちしています。
ActiveRecordを除外する
derailed_benchmarksは、依存関係としてActiveRecord gemが含まれている場合はデフォルトで読み込みます。ActiveRecordはRailsのデフォルトgemなので、rails
gemを使えば読み込まれます。別のORMを使っている場合は、railties
だけを読み込むようにするか、DERAILED_SKIP_ACTIVE_RECORD
フラグを設定します。
$ DERAILED_SKIP_ACTIVE_RECORD=true
別の環境で実行する
デフォルトではproduction環境でテストを実行しますが、ローカルのRAILS_ENV
がproduction
に設定された環境でアプリが動かない場合は次のように簡単に変更できます。
$ RAILS_ENV=development bundle exec derailed exec perf:mem
perf.rake
derailed_benchmarksをカスタマイズしたい場合は、ベンチマークを行うプロジェクトのルートディレクトリにperf.rake
ファイルを作成する必要があります。
rake
を直接使ってベンチマークを実行できます。
$ cat << EOF > perf.rake
require 'bundler'
Bundler.setup
require 'derailed_benchmarks'
require 'derailed_benchmarks/tasks'
EOF
perf.rake
ファイルの内容は次のような感じになります。
$ cat perf.rake
require 'bundler'
Bundler.setup
require 'derailed_benchmarks'
require 'derailed_benchmarks/tasks'
上の設定を使うと、アプリより先にベンチマークが読み込まれます。これはベンチマークによっては重要なことがありますが、さほど重要でないこともあります。この設定では、ベンチマークが不要な場合に誤って読み込まれることも防げます。
続いて、rake
を使ってコマンドを実行できます。
$ rake -f perf.rake -T
を使って、実行可能なタスクの一覧を見つけることもできます。このコマンドは本質的に、perf.rake
ファイルを用いてすべてのタスク一覧を表示しているだけです。
$ rake -f perf.rake -T
Rackのセットアップ
Railsをお使いであれば、特別な設定は不要です。Rackをお使いの場合は、アプリの起動方法の指定が必要です。以下のようにperf.rake
ファイルにタスクを追加します。
namespace :perf do
task :rack_load do
DERAILED_APP = # ここにコードを書く
end
end
DERAILED_APP
定数には、Raskアプリの名前を設定します。詳しくはプルリク#1をご覧ください。
perf.rake
の設定例は次のようになります。
# perf.rake
require 'bundler'
Bundler.setup
require 'derailed_benchmarks'
require 'derailed_benchmarks/tasks'
namespace :perf do
task :rack_load do
require_relative 'lib/application'
DERAILED_APP = MyApplication::Routes
end
end
認証
認証が行われているエンドポイントをテストする場合は、認証のバイパス方法をタスクで指定する必要があります。認証はDerailedBenchmarks.auth
オブジェクトで管理されます。derailed_benchmarksにはDeviseのサポートが組み込まれています。他の認証方法を使っている場合は、独自の認証ストラテジーを記述することもできます。
テストで認証を有効にするには以下を実行します。
$ USE_AUTH=true bundle exec derailed exec perf:mem
認証のカスタマイズ方法については後述します。
Deviseでの認証
Deviseをお使いの場合は、Devise gemの存在を検出して自動で読み込まれる組み込みの認証ヘルパーを使えます。
プロジェクトのルートディレクトリにperf.rake
ファイルを作成します。
$ cat perf.rake
ログインユーザーをカスタマイズするには、perf.rake
ファイルで以下のように設定します。
DerailedBenchmarks.auth.user = -> { User.find_or_create!(twitter: "schneems") }
有効なユーザーを指定する必要があります。user.rb
でのバリデーション方法によっては、パラメータを変える必要があるかもしれません。
User
モデルを使わない認証を行う場合は、独自の認証ストラテジーを書く必要があります。
独自の認証ストラテジー
独自の認証ストラテジーを実装するには、auth_helper.rbを継承するクラスの作成と、setup
メソッドとcall
メソッドの実装が必要です。Devise認証ヘルパーのサンプルコードについてはauth_helpers/devise.rbをご覧ください。以下のコードをperf.rake
ファイルに書けます。
class MyCustomAuth < DerailedBenchmarks::AuthHelper
def setup
# 初期化コードをここに書く
end
def call(env)
# リクエストごとのログを何か出力する
app.call(env)
end
end
Deviseのストラテジーは、Rackリクエストの内部でテストモードを有効にしてスタブユーザーを挿入することで動作するようになります。Deviseを使っていない場合は、この部分のロジックを複製して独自の認証スキームを作成する必要があります。
クラスを作成したら、クラスの新しいインスタンスにDerailedBenchmarks.auth
を設定する必要があります。perf.rake
ファイルに以下を追加します。
DerailedBenchmarks.auth = MyCustomAuth.new
これにより、USE_AUTH
環境変数を使って設定されたすべてのリクエストで、MyCustomAuth#call
メソッドが呼び出されるようになります。
ライセンス
MIT
献辞
コマンドの多くは他のライブラリのラッパーですので、チェックしてみてください。$ rake perf:setup
のRails初期化コードの一部については、@tenderloveのとあるプロジェクトのコードを使いましたので、ここにお礼を申し上げます。
アリガトソレジャマタ @schneems