Rubyのプロファイラメモ
Rubyのプロファイラを活用することで、プログラムの実行速度や使用リソースの収集ができます。 そして、そのプロファイル結果を解析することで、コードのボトルネックを把握し、パフォーマンスチューニングを効率的に実施していけます。
プロファイラとは何か
プロファイラとは、プログラムの実行時にパフォーマンス情報を収集するツールです。プログラムの各部分の実行時間や、使用リソースなどを詳細に解析できます。プロファイラを使用することで、パフォーマンス上のボトルネックを特定し、最適化を行うことができます。
プロファイラには主に、実行速度の最適化とリソース使用量の最適化のケースで利用されます。
- 実行速度の最適化では、プログラムの各部分がどの程度の時間を要しているかを確認することで、チューニングが必要な箇所を特定します。
- リソース使用量の最適化では、オブジェクトの割り当てやメモリ使用量など、リソースの利用状況を分析し、リソース使用量の最適化をはかることができます。
Rubyのプロファイリングをするgem
Rubyの主要なプロファイリングを行うgemにはいくつかあります。
名前 | Star数 (23/4時点) | 説明 |
---|---|---|
2k | Rubyプログラムの実行速度をプロファイルする高速なコードプロファイラ。 | |
2k | サンプリングしたコールスタックのプロファイラ | |
3.5k | HTMLにプロファイル結果を表示するプロファイラ |
他にも、メモリ消費やガベージコレクタの動作を詳細に分析できる memory_profiler やRSpecやFactoryBotなどテストをプロファイルできる test-prof などがあります。
ruby-profの使い方
gemのインストール
gem 'ruby-prof'
Rackアプリケーションへの設定方法
require 'ruby-prof'
# 計測方法(経過時間、プロセス時間、オブジェクト割り当て、メモリを測定できる)
RubyProf.measure_mode = RubyProf::WALL_TIME
# Rackアプリケーションで特定のパスをプロファイル
use Rack::RubyProf, path: 'tmp/ruby-prof', only_paths: [%r{/api/v1/users}]
レポート形式はテキスト、HTML、グラフなどいろいろある。
詳細の使い方は ruby-prof を確認してください。
stackprofの使い方
gemのインストール
gem 'stackprof'
Rackアプリケーションへの設定方法
require 'stackprof'
mode = :wall # cpu, object, custom などできる
use StackProf::Middleware,
enabled: true,
mode:,
interval: 1000,
save_every: 5,
# raw: true,
path: "tmp/stackprof-#{mode}-myapp.dump"
dumpファイルを stackprof
コマンドで解析する
$ stackprof tmp/stackprof-cpu-*.dump --text --limit 10
==================================
Mode: cpu(1000)
Samples: 17 (34.62% miss rate)
GC: 1 (5.88%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
7 (41.2%) 7 (41.2%) MyApp#do_slow_stuff
3 (17.6%) 3 (17.6%) IO#set_encoding
6 (35.3%) 3 (17.6%) Kernel#require
1 (5.9%) 1 (5.9%) (marking)
1 (5.9%) 1 (5.9%) Mysql2::Client#connect
1 (5.9%) 1 (5.9%) Mysql2::Client#_query
1 (5.9%) 1 (5.9%) Hash#delete
16 (94.1%) 0 (0.0%) Sinatra::Base#invoke
16 (94.1%) 0 (0.0%) Sinatra::Base#call!
16 (94.1%) 0 (0.0%) Sinatra::Base#call
コードのどの部分が遅いかもみれる
$ stackprof tmp/stackprof-wall-*.dump --text -m --file app.rb
| 103 | get '/api/v1/users' do
10 (4.0%) | 104 | users = select_users
| 105 |
233 (92.1%) | 106 | do_slow_stuff
| 107 |
6 (2.4%) | 108 | json(status: true, data: { users: })
| 109 | end
| 110 |
| 111 | def select_users
| 112 | users = []
| 113 |
10 (4.0%) | 114 | mysql_db.query('SELECT id, name FROM users').each do |row|
| 115 | users.push({
| 116 | id: row[:id],
| 117 | name: row[:name],
| 118 | })
| 119 | end
| 120 | end
| 121 |
| 122 | def do_slow_stuff
233 (92.1%) | 123 | 1_000_000.times.each do |n|
| 124 | n + 1
233 (92.1%) / 233 (92.1%) | 125 | end
詳細な使い方は tmm1/stackprof を確認してください。
rack-mini-profilerの使い方
gemのインストール
gem 'rack-mini-profiler'
Rackアプリケーションに設定
require 'rack-mini-profiler'
use Rack::MiniProfiler
HTMLの画面を開くとプロファイル結果が表示される
参考: プロファイル結果の出力例の対象コード
上記のプロファイルの出力結果のコード
# sinatraで書いています
get '/api/v1/users' do
users = select_users
do_slow_stuff
json(status: true, data: { users: })
end
def select_users
users = []
mysql_db.query('SELECT id, name FROM users').each do |row|
users.push({
id: row[:id],
name: row[:name],
})
end
end
def do_slow_stuff
1_000_000.times.each do |n|
n + 1
end
end