web-dev-qa-db-ja.com

どのようにしてPythonスクリプトをプロファイルできますか?

Project Eulerや他のコーディングコンテストは、多くの場合、最大の実行時間があるか、または特定のソリューションの実行速度を誇っています。 pythonでは、時々アプローチがややぎこちなくなります - つまり、タイミングコードを__main__に追加します。

Pythonプログラムの実行にかかる時間をプロファイルするのに良い方法は何ですか?

1113
Chris Lawlor

Pythonには cProfile というプロファイラが含まれています。合計実行時間だけでなく、各関数を別々に計時し、各関数が呼び出された回数も表示されるので、最適化の場所を簡単に判断できます。

次のように、コード内から、またはインタプリタから呼び出すことができます。

import cProfile
cProfile.run('foo()')

さらに便利なことに、スクリプトを実行するときにcProfileを呼び出すことができます。

python -m cProfile myscript.py

さらに簡単にするために、 'profile.bat'という名前の小さなバッチファイルを作成しました。

python -m cProfile %1

それで私がしなければならないのは走ることだけです:

profile euler048.py

そして私はこれを得ます:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

編集: Python Profiling というタイトルのPyCon 2013の優れたビデオリソースへのリンクを更新。
またYouTube経由で

1199
Chris Lawlor

しばらく前に私はあなたのPythonコードから視覚化を生成する pycallgraph を作りました。 編集: この執筆時点での最新リリースである3.3で動作するように例を更新しました。

pip install pycallgraphをインストールして GraphViz をインストールした後は、コマンドラインから実行できます。

pycallgraph graphviz -- ./mypythonscript.py

または、コードの特定の部分をプロファイルすることもできます。

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

どちらも下の画像のようなpycallgraph.pngファイルを生成します。

enter image description here

380
Gerald Kaszuba

プロファイラーの使用は(デフォルトでは)メインスレッドでのみ機能することを指摘しておく価値があります。それらを使用しても、他のスレッドから情報を取得することはできません。 profilerのドキュメント に完全には記載されていないので、これはちょっとした問題かもしれません。

スレッドのプロファイルも作成したい場合は、docsの threading.setprofile()関数 を見てください。

独自のthreading.Threadサブクラスを作成してそれを行うこともできます。

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

そして標準クラスの代わりにそのProfiledThreadクラスを使用してください。それはあなたにもっと柔軟性を与えるかもしれません、しかし私はそれがそれが価値があるかどうか、特にあなたがあなたのクラスを使わないであろう第三者のコードを使っているならば。

187
Joe Shaw

Python wikiはプロファイリングリソースのための素晴らしいページです: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

pythonのドキュメントと同様に、 http://docs.python.org/library/profile.html

chris Lawlorが示すように、cProfileは素晴らしいツールであり、簡単に画面に印刷するために使用できます。

python -m cProfile -s time mine.py <args>

またはファイルに:

python -m cProfile -o output.file mine.py <args>

PS> Ubuntuを使用している場合は、python-profileを必ずインストールしてください。

Sudo apt-get install python-profiler 

ファイルに出力すると、以下のツールを使って素敵な視覚化を得ることができます。

PyCallGraph:コールグラフ画像を作成するためのツール
インストール:

 Sudo pip install pycallgraph

実行します。

 pycallgraph mine.py args

ビュー:

 gimp pycallgraph.png

あなたはあなたがpngファイルを見るために好きなものを使うことができます、私はgimpを使いました
残念ながら私はよく

dot:graphはcairo-rendererのビットマップには大きすぎます。収まるように0.257079でスケーリング

これは私の画像が異常に小さくなります。だから私は一般的にSVGファイルを作成します。

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> graphvizをインストールしてください(これはドットプログラムを提供します):

Sudo pip install graphviz

@maxy/@quodlibetorによるgprof2dotを使った代替グラフ

Sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
135
brent.payne

この回答 に関する@ Maxyのコメントは、私がそれ自身の答えに値すると思うほど十分に私を助けてくれました:私はすでにcProfileで生成された.pstatsファイルを持っていました gprof2dot を使用し、かなりのSVGを取得しました。

$ Sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

そしてブルーム!

これはドット(pycallgraphが使用するものと同じもの)を使用するので、出力は似たように見えます。私はgpr​​of2dotがより少ない情報を失うという印象を得る。

gprof2dot example output

125
quodlibetor

このトピックを調査したところ、 SnakeViz という便利なツールがありました。 SnakeVizはWebベースのプロファイリング視覚化ツールです。インストールと使用はとても簡単です。私が使う通常の方法は、%prunを使ってstatファイルを生成してからSnakeVizで分析することです。

使用される主な技術は、以下に示すように、 サンバーストチャート です。ここで、関数呼び出しの階層は、角度の幅でエンコードされた円弧と時間情報の層として配置されます。

一番いいのはチャートと対話できることです。たとえば、ズームインするには弧をクリックします。弧とその子孫が新しいサンバーストとして拡大され、詳細が表示されます。

enter image description here

57
zaxliu

