こんにちは、ロージーです。今回は手前味噌 gem である、 speed_gun の活用方法について解説します。
SpeedGun とは
more better performance profiler for rails or rack として開発されたパフォーマンス測定 gem です。
もっと詳しい解説記事はこちら。
今回、 speed_gun そのものの解説は割愛します。
まずは使ってみる
サンプルアプリを作って、 speed_gun を導入します。まずは Rails アプリを作ります。
$ rails new speed_gun_example
...
これで、とりあえずひな形が出来上がりました。次は Gemfile に speed_gun を追加します。
$ echo "gem 'speed_gun'" >> Gemfile
$ bundle install
$ bundle list | grep speed_gun
* speed_gun (0.0.1)
しっかり導入されていますね。じゃあ早速ですが Rails を起動しましょう!
$ bundle exec rails s
この状態で http://localhost:3000/ にアクセスすると、しっかり speed_gun が稼働しています。Rails の Welcome ページが表示され、右下に ***ms と小さな表示が出ていますね。
この表示をクリックすると、 speed_gun の詳細画面を見ることが出来ます。
Rack は 30ms ほどで返しているのに、ブラウザ側で DOM のパースや画像のロードに時間がかかり、結局全部終わって document の load イベントが発火しているのはアクセス開始から 300ms 後……などの情報がわかります。
このままでも ActiveRecord のクエリの実行時間や、 ActionView がレンダリングするビューの処理時間、 ActionController の処理時間など、様々な情報がわかりますが、せっかくなので他にもいろんなものを計測してみましょう。
Rails の特定部分の処理を計測する
まずは適当に scaffold します。
$ bundle exec rails g scaffold Post title:string body:string
$ bundle exec rake db:migrate
この状態で http://localhost:3000/posts へアクセスすれば、それっぽい画面が出ているはずです。
さて、ではこの Post の表示時に、 body を markdown で表示できるようにしましょう。
markdown gem を導入して……
$ echo "gem 'markdown'" >> Gemfile
$ bundle install
Post
モデルに #body_with_markdown
を実装します。
class Post < ActiveRecord::Base
def body_with_markdown
Markdown.new(body).to_html
end
end
あとは app/views/posts/show.html.erb
で #body_with_markdown
を使うようにするだけですね。
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @post.title %>
</p>
<p>
<strong>Body:</strong>
</p>
<div class="markdown">
<%== @post.body_with_markdown %>
</div>
<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
これで投稿内容が markdown を解釈して HTML で表示されるようになりました。
ここで、 speed_gun を使って #body_with_markdown
のプロファイリングをしてみましょう。
先ほど実装した Post#body_with_markdown
を以下のように書き換えます。
def body_with_markdown
SpeedGun.profile('Post#body_with_markdown') do
Markdown.new(body).to_html
end
end
この状態でもう一度実行すると、 Manual: Post#body_with_markdown
という項目が speed_gun の詳細画面に追加されていると思います。
このように speed_gun なら簡単にプロファイリングを行うことが出来ます。
カスタムプロファイラでメソッド監視
speed_gun ならカスタムプロファイラを使ったメソッド監視も簡単に実装できます。
config/initializers/markdown_profile.rb
に以下のようなカスタムプロファイラを作ります。
require 'speed_gun/profiler/base'
require 'markdown'
class MarkdownProfiler < SpeedGun::Profiler::Base
hook_method Markdown::Wrapper, :to_html
end
#to_html
は Markdown::Wrapper
に定義されているので、そこにフックしています。あとは Rails を再起動してもう一度 Post の個別ページをみると、 MarkdownProfiler
という項目が増えていますね。
筆者の環境だと Post#body_with_markdown
が 118ms で #to_html
が 105ms なので、 Markdown.new
にかかっている時間は大体 13ms ぐらいなのでしょうか?みたいなことを考えることが出来ます。
Javascript のパフォーマンスだってちゃんと見たい
Rails のパフォーマンスと言うと、どうしても Ruby のコードそのものだけに注視しがちですが、リッチコンテンツを扱うこのご時世ですから、 Javascript のパフォーマンスだってちゃんと考えてあげなくてはいけません。
ということで、試しに Javascript で適当な処理を作りましょう。絵文字処理とかいいですね。やりましょう。
gemoji gem を導入します。
$ echo "gem 'gemoji'" >> Gemfile
$ bundle install
module SpeedGunExample
class Application < Rails::Application
config.assets.paths << Emoji.images_path
end
end
では、肝心の置換処理です。
jQuery(($) ->
$('.markdown p').each((index, paragraph) ->
paragraph = $(paragraph)
original = paragraph.html()
paragraph.html(original.replace(/:(\w+?):/g, (matched) ->
"<img class=\"emoji\" src=\"/assets/emoji/#{RegExp.$1}.png\"></img>"
))
)
)
ずいぶん適当ですが、なにはともあれ、絵文字を表示することが出来ました。では、この JS 処理をプロファイリングしましょう。
jQuery(($) ->
speedGun.profile('Emoji', () ->
$('.markdown p').each((index, paragraph) ->
paragraph = $(paragraph)
original = paragraph.html()
paragraph.html(original.replace(/:(\w+?):/g, (matched) ->
"<img class=\"emoji\" src=\"/assets/emoji/#{RegExp.$1}.png\"></img>"
))
)
)
)
単に処理部分を speedGun.profile
でくくってあげただけです。
こうしてくくっておくことで、 JS のプロファイル結果をサーバー側に送信し、ためておくことが出来ます。もちろん、ここでとったプロファイルは speed_gun の詳細画面からも見ることが出来ます。
まとめ
speed_gun には他にも SpeedGun::Hook
などの便利な機能も存在していますが、今回は割愛します。
また、 speed_gun の詳細画面には Navigation Timing API を用いて、レンダリングやリダイレクトにかかった時間も表示されています。
他にも様々な活用法があると思うので、ぜひお試しください。