diff options
author | Guido van Rossum <guido@python.org> | 2003-03-14 17:21:00 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2003-03-14 17:21:00 (GMT) |
commit | 538f1d842c3dfeff279c084d616c03113ec5dd94 (patch) | |
tree | 4c9768105507ad94ef7e575a4e845b1ae00f556d | |
parent | 0834d77bc4f07e5632588ed636b6db21e87694cc (diff) | |
download | cpython-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.py | 58 |
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__": |