cProfile はプロファイリングに最適で、 kcachegrind は結果を視覚化するには最適だと思います。 pyprof2calltree の間にあるファイル変換を処理します。

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

必要なツールをインストールするには(少なくともUbuntuでは):

apt-get install kcachegrind
pip install pyprof2calltree

結果:

Screenshot of the result

42
Federico

GUI cProfile dump viewer RunSnakeRun も言及する価値があります。それはあなたがソートして選択することを可能にし、それによってプログラムの関連部分にズームインします。写真内の長方形のサイズは、かかる時間に比例します。四角形の上にマウスを置くと、テーブル内とマップ上のいたるところでその呼び出しが強調表示されます。四角形をダブルクリックすると、その部分が拡大されます。それは誰がその部分を呼ぶのか、そしてその部分が何を呼ぶのかをあなたに示すでしょう。

説明的な情報はとても役に立ちます。それはあなたに組み込みのライブラリ呼び出しを扱っているときに役立つことができるそのビットのためのコードを示します。どのファイルとどの行でコードを見つけるかがわかります。

また、OPが「プロファイリング」と言ったことを指摘したいのですが、彼は「タイミング」を意味していたようです。プロファイルを作成すると、プログラムの実行速度が遅くなります。

enter image description here

38
Pete

Niceプロファイリングモジュールはline_profilerです(スクリプトkernprof.pyを使って呼び出されます)。ダウンロードできます ここ

私の理解するところでは、cProfileは各機能に費やされた合計時間に関する情報だけを提供します。そのため、個々のコード行はタイミングが取られません。 1つの行に多くの時間がかかることがあるため、これは科学計算における問題です。また、私が覚えているように、cProfileは私がnumpy.dotで言っていた時間を捉えていませんでした。

30
Ian Langmore

最も簡単な そして 最も速い 常に進行中の場所を見つける方法。

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

ブラウザで円グラフを描画します。最大のものは問題関数です。とても簡単です。

29
CodeCabbie

プロファイル

line_profiler(すでにここに表示されています)は pprofile にも影響を与えました。

細分性、スレッド対応の確定的および統計的純粋pythonプロファイラ

これは、line_profilerのような細かさを提供し、純粋なPythonであり、スタンドアロンのコマンドまたはモジュールとして使用でき、[k|q]cachegrindを使用して簡単に分析できるcallgrind形式のファイルも生成できます。

vprof

vprof もあります。これは、次のように記述されたPythonパッケージです。

[...]実行時間やメモリ使用量などのPythonプログラムのさまざまな特性について、豊富でインタラクティブな視覚化を提供します。

heatmap

29
BenC

私は最近Pythonランタイムとインポートプロファイルを視覚化するために tuna を作成しました。これはここで役に立つかもしれません。

enter image description here

と一緒にインストール

pip3 install tuna

ランタイムプロファイルを作成する

python -mcProfile -o program.prof yourfile.py

またはインポートプロファイル(Python 3.7以降が必要)

python -X importprofile yourfile.py 2> import.log

それからそのファイルに対してtunaを実行してください。

tuna program.prof
14
Nico Schlömer

たくさんの素晴らしい答えがありますが、それらは結果のプロファイリングやソートのためにコマンドラインか何らかの外部プログラムを使います。

コマンドラインに手を加えたり、何かをインストールしたりせずに、IDE(Eclipse-PyDev)で使用できる方法を本当に逃しました。だからここにあります。

コマンドラインなしのプロファイリング

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __== '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

詳細については docs または他の回答を参照してください。

12
David Mašek

マルチスレッドコードが期待どおりに動作しないというJoe Shawの回答に続いて、cProfileのruncallメソッドは単にプロファイルされた関数呼び出しの周囲でself.enable()およびself.disable()の呼び出しを行っているだけであると考えました。 - 既存のコードとの干渉を最小限に抑えます。

11
PypeBros

Virtaalの source には(特定のメソッドや関数の場合でも)プロファイリングを非常に簡単にすることができる非常に便利なクラスとデコレータがあります。出力はKCacheGrindでとても快適に見ることができます。

10
Walter

cProfileは迅速なプロファイリングには最適ですが、ほとんどの場合はエラーで終了していました。関数runctxは環境と変数を正しく初期化することでこの問題を解決します。誰かに役立つことを願います:

import cProfile
cProfile.runctx('foo()', None, locals())
9
Datageek

