|
|
@ -54,7 +54,7 @@ instead of a detailed (but costly) profile. |
|
|
|
Caveats |
|
|
|
|
|
|
|
A thread on python-dev convinced me that hotshot produces bogus numbers. |
|
|
|
See http://mail.python.org/pipermail/python-dev/2005-November/058264.html |
|
|
|
See https://mail.python.org/pipermail/python-dev/2005-November/058264.html |
|
|
|
|
|
|
|
I don't know what will happen if a decorated function will try to call |
|
|
|
another decorated function. All decorators probably need to explicitly |
|
|
@ -74,7 +74,7 @@ Caveats |
|
|
|
executed. For this reason coverage analysis now uses trace.py which is |
|
|
|
slower, but more accurate. |
|
|
|
|
|
|
|
Copyright (c) 2004--2016 Marius Gedminas <marius@pov.lt> |
|
|
|
Copyright (c) 2004--2017 Marius Gedminas <marius@gedmin.as> |
|
|
|
Copyright (c) 2007 Hanno Schlichting |
|
|
|
Copyright (c) 2008 Florian Schulze |
|
|
|
|
|
|
@ -104,8 +104,8 @@ Released under the MIT licence since December 2006: |
|
|
|
__author__ = "Marius Gedminas <marius@gedmin.as>" |
|
|
|
__copyright__ = "Copyright 2004-2017 Marius Gedminas and contributors" |
|
|
|
__license__ = "MIT" |
|
|
|
__version__ = '1.9.0' |
|
|
|
__date__ = "2017-01-02" |
|
|
|
__version__ = '1.10.0' |
|
|
|
__date__ = "2017-12-09" |
|
|
|
|
|
|
|
|
|
|
|
import atexit |
|
|
@ -118,6 +118,9 @@ import sys |
|
|
|
from profile import Profile |
|
|
|
import pstats |
|
|
|
|
|
|
|
# For timecall |
|
|
|
import timeit |
|
|
|
|
|
|
|
# For hotshot profiling (inaccurate!) |
|
|
|
try: |
|
|
|
import hotshot |
|
|
@ -142,9 +145,6 @@ try: |
|
|
|
except ImportError: |
|
|
|
cProfile = None |
|
|
|
|
|
|
|
# For timecall |
|
|
|
import time |
|
|
|
|
|
|
|
|
|
|
|
# registry of available profilers |
|
|
|
AVAILABLE_PROFILERS = {} |
|
|
@ -503,7 +503,7 @@ if hotshot is not None: |
|
|
|
old_trace = sys.gettrace() |
|
|
|
try: |
|
|
|
return self.profiler.runcall(self.fn, args, kw) |
|
|
|
finally: # pragma: nocover |
|
|
|
finally: # pragma: nocover |
|
|
|
sys.settrace(old_trace) |
|
|
|
|
|
|
|
def atexit(self): |
|
|
@ -528,10 +528,11 @@ if hotshot is not None: |
|
|
|
if what == hotshot.log.LINE: |
|
|
|
fs.mark(lineno) |
|
|
|
if what == hotshot.log.ENTER: |
|
|
|
# hotshot gives us the line number of the function definition |
|
|
|
# and never gives us a LINE event for the first statement in |
|
|
|
# a function, so if we didn't perform this mapping, the first |
|
|
|
# statement would be marked as never executed |
|
|
|
# hotshot gives us the line number of the function |
|
|
|
# definition and never gives us a LINE event for the first |
|
|
|
# statement in a function, so if we didn't perform this |
|
|
|
# mapping, the first statement would be marked as never |
|
|
|
# executed |
|
|
|
if lineno == fs.firstlineno: |
|
|
|
lineno = fs.firstcodelineno |
|
|
|
fs.mark(lineno) |
|
|
@ -576,13 +577,13 @@ class TraceFuncCoverage: |
|
|
|
def __call__(self, *args, **kw): |
|
|
|
"""Profile a singe call to the function.""" |
|
|
|
self.ncalls += 1 |
|
|
|
if TraceFuncCoverage.tracing: # pragma: nocover |
|
|
|
if TraceFuncCoverage.tracing: # pragma: nocover |
|
|
|
return self.fn(*args, **kw) |
|
|
|
old_trace = sys.gettrace() |
|
|
|
try: |
|
|
|
TraceFuncCoverage.tracing = True |
|
|
|
return self.tracer.runfunc(self.fn, *args, **kw) |
|
|
|
finally: # pragma: nocover |
|
|
|
finally: # pragma: nocover |
|
|
|
sys.settrace(old_trace) |
|
|
|
TraceFuncCoverage.tracing = False |
|
|
|
|
|
|
@ -710,12 +711,12 @@ def timecall(fn=None, immediate=True, timer=None): |
|
|
|
somefunc(2, 3) |
|
|
|
|
|
|
|
will print the time taken by somefunc on every call. If you want just |
|
|
|
a summary at program termination, use |
|
|
|
a summary at program termination, use :: |
|
|
|
|
|
|
|
@timecall(immediate=False) |
|
|
|
|
|
|
|
You can also choose a timing method other than the default ``time.time()``, |
|
|
|
e.g.: |
|
|
|
You can also choose a timing method other than the default |
|
|
|
``timeit.default_timer()``, e.g.:: |
|
|
|
|
|
|
|
@timecall(timer=time.clock) |
|
|
|
|
|
|
@ -726,7 +727,7 @@ def timecall(fn=None, immediate=True, timer=None): |
|
|
|
return decorator |
|
|
|
# @timecall syntax -- we are a decorator. |
|
|
|
if timer is None: |
|
|
|
timer = time.time |
|
|
|
timer = timeit.default_timer |
|
|
|
fp = FuncTimer(fn, immediate=immediate, timer=timer) |
|
|
|
# We cannot return fp or fp.__call__ directly as that would break method |
|
|
|
# definitions, instead we need to return a plain function. |
|
|
@ -783,6 +784,7 @@ class FuncTimer(object): |
|
|
|
self.totaltime, self.totaltime / self.ncalls) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|
|
|
|
local = dict((name, globals()[name]) for name in __all__) |
|
|
|