Python Profiling
コードを実際に動作させながら、どこで遅くなるかを計測するのだ。
プロファイラとは?
良好なパフォーマンスを確保するための開発者のツールボックスの中で最も優れたツールの一つがプロファイリングです。本番のコードがどこで遅くなるかを正確に予測するのは非常に困難です。プロファイリングツールを使えば、コードの中で遅くなっている行を正確に示すことができます。また、特定の最適化を行い、テストすることも可能です。 Sentry 日本語公式ブログ - プロファイリング入門101:プロファイリングとは何か? - Ichizoku
Python のプロファイラ?
cProfile と profile は 決定論的プロファイリング (deterministic profiling) を行います。 プロファイル (profile) とは、プログラムの各部分がどれだけ頻繁に呼ばれたか、そして実行にどれだけ時間がかかったかという統計情報です。 pstats モジュールを使ってこの統計情報をフォーマットし表示することができます。 (https://docs.python.org/ja/3/library/profile.html)
- cProfile: ほとんどのユーザーに推奨されるモジュールです。 C言語で書かれた拡張モジュールで、オーバーヘッドが少ないため長時間実行されるプログラムのプロファイルに適しています。 Brett Rosen と Ted Czotter によって提供された lsprof に基づいています。
- profile: cProfile の低レベル版、ピュア Python モジュールで、 cProfile モジュールはこのモジュールのインターフェースを真似ています。対象プログラムに相当のオーバーヘッドが生じます。もしプロファイラに何らかの拡張をしたいのであれば、こちらのモジュールを拡張する方が簡単でしょう。このモジュールはもともと Jim Roskind により設計、実装されました。
- py-spy: https://github.com/benfred/py-spy
py-spy
py-spy は Python のプロファイラ。 2024-03-25 時点では python v3.11 までしかサポートしていないので、その点だけ注意!
以下のようにインストールできる。
pip install py-spy
ヘルプを見ると良い
$ py-spy --help
py-spy 0.3.14
Sampling profiler for Python programs
USAGE:
py-spy <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
record Records stack trace information to a flamegraph, speedscope or raw file
top Displays a top like view of functions consuming CPU
dump Dumps stack traces for a target program to stdout
help Print this message or the help of the given subcommand(s)
サブコマンド record の使い方
$ py-spy record -h
py-spy-record
Records stack trace information to a flamegraph, speedscope or raw file
USAGE:
py-spy record [OPTIONS] [python_program]...
ARGS:
<python_program>... commandline of a python program to run
OPTIONS:
-p, --pid <pid> PID of a running python program to spy on
--full-filenames Show full Python filenames, instead of shortening to show only the package part
-o, --output <filename> Output filename
-f, --format <format> Output file format [default: flamegraph] [possible values: flamegraph, raw, speedscope]
-d, --duration <duration> The number of seconds to sample for [default: unlimited]
-r, --rate <rate> The number of samples to collect per second [default: 100]
-s, --subprocesses Profile subprocesses of the original process
-F, --function Aggregate samples by function's first line number, instead of current line number
--nolineno Do not show line numbers
-t, --threads Show thread ids in the output
-g, --gil Only include traces that are holding on to the GIL
-i, --idle Include stack traces for idle threads
--nonblocking Don't pause the python process when collecting samples. Setting this option will reduce the performance impact of sampling, but may lead to inaccurate results
-h, --help Print help information
この辺に従って、 v0.3.14 での実行方法はコレ。
$ sudo py-spy record -- python summarize.py
py-spy> Sampling process 100 times a second. Press Control-C to exit.
^C
Traceback (most recent call last):
File "/Users/george/dev/take4mats/cidrs/summarize.py", line 5, in <module>
for l in sys.stdin:
KeyboardInterrupt
py-spy> Stopped sampling because Control-C pressed
py-spy> Wrote flamegraph data to 'python-2024-03-25T09:27:23+09:00.svg'. Samples: 2020 Errors: 0
python-2024-03-25T09:27:23+09:00.svg
すると、 flamegraph が svg で出力されるのでブラウザで開いてみると、こんな感じ。