Welcome, guest | Sign In | My Account | Store | Cart

Inspired by this post I wrote this context manager to benchmark code blocks or function calls.

Usage is incredibly simple:

with Timer():
    ...  # code to benchmark goes here

The time taken (in seconds) will be printed when the code block completes. To capture the time taken programmatically is almost as easy:

t = Timer()
with t:
    ...  # code to benchmark goes here
time_taken = t.interval

Due to the difficulties of timing small snippets of code accurately, you should only use this for timing code blocks or function calls which take a significant amount of time to process. For micro-benchmarks, you should use the timeit module.

Python, 25 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import gc
import timeit
import time

class Timer:
    def __init__(self, timer=None, disable_gc=False, verbose=True):
        if timer is None:
            timer = timeit.default_timer
        self.timer = timer
        self.disable_gc = disable_gc
        self.verbose = verbose
        self.start = self.end = self.interval = None
    def __enter__(self):
        if self.disable_gc:
            self.gc_state = gc.isenabled()
            gc.disable()
        self.start = self.timer()
        return self
    def __exit__(self, *args):
        self.end = self.timer()
        if self.disable_gc and self.gc_state:
            gc.enable()
        self.interval = self.end - self.start
        if self.verbose:
            print('time taken: %f seconds' % self.interval)

The hard part of timing code snippets accurately is that the operating system and other running processes get in the way. This makes micro-benchmarks hard to perform accurately, and the timeit module is designed for this purpose. But for more heavyweight code, the noise introduced by the OS is usually unimportant (although if your anti-virus scanner decides to schedule a full disk scan just as your test starts, your results may be affected...), and using timeit doesn't gain you very much and this is much more convenient.

This should work in any version of Python from 2.5 onwards. In 2.5, you will need to enable the with statement first:

from __future__ import with_statement

The Timer object takes three optional arguments: a timer function, a flag telling it whether or not to disable Python's garbage collector, and a verbose flag.

The usual choices for the timer function are time.clock (usually best for Windows) or time.time (usually best for other platforms). By default, it will use the platform-specific default timer from the timeit module.

If the second argument is true, the garbage collector will be disabled just before running the code block, and then reverted to its previous state afterwards. By default the garbage collector is left alone.

If the third argument is true, the benchmark is printed just after finishing. Note that if an exception takes place inside the block, the benchmark will still be printed just before the traceback.