web-dev-qa-db-ja.com

pythonスクリプトをベンチマークする簡単な方法はありますか?

通常、シェルコマンドtimeを使用します。私の目的は、データが小さい、中程度、大きい、または非常に大きいセットであるかどうか、時間とメモリ使用量がどれくらいになるかをテストすることです。

Linux用のツール、またはpythonこれを行うには?

66
noomz

timeitpythonプロファイラー および pycallgraph をご覧ください。

timeit

_def test():
    """Stupid test function"""
    lst = []
    for i in range(100):
        lst.append(i)

if __== '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))
_

基本的に、文字列パラメータとしてpython codeを渡すことができます。指定した回数実行され、実行時間が出力されます。ドキュメントの重要な部分:

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)

所定のステートメント、setupコード、およびtimer関数を使用してTimerインスタンスを作成し、そのtimeitメソッドnumber実行。

...および:

Timer.timeit(number=1000000)

メインステートメントの時間number実行。これにより、セットアップステートメントが1回実行され、メインステートメントの実行にかかる時間を秒単位で浮動小数点数で返します。引数はループの回数で、デフォルトは100万回です。メインステートメント、セットアップステートメント、および使用するタイマー関数がコンストラクターに渡されます。

デフォルトでは、timeitはタイミング中に_garbage collection_を一時的にオフにします。このアプローチの利点は、独立したタイミングをより比較可能にすることです。この欠点は、GCが測定される関数のパフォーマンスの重要な要素になる可能性があることです。その場合、GCはsetup文字列の最初のステートメントとして再度有効にできます。例えば:

timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

プロファイリング

プロファイリングを行うと、何が起こっているかについてmuchより詳細なアイデアが得られます。 公式ドキュメント の「インスタント例」は次のとおりです。

_import cProfile
import re
cProfile.run('re.compile("foo|bar")')
_

それはあなたに与えるでしょう:

_      197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)
_

これらのモジュールは両方とも、ボトルネックを探す場所についてのアイデアを提供するはずです。

また、profileの出力を把握するには、 この投稿 をご覧ください。

パイコールグラフ

このモジュール graphvizを使用して、次のようなコールグラフを作成します。

callgraph example

最も多く使用されたパスを色で簡単に確認できます。 pycallgraph APIを使用するか、パッケージ化されたスクリプトを使用して作成できます。

_pycallgraph graphviz -- ./mypythonscript.py
_

ただし、オーバーヘッドはかなり大きくなります。そのため、すでに長時間実行されているプロセスの場合、グラフの作成には時間がかかる場合があります。

94
exhuma

Funcの時間を計るのに簡単なデコレータを使用します

def st_time(func):
    """
        st decorator to calculate the total time of a func
    """

    def st_func(*args, **keyArgs):
        t1 = time.time()
        r = func(*args, **keyArgs)
        t2 = time.time()
        print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
        return r

    return st_func
26
Danyun Liu

timeitモジュールは遅くて奇妙だったので、これを書きました:

def timereps(reps, func):
    from time import time
    start = time()
    for i in range(0, reps):
        func()
    end = time()
    return (end - start) / reps

例:

import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)

私にとっては、それは言う:

python can do 40925 os.listdir('/') per second

これは基本的なベンチマークの種類ですが、それで十分です。

12
Sam Watkins

私は通常、time ./script.pyをすばやく実行して、所要時間を確認します。ただし、少なくともデフォルトとしては、メモリは表示されません。 /usr/bin/time -v ./script.pyを使用して、メモリ使用量を含む多くの情報を取得できます。

10
Martin Ueding

すべてのメモリニーズに対応するメモリプロファイラ。

https://pypi.python.org/pypi/memory_profiler

Pipインストールを実行します。

pip install memory_profiler

ライブラリをインポートします。

import memory_profiler

プロファイリングするアイテムにデコレーターを追加します。

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __== '__main__':
    my_func()

コードを実行します。

python -m memory_profiler example.py

出力を受け取ります。

 Line #    Mem usage  Increment   Line Contents
 ==============================================
 3                           @profile
 4      5.97 MB    0.00 MB   def my_func():
 5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
 6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
 7     13.61 MB -152.59 MB       del b
 8     13.61 MB    0.00 MB       return a

例は、上記にリンクされているドキュメントからのものです。

3

nose とそのプラグインの1つ、特に this one を見てください。

インストールされると、noseはパス内のスクリプトであり、いくつかのpythonスクリプトを含むディレクトリで呼び出すことができます。

$: nosetests

これにより、現在のディレクトリ内のすべてのpythonファイルが検索され、テストとして認識されるすべての関数が実行されます。たとえば、名前にWord test_が含まれるすべての関数がテストとして認識されます。

したがって、test_yourfunction.pyという名前のpythonスクリプトを作成し、その中に次のように記述できます。

$: cat > test_yourfunction.py

def test_smallinput():
    yourfunction(smallinput)

def test_mediuminput():
    yourfunction(mediuminput)

def test_largeinput():
    yourfunction(largeinput)

その後、実行する必要があります

$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py

そしてプロファイルファイルを読むには、これを使用しますpython行:

python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
3
dalloliogm

timeitは非常に遅いことに注意してください。初期化する(または関数を実行する)には、メディアプロセッサで12秒かかります。この受け入れられた答えをテストできます

def test():
    lst = []
    for i in range(100):
        lst.append(i)

if __== '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second

簡単にするために、代わりにtimeを使用します。PCでは結果0.0

import time

def test():
    lst = []
    for i in range(100):
        lst.append(i)

t1 = time.time()

test()

result = time.time() - t1
print(result) # 0.000000xxxx
0
cieunteung

関数をすばやくテストする簡単な方法は、次の構文を使用することです:%timeit my_code

例えば ​​:

%timeit a = 1

13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
0
Arcyno