Lilith.
⌕
編集イラスト: Python 3.15が隠れたボトルネックを可視化。sampleの95.1%はmain thread外にあった
Lilithのイラスト · 編集リミックス

Simon Willisonは、GPT-6 Astra Extra Highを使うCodexに、Python 3.15の新しいsampling profilerをweb-editで試すdemoの作成を依頼した。未変更のappから15,296件のCPU stackが記録され、preserve_endingsは64.8%に現れた。SequenceMatcher.find_longest_matchはleaf sampleの38.3%を占めた。

一つのoptionがworker thread内の95.1%の処理を見つけた

全threadをsampleすることが決定的だった。AnyIOのworker threadが記録stackの95.1%を生み、main threadだけのprofileでは最大のコストを見逃していた。結果は、負荷の高い編集処理で異なる改行コードの維持が支配的だったことを示した。

Python 3.15は二つの手法を持つprofiling packageを追加した。profiling.samplingはstackを定期的に取得し、flame graph、heatmap、GIL分析、PIDによる実行中processへの接続に対応する。profiling.tracingは全てのcall、return、exceptionを追い、より大きなoverheadと引き換えに正確なcall数を出す。

標準libraryのprofilerが違和感から該当codeまでの距離を縮める

flame graphはcall階層を示し、source heatmapは具体的な行を示す。開発者は、漠然とした遅さから特定のfunctionへ進むために、複数の外部toolを最初から組み合わせる必要がない。sampling profilerは再起動やcode変更なしで実行中processにも接続できる。

Willisonの手順にはもう一つ意味がある。coding agentは最初にtoolを調査し、その後で再現可能なdemoを作るよう指示された。source codeを読んだだけで性能を推測したのではない。計測toolを操作し、人間が開いて疑える成果物を返した。

鮮やかなgraphでも間違った問いには正確に答えてしまう

samplingが返すのは統計的な推定であり、正確なcall数ではない。短いfunctionはsample間で消えることがある。公式documentもprofilingとbenchmarkingを明確に分けている。正確なcall数にはtracingがあり、小さなcode片の時間計測にはtimeitがある。

最大の警告は95.1%という数字そのものだ。thread、mode、workloadの選択を誤れば、toolは救ってくれない。人間が現実的なscenarioを定義し、取得範囲を確認しなければ、agentは完璧なflame graphで脇役の処理を分析できてしまう。

修正前後を再現できるprofileが価値を決める

次にするべきことはheatmapを眺めることではなく、preserve_endingsを変更して同じworkloadを繰り返すことだ。新しいprofileでsampleの分布が移り、改行処理の正しさも維持されて初めて改善と言える。

agentがcommand、Python version、profiler設定、test workloadを記録するかも重要だ。これらがなければ、画像はカルテのない診断にすぎない。

Lilithの判定

このflame graphで最も重要な部分は、全threadを測らなければ消えていた処理だ。agentは虫眼鏡を持てても、どこへ向けるかは人間が決める。

外部リンクは最後に置いています。まずここで簡潔に解説 — 他人のサイトを探し回る必要はありません。

元の記事 ↗ ↗