rack-mini-profiler の flamegraph から機械可読な stackprof データを抜いて集計する
rack-mini-profiler が動いている環境では
?pp=flamegraph でフレームグラフが見れる。ただしこの出力は人間用の speedscope HTML なので、AI/エージェントには読めない。
そこで、その HTML 内に埋め込まれた
var graph = を抜く。これは生の stackprof JSON (raw 形式: mode / interval / samples / frames …) なので、機械可読に集計できる。何も追加で仕込まずに済み、再現可能で、対策の before/after を同じ方法で定量比較できるのが利点。
手順1: flamegraph HTML を取得して graph JSON を抜く
wall モードで取得する (cpu / object / custom も可)。認証が要るページなら Cookie 等を適宜付ける。
bashcurl -s "https://example.com/<PATH>?pp=flamegraph&flamegraph_mode=wall&flamegraph_sample_rate=1" \ -o /tmp/flame.html# var graph = {...}; の 1 行を取り出して JSON 化grep -m1 'var graph = ' /tmp/flame.html | sed -E 's/^[[:space:]]*var graph = //; s/;[[:space:]]*$//' > /tmp/graph.json手順2: 集計する
frames の
samples が self、 total_samples が total。ホットスポットは self% で見る。pythonimport json; g=json.load(open('/tmp/graph.json')); S=g['samples']rows=[(v.get('name'),v.get('samples',0),v.get('total_samples',0)) for v in g['frames'].values()]for n,s,t in sorted(rows,key=lambda r:-r[1])[:25]: print(f"{s:5d} {100*s/S:4.1f}% tot={t:5d} {n}")print("wall~%.0fms samples=%d gc=%d"%(S*g['interval']/1000, S, g['gc_samples']))注意
middleware フレームは total ≒ 100% になる (リクエスト全体をラップしているだけ) ので、ボトルネック特定は total ではなく self を見ること。
self 時間を用途ごと (例: DB/ORM の属性アクセス、文字列生成、GC の
(sweeping) / (marking) 、IO 待ちの Kernel.select など) に束ねると傾向が掴みやすい。束ね方はアプリ依存。 flamegraph_mode は wall / cpu / object / custom。 flamegraph_sample_rate はサンプリング間隔 (ms)。 全オプションは
?pp=help で確認できる。---