web-dev-qa-db-ja.com

Pythonでのプロファイリング:誰が関数を呼び出しましたか?

Python using cProfileを使用してプロファイリングしています。CPU時間を多く消費する関数を見つけました。この重い関数を最も呼び出している関数を見つけるにはどうすればよいですか?

編集:

回避策を決定します。その重い関数内に、それを呼び出した関数の名前を出力するPython行を記述できますか?

48
Ram Rachum

それはあなたの質問に直接答えないかもしれませんが、間違いなく助けになります。オプション--sortcumulativeを指定してプロファイラーを使用すると、累積時間で関数が並べ替えられます。これは、重い関数だけでなく、それらを呼び出す関数を検出するのに役立ちます。

python -m cProfile --sort cumulative myScript.py

呼び出し元関数を取得するための回避策があります。

import inspect
print inspect.getframeinfo(inspect.currentframe().f_back)[2]

呼び出し元の呼び出し元などが必要な場合は、必要な数のf_backを追加できます。頻繁な呼び出しを計算する場合は、次のようにします。

record = {}

caller = inspect.getframeinfo(inspect.currentframe().f_back)[2]
record[caller] = record.get(caller, 0) + 1

次に、頻度順に印刷します。

print sorted(record.items(), key=lambda a: a[1])
34
Nadia Alramli

私はほとんどの場合、 Gprof2dot を使用してcProfileモジュールの出力を表示します。基本的には、出力をgraphvisグラフ(a .dot file)、例:

example gprof2dot output

どの関数が最も遅いか、そしてどの関数がそれを呼び出したかを非常に簡単に判断できます。

使用法は次のとおりです。

python -m cProfile -o output.pstats path/to/your/script arg1 arg2
gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png
105
dbr

inspect.stack() は、現在の呼び出し元スタックを提供します。

pycallgraph をご覧ください。

3
Anonymous

標準ライブラリのプロファイラーcProfileを使用してこれを行うことができます。
_pstats.Stats_(プロファイラーの結果)には、メソッド_print_callees_(または_print_callers_)があります。


サンプルコード:

_import cProfile, pstats
pr = cProfile.Profile()
pr.enable()

# ... do something ...

pr.disable()
ps = pstats.Stats(pr).strip_dirs().sort_stats('cumulative')
ps.print_callees()
_

結果は次のようになります。

_Function                           called...
                                       ncalls  tottime  cumtime
ElementTree.py:1517(_start_list)   ->   24093    0.048    0.124  ElementTree.py:1399(start)
                                        46429    0.015    0.041  ElementTree.py:1490(_fixtext)
                                        70522    0.015    0.015  ElementTree.py:1497(_fixname)
ElementTree.py:1527(_data)         ->   47827    0.017    0.026  ElementTree.py:1388(data)
                                        47827    0.018    0.053  ElementTree.py:1490(_fixtext)
_

左側に発信者があり、右側に発信者がいます。
(たとえば、__fixtext_は__data_ 47827回および__start_list_ 46429回から呼び出されました)


参照:


メモのカップル:

  • このためにコードを編集する必要があります(これらのプロファイルステートメントを挿入してください)。
    (つまり、_python -m cProfile myscript.py_のようにコマンドラインから使用することはできません。そのために別のスクリプトを作成することは可能ですが)
  • 少し関係ありませんが、strip_dirs()sort_stats()の前に配置する必要があります(そうでない場合、並べ替えは機能しません)

私自身はcProfileを使用していませんが、ほとんどのプロファイラーは呼び出し階層を提供します。
グーグル私はこれを見つけました スライド cProfileについて。多分それは助けになります。 6ページはcProfileが階層を提供しているように見えます。

1
lothar

Pycscopeはこれを行います。今日見つけたばかりなので、どれだけ良いかは言えませんが、試したいくつかの例はかなり良いものでした(完璧ではありませんが)。

https://pypi.python.org/pypi/pycscope/

これを使用してcscopeファイルを生成し、次にエディターからcscopeプラグインを生成します。VIM具体的には、Vanilla cscopeで使用してみましたが、単純なcscopeが混乱しているようです。

0
Yike Lu

申し訳ありませんが、Pythonに精通していませんが、ランダムな時間に手動で実行を中断できると仮定すると、 一般的な方法 が機能します。

そうして、コールスタックを表示します。それはあなたが知りたいことを高い確率で教えてくれます。もっと確実にしたい場合は、数回実行してください。

これは、有罪の発信者が無駄になっている時間の一部の間、コールスタックに存在する必要があるために機能します。これにより、多くの短い通話に分散している場合でも、いくつかの長い通話に分散している場合でも、多くの時間、割り込みにさらされます。

注:このプロセスは、測定というより診断に似ています。悪い電話が90%の時間を無駄にしているとしましょう。その後、停止するたびに、不良コールステートメントがコールスタックのすぐ上にある可能性が90%になり、不良であることがわかります。ただし、無駄を正確に測定したい場合は、別の問題になります。そのためには、サンプルの何%にその呼び出しが含まれているかを確認するために、さらに多くのサンプルが必要になります。または、代わりに、有罪の電話を修正し、スピードアップを計時すると、無駄が何であったかが正確にわかります。

0
Mike Dunlavey