summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2003-03-14 17:21:00 (GMT)
committerGuido van Rossum <guido@python.org>2003-03-14 17:21:00 (GMT)
commit538f1d842c3dfeff279c084d616c03113ec5dd94 (patch)
tree4c9768105507ad94ef7e575a4e845b1ae00f556d
parent0834d77bc4f07e5632588ed636b6db21e87694cc (diff)
downloadcpython-538f1d842c3dfeff279c084d616c03113ec5dd94.zip
cpython-538f1d842c3dfeff279c084d616c03113ec5dd94.tar.gz
cpython-538f1d842c3dfeff279c084d616c03113ec5dd94.tar.bz2
Implement some recommendations from Raymond H:
- Make all local variables in the template start with an underscore, to prevent name conflicts with the timed code. - Added a method to print a traceback that shows source lines from the expanded template. - Use that method in main().
-rw-r--r--Lib/timeit.py58
1 files changed, 48 insertions, 10 deletions
diff --git a/Lib/timeit.py b/Lib/timeit.py
index f244b73..c211082 100644
--- a/Lib/timeit.py
+++ b/Lib/timeit.py
@@ -58,6 +58,7 @@ except ImportError:
__all__ = ["Timer"]
+dummy_src_name = "<timeit-src>"
default_number = 1000000
default_repeat = 10
@@ -72,13 +73,13 @@ else:
# in Timer.__init__() depend on setup being indented 4 spaces and stmt
# being indented 8 spaces.
template = """
-def inner(seq, timer):
+def inner(_seq, _timer):
%(setup)s
- t0 = timer()
- for i in seq:
+ _t0 = _timer()
+ for _i in _seq:
%(stmt)s
- t1 = timer()
- return t1-t0
+ _t1 = _timer()
+ return _t1 - _t0
"""
def reindent(src, indent):
@@ -107,11 +108,36 @@ class Timer:
stmt = reindent(stmt, 8)
setup = reindent(setup, 4)
src = template % {'stmt': stmt, 'setup': setup}
- code = compile(src, "<src>", "exec")
+ self.src = src # Save for traceback display
+ code = compile(src, dummy_src_name, "exec")
ns = {}
exec code in globals(), ns
self.inner = ns["inner"]
+ def print_exc(self, file=None):
+ """Helper to print a traceback from the timed code.
+
+ Typical use:
+
+ t = Timer(...) # outside the try/except
+ try:
+ t.timeit(...) # or t.repeat(...)
+ except:
+ t.print_exc()
+
+ The advantage over the standard traceback is that source lines
+ in the compiled template will be displayed.
+
+ The optional file argument directs where the traceback is
+ sent; it defaults to sys.stderr.
+ """
+ import linecache, traceback
+ linecache.cache[dummy_src_name] = (len(self.src),
+ None,
+ self.src.split("\n"),
+ dummy_src_name)
+ traceback.print_exc(file=file)
+
def timeit(self, number=default_number):
"""Time 'number' executions of the main statement.
@@ -162,6 +188,10 @@ def main(args=None):
The return value is an exit code to be passed to sys.exit(); it
may be None to indicate success.
+
+ When an exception happens during timing, a traceback is printed to
+ stderr and the return value is 1. Exceptions at other times
+ (including the template compilation) are not caught.
"""
if args is None:
args = sys.argv[1:]
@@ -201,17 +231,25 @@ def main(args=None):
# determine number so that 0.2 <= total time < 2.0
for i in range(1, 10):
number = 10**i
- x = t.timeit(number)
+ try:
+ x = t.timeit(number)
+ except:
+ t.print_exc()
+ return 1
if x >= 0.2:
break
- r = t.repeat(repeat, number)
+ try:
+ r = t.repeat(repeat, number)
+ except:
+ t.print_exc()
+ return 1
best = min(r)
print "%d loops," % number,
usec = best * 1e6 / number
if repeat > 1:
- print "best of %d: %.3f usec" % (repeat, usec)
+ print "best of %d: %.3f usec per loop" % (repeat, usec)
else:
- print "time: %.3f usec" % usec
+ print "time: %.3f usec per loop" % usec
return None
if __name__ == "__main__":