私のやり方はyappi( https://code.google.com/p/yappi/ )を使うことです。プロファイリング情報を開始、停止、および印刷するためのメソッドを登録するRPCサーバーと組み合わせると(デバッグだけでも)特に便利です。この方法では:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

その後、プログラムが動作したら、startProfiler RPCメソッドを呼び出してプロファイラを起動し、printProfilerを呼び出してプロファイリング情報をログファイルにダンプし(または呼び出し元に返すようにrpcメソッドを変更する)、次のような出力を取得できます。

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

短いスクリプトにはあまり便利ではないかもしれませんが、特にprintProfilerメソッドが時間をかけて何度も呼び出されてプロファイルと比較を行うことができる場合は、サーバータイプのプロセスを最適化するのに役立ちます。さまざまなプログラム使用シナリオ.

6
Mr. Girgitt

Pythonでプロファイリングを処理するための新しいツールはPyVmMonitorです。 http://www.pyvmmonitor.com/

それはのようないくつかのユニークな機能を持っています

  • 実行中の(CPython)プログラムにプロファイラーを添付する
  • Yappi統合によるオンデマンドプロファイリング
  • 別のマシンでプロファイルする
  • マルチプロセスサポート(マルチプロセッシング、Django ...)
  • ライブサンプリング/ CPUビュー(時間範囲選択あり)
  • CProfile/profile統合による決定論的プロファイリング
  • 既存のPStatsの結果を分析する
  • DOTファイルを開く
  • プログラムによるAPIアクセス
  • 方法またはライン別にサンプルをグループ化する
  • PyDevの統合
  • PyCharmの統合

注:商用ですが、オープンソースは無料です。

3
Fabio Zadrozny

それはあなたがプロファイリングから見たいものに依存するでしょう。単純な時間測定基準は(bash)で与えられます。

time python python_prog.py

'/ usr/bin/time'でも '--verbose'フラグを使用することで詳細なメトリックを出力できます。

各関数によって与えられた時間メトリックスをチェックし、関数にどのくらいの時間が費やされているかをよりよく理解するために、あなたはpythonの作り付けのcProfileを使うことができます。

パフォーマンスのようなより詳細な測定基準に入ると、時間だけが測定基準ではありません。あなたは、メモリ、スレッドなどについて心配することができます.
プロファイリングオプション:
1。 line_profiler は、タイミングメトリクスを1行ずつ見つけるために一般的に使用されるもう1つのプロファイラです。
2。 memory_profiler は、メモリ使用量をプロファイルするためのツールです。
3。 heapy(プロジェクトGuppyから) ヒープ内のオブジェクトの使用方法をプロファイルします。

これらは私が使いがちな共通のものです。しかし、もっと知りたいのなら、この本を読んでみてください。 book パフォーマンスを念頭に置いて始めてみると、かなりよい本です。 CythonとJIT(Just-In-Time)コンパイル済みPythonの使用に関する高度なトピックに進むことができます。

3
VishalMishra

そのPythonスクリプトが何をしているのか知りたいと思ったことはありませんか。検査シェルに入ります。 Inspect Shellでは、実行中のスクリプトを中断することなく、グローバルを印刷/変更して関数を実行できます。オートコンプリートとコマンド履歴付き(Linuxのみ)。

Inspect Shellはpdbスタイルのデバッガではありません。

https://github.com/amoffat/Inspect-Shell

あなたはそれ(そしてあなたの腕時計)を使うことができます。

3
Colonel Panic

https://stackoverflow.com/a/582337/1070617 に追加するには、

私はあなたがcProfileを使いそしてその出力を簡単に見ることを可能にするこのモジュールを書きました。もっとここに: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

収集された統計を理解する方法については、 http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html も参照してください。

3
michael

statprof という統計的プロファイラもあります。これはサンプリングプロファイラなので、コードに最小限のオーバーヘッドを追加し、(関数だけではなく)行ベースのタイミングを提供します。ゲームのようなソフトリアルタイムアプリケーションには適していますが、cProfileよりも精度が低い場合があります。

pypiのバージョン は少し古いので、 gitリポジトリ を指定することでpipを付けてインストールできます。

pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01

このように実行することができます:

import statprof

with statprof.profile():
    my_questionable_function()

https://stackoverflow.com/a/10333592/320036 も参照してください。

1
z0r

私がサーバーのルートになっていないときは、 lsprofcalltree.py を使用し、次のようにプログラムを実行します。

python lsprofcalltree.py -o callgrind.1 test.py

それから、 qcachegrind のように、callgrind互換のソフトウェアでレポートを開くことができます。

0
Vincent Fenet

これらの派手なUIがすべてインストールまたは実行に失敗した場合の端末専用(および最も単純な)ソリューション:
cProfileを完全に無視し、pyinstrumentに置き換えます。これは、実行直後に呼び出しのツリーを収集して表示します。

インストール:

$ pip install pyinstrument

プロファイルと表示結果:

$ python -m pyinstrument ./prog.py

Python2および3で動作します。

0
Francois

gprof2dot_magic

JupyterLabまたはJupyter NotebookでPythonステートメントをDOTグラフとしてプロファイルするgprof2dotのマジック関数。

enter image description here

GitHubリポジトリ: https://github.com/mattijn/gprof2dot_magic

インストール

Pythonパッケージgprof2dot_magicがあることを確認してください。

pip install gprof2dot_magic

依存関係gprof2dotおよびgraphvizもインストールされます

使用法

マジック機能を有効にするには、最初にgprof2dot_magicモジュールをロードします

%load_ext gprof2dot_magic

そして、次のようなDOTグラフとして、ラインステートメントのプロファイルを作成します。

%gprof2dot print('hello world')

enter image description here

0
Mattijn