timeモジュール(time.perf_counter)
- 使いどころは特定のコードブロックに対する計測。精度はマイクロ秒程度。精度を求める場合はこれ。(逆にcProfile/line_profileなどのプロファイリングは基本的にクロック程度の精度,1/100秒程度しかなく,ボトルネックの発見が目的と考えてよいのかもしれない。)
- 使い方は開始位置と終了位置でtime.time()ならエポック秒(UNIX時間)を,time.perf_counter()ならパフォーマンスカウンタの値を取得して差分として計算する。
- Pythonのドキュメントに依ると,time.time()システムによっては1秒程度しか精度が無い場合もある。しかし,UNIXにおいてはgettimeofday()を使って時刻を取得するようなので,マイクロ秒単位程度の精度があるようだ。
# Web上にはtime.time()が1/60~1/100秒程度の精度の記述が見られるが,Python3のドキュメントにはその記述は見つけられなかった。
- より明確にパフォーマンスカウンタ値を返す関数としてtime.perf_counter()がある。time.time()と同じような気もするけど,使い方は同じであるし,無難にこちらを使っておく。
# 実際に,time.get_clock_info('time')とtime.get_clock_info('perf_counter')のresolutionはどちらも1e-09。
import time
start_time = time.perf_counter()
end_time = time.perf_counter()
print('Elapsed time:{:.7}'.format(end_time - start_time))
cProfile
- 使いどころは関数ごとの処理時間やコール回数を計測したい場合。精度は1/100秒程度。
- 使い方はスクリプト実行時に,cProfileをインポートして実行するだけ。
- 表示の意味をまとめておく。
- ncalls: 呼び出し回数。再帰の場合が別途表示されていて,"再帰含む場合"/”再帰を含まない場合”の2つが出力される。
- tottime: その関数で消費された時間。その関数が呼び出す関数の消費時間は含まない。
- cumtime: その関数で消費された時間。その関数が呼び出す関数の消費時間は含む。
- '-s'オプションでソートして出力することがほとんど。
- time: tottimeでソート
- cumulative: cumtimeでソート
- calls: ncallsでソート
hoge@foo:~/$ python3 -m cProfile -s time tak.py
12604868 function calls (8 primitive calls) in 3.457 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
12604861/1 3.457 0.000 3.457 3.457 tak.py:3(tak)
1 0.000 0.000 0.000 0.000 {built-in method builtins.print}
1 0.000 0.000 3.457 3.457 tak.py:15(main)
1 0.000 0.000 3.457 3.457 tak.py:1(<module>)
2 0.000 0.000 0.000 0.000 {built-in method time.perf_counter}
1 0.000 0.000 3.457 3.457 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
line_profiler
- 使いどころは行単位のプロファイルを取りたい場合。cProfileであたりを関数単位で付けて,計測したい関数をline_profileで指定(デコレータ)する。
- いくつかの使い方があるが,コードを修正してしまうので面倒ではあるが単純なのは関数に@profileデコレータを付けて,kerfnprof.py(line_profileと一緒にインストールされる)を使う。
@profile
def f():
...
...
...
return
- pipでインストールして,かつline_profilerをgit cloneしていて例があるが,kernprof.py自体はローカルにあるので不要。
$ pip3 install line_profiler --user
$ python3 ~/.local/lib/python3.6/site-packages/kernprof.py -l -v hoge.py