CProfileを使用して、Pythonで関数のメソッドをプロファイルしたいと思います。私は以下を試しました:
import cProfile as profile
# Inside the class method...
profile.run("self.myMethod()", "output_file")
しかし、それは機能しません。 「run」でself.methodを呼び出すにはどうすればよいですか?
Profilehooksデコレーターを使用する
編集:申し訳ありませんが、プロファイルの呼び出しがクラスメソッドのinであることを理解していませんでした。
run
は、渡した文字列をexec
にしようとします。 self
が使用しているプロファイラーのスコープ内の何にもバインドされていない場合、run
では使用できません。 runctx
メソッドを使用して、プロファイラーの呼び出しのスコープでローカル変数とグローバル変数を渡します。
>>> import time
>>> import cProfile as profile
>>> class Foo(object):
... def bar(self):
... profile.runctx('self.baz()', globals(), locals())
...
... def baz(self):
... time.sleep(1)
... print 'slept'
... time.sleep(2)
...
>>> foo = Foo()
>>> foo.bar()
slept
5 function calls in 2.999 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 2.999 2.999 <stdin>:5(baz)
1 0.000 0.000 2.999 2.999 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 2.999 1.499 2.999 1.499 {time.sleep}
最後の行に注意してください:time.sleep
は、時間を費やしているものです。
プロファイルの関数が値を返す場合は、@ katrielalexから優れた答えを少し変更する必要があります。
... profile.runctx('val = self.baz()', globals(), locals())
... print locals()['val']
単一のルーチンをプロファイリングすることはお勧めしません。これは、そこに問題があることを事前に知っていることを意味するためです。
パフォーマンスの問題の基本的な側面は、こっそりしていることです。彼らはあなたが彼らがいると思っている場所ではありません。
プログラム全体を現実的なワークロードで実行し、プロファイリングテクニックに問題の場所を通知させることをお勧めします。
例はここにあります プロファイリングで問題が見つかりましたが、予想された場所ではありません。
累積プロファイラーを作成する場合は、関数を数回続けて実行し、結果の合計を監視します。
これを使用できますcumulative_profiler
デコレータ:
import cProfile, pstats
class _ProfileFunc:
def __init__(self, func, sort_stats_by):
self.func = func
self.profile_runs = []
self.sort_stats_by = sort_stats_by
def __call__(self, *args, **kwargs):
pr = cProfile.Profile()
pr.enable() # this is the profiling section
retval = self.func(*args, **kwargs)
pr.disable()
self.profile_runs.append(pr)
ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
return retval, ps
def cumulative_profiler(amount_of_times, sort_stats_by='time'):
def real_decorator(function):
def wrapper(*args, **kwargs):
nonlocal function, amount_of_times, sort_stats_by # for python 2.x remove this row
profiled_func = _ProfileFunc(function, sort_stats_by)
for i in range(amount_of_times):
retval, ps = profiled_func(*args, **kwargs)
ps.print_stats()
return retval # returns the results of the function
return wrapper
if callable(amount_of_times): # incase you don't want to specify the amount of times
func = amount_of_times # amount_of_times is the function in here
amount_of_times = 5 # the default amount
return real_decorator(func)
return real_decorator
例
関数のプロファイリングbaz
import time
@cumulative_profiler
def baz():
time.sleep(1)
time.sleep(2)
return 1
baz()
baz
は5回実行され、これを出力しました:
20 function calls in 15.003 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
10 15.003 1.500 15.003 1.500 {built-in method time.sleep}
5 0.000 0.000 15.003 3.001 <ipython-input-9-c89afe010372>:3(baz)
5 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
回数の指定
@cumulative_profiler(3)
def baz():
...