Singed、Ruby および Rails アプリケーション用のプロファイラー フロントエンド

May 09 2023
Ruby コードのブロック、特定の Web リクエスト、特定のコントローラー アクションの実行速度が非常に遅い理由を理解したいと思ったことはありませんか? おそらく、過去に speedscope などのプロファイリング ツールを使用したことがありますが、面倒であると感じたり、それらの使用方法を試してみましたが理解できなかったりすることがあります。Josh Nichols (別名 @technicalpickles) によって書かれた、Gusto の新しいプロファイリング フロントエンドである Singed を紹介します。

Ruby コードのブロック、特定の Web リクエスト、特定のコントローラー アクションの実行速度が非常に遅い理由を理解したいと思ったことはありませんか? おそらく、過去に speedscope などのプロファイリング ツールを使用したことがありますが、面倒であると感じたり、それらの使用方法を試してみましたが理解できなかったりすることがあります。

flamegraph: 何でも…それだけです!

Josh Nichols (別名 @technicalpickles)によって書かれた、Gusto の新しいプロファイリング フロントエンドであるSingedを紹介します。Singed は、いくつかのツール ( stackprof、rbspy、およびspeedscope )のスイス アーミー ナイフ フロントエンドとして構築されており、フレームグラフを簡単にキャプチャして表示するのに役立ちます。 .

別のプロファイリング ツールを使用する理由

Singed はカーネルに新しいメソッドを追加し、どこでも利用できます:

flamegraph {
  # your code here
}

主に、フレームグラフを調べたいほとんどの Ruby 開発者は、stackprofの優れた使いやすいフロントエンドであるrack-mini-profilerを使用します。URL の末尾に?pp=flamegraph を追加するだけで、ブラウザでフレームグラフが開きます。

ただし、ブラウザーのナビゲーション バーにある現在の URL だけでなく、プロファイルを作成したいことがよくあります。

たとえば、Apollo のようなゲートウェイを介して行われる GraphQL リクエストをプロファイリングしたい場合があります。Apollo Gateway がリクエストを作成するために使用しているURL を簡単に見つけることができない場合があるため、rack-mini-profiler を複製して使用してフレームグラフをキャプチャすることは困難です。

または、Ruby コードのブロックやバックグラウンド ジョブ、さらにはテストをプロファイリングしたい場合もあります。これを行う独自のコードを記述して、自分で stackprof を呼び出すこともできますが、出力をファイルにリダイレクトするには数十行のボイラープレートが必要であり、おそらくブラウザで手動で開く必要があります。

Speedscope、Stackprof、rbspy を使用する理由

Singed は、基本的に 3 つの異なるツールのラッパーです。

  • Speedscope、フレームグラフ ビジュアライザー。
  • Ruby 用のサンプリング プロファイラーであるstackprof 。
  • rbspy は、Ruby 用の別のサンプリング プロファイラーで、Rust で記述されています。
Speedscope のビジュアライザーは、大きなプロファイルでも美しく、非常に高速です。

stackprof は、Ruby のサンプリング プロファイラーです。これは Ruby VM の C 拡張であるため、Ruby プロセスと同時に「開始」する必要があります。rbspy の動作は異なります。実際には sudo 権限を使用して、Ruby プロセスのメモリを外部から読み取ります。そのため、いつでも Ruby プロセスにアタッチできます。これが、Singed がこれを使用して CLI から Ruby プロセスをプロファイリングする理由です。

stackprof や rbspy などのサンプリング プロファイラーは、より大きなコードベースに非常によくスケーリングされるため、優れた選択肢です。ruby-profなどのプロファイラーのトレースは、アプリケーションの実行に大量のコードが含まれるため、Gusto スケールでは失敗する傾向があります。

最後に、stackprof と rbspy はコミュニティで多くのサポートを受けています。たとえば、新しい Ruby バージョンをサポートするためにプロファイラーを独自にアップグレードする必要はありません。

クイック機能ツアー

Singed が実際にできることを簡単に見てみましょう。Singed を使用する私のお気に入りの方法の 1 つは、Rails アプリで単純なコード ブロックをプロファイリングすることです。

たとえば、バックグラウンド ジョブ MyWorker のプロファイルを作成したいとします。myprofile.rb という名前のファイルを作成し、Rails アプリケーションのルートに配置して、以下を追加します。

user = User.first
flamegraph { MyWorker.new.perform(user) }

bin/rails runner myprofile.rb

プロファイルに関してよく遭遇するもう 1 つの問題は、コードの一部をプロファイルするために必要な状態を設定するのが非常に複雑な場合があることです。非常に特定のデータベース状態が必要な場合や、最初に大量のコードを実行する必要がある場合があります。多くの場合、このセットアップはテストに既に存在します。

Singed を使用すると、テストのプロファイリングが非常に簡単になります。これはもちろん、テストスイートをプロファイリングして最適化できることを意味しますが、実際には、多くの特定の設定が必要なコードをプロファイリングする場合により便利です。

require 'singed/rspec'
RSpec.describe YourClass do
  it "is slow :(", flamegraph: true do
    # your code here
  end
end

Singed のもう 1 つの使用例は、リクエストのプロファイリングです。Gusto には、Rails バックエンドにリクエストを送信する GraphQL ゲートウェイ (Apollo) があります。時々、それらのリクエストをプロファイリングしたいのですが、Apollo バックエンドが Rails に送信している URL とリクエスト ボディがわからないため、rack-mini-profiler を使用してこれを行うのは非常に困難です。代わりに、Singed では次のことを行います。

  • フロントエンドから GraphQL バックエンド リクエストをトリガーします。
  • Chrome DevTools で、そのリクエストを「as fetch」でコピーします。これにより、Javascript コンソールに貼り付けて、この 1 つの GraphQL リクエストをオンデマンドでトリガーできます。
  • バックエンド サーバーを停止して再起動します。今回は SINGED_MIDDLEWARE_ALWAYS_CAPTURE=1 環境変数を追加します。
  • Javascript コンソールで再度リクエストをトリガーします。

Rails アプリケーションのブートを簡単にプロファイリングすることもできます。

bundle binstub singed
bin/singed -- bin/rails runner 'true'

多くの用途を持つプロファイラー フロントエンド

うまくいけば、Singed を試すように説得できました。ここガストではほぼ毎日使っています。

これが興味深いと思ったら、GitHub でチェックしてください。