Skip to main content
Join the official 2020 Python Developers SurveyStart the survey!

A simple stack-based performance logger

Project description

A simple stack-based performance logger.

Wallclock provides some simple tools for identifying slow parts of your code.
It maintains a stack of running timers, and reports the tree of execution
times when the stack empties out.

Simple Usage

To time code with wallclock, use the ``push`` and ``pop`` functions provided
by the wallclock module::

import wallclock

def slow_function():
wallclock.push('slow function')
import time
wallclock.pop('slow function')

def main():
wallclock.push('handling one request', enable=True)
wallclock.pop('handling one request')


This will produce a small tree on ``stderr`` summarizing the time taken to
execute ``main()``::

[3.001 sec] handling one request
[3.001 sec] slow function

The ``push`` function takes one positional argument, which is the label of the
timer being pushed onto wallclock's stack. This is normally a short,
descriptive label for the kind of work that happens under timing. ``push``
also takes one optional keyword argument, ``enable``, which controls whether
this call to ``push`` should start timing (if it's not already started).
``wallclock`` ignores calls to ``push`` until it has been enabled, and
disables itself automatically when the enabling ``push`` is ``pop``ped.

The ``pop`` function takes one positional argument, which is the label to pop.
This allows for simple insertion of ``push``/``pop`` pairs surrounding code
that might return, or might raise an exception, without adding extra
``try``/``except`` blocks or similar (but see below for a better approach).
``wallclock`` will pop timers off of the stack until it finds a timer pushed
with the passed label, or until it empties the timer stack.


``wallclock`` exposes two module-scoped symbols that can be used to control
its behaviour:

* ``wallclock.threshold`` is a number (``float``, ``int``, or ``long``) of
seconds. Any timers whose duration is strictly less than ``threshold`` will
not be recorded. By default, the threshold is approximately 10 milliseconds
(0.01 seconds). Setting the threshold to ``0`` will record every timer.
* ``wallclock.output`` is a callable object used to print recorded times. By
default, it's set to ``wallclock.stderr_output``, which writes the tree to
standard error, but applications can replace this with their own callables.
``wallclock`` invokes ``output`` with one argument, which is the root timer
object. Timer objects have three readable properties:
1. ``label``, which is the label passed to ``push`` when the timer was
2. ``duration``, which is the total time recorded on the timer (in seconds).
3. ``children``, which is a sequence of timer objects that were recorded
while the passed timer object was at the top of the stack.

Automatic Timer Management

Manually inserting calls to ``push`` and ``pop`` works for debugging, but not
so well for leaving wallclock in place afterwards. The ``wallclock`` module
provides some tidier alternatives.

Context Manager

The ``wallclock.block`` context manager automatically calls ``push`` before
evaluating the block, and ensures ``pop`` is called after exiting the block by
any means::

import wallclock

def slow_function():
with wallclock.block('slow function'):
import time

def main():
with wallclock.block('handling one request', enable=True):


The ``block`` context manager accepts the same arguments that ``push``
accepts: a positional argument labelling the block, and an optional keyword
argument called ``enable`` for controlling whether the block should start
wallclock (if it's not already started).


The ``wallclock.function`` and ``wallclock.trace_function`` decorators
automatically call ``push`` before executing the decorated function, and
automatically call ``pop`` after the function exits, but before returning to
the caller::

import wallclock

def slow_function():
import time

def main():


Both decorators determine the label for the pushed timer by examining the
called function's module and name. ``trace_function`` enables wallclock, while
``function`` does not.


Wallclock makes a reasonable effort to keep a timer stack for each thread.
Timer stacks are kept in a ``threading.threadlocal`` object and are enabled
and disabled on a per-thread basis.


Timing your code is not free. While wallclock is noticably faster than a full
profiler, it still introduces overhead to manage the stack of pending timers
and the tree of completed timers. I've found the overhead to be surprisingly
large (a decorated empty function takes ~100x as long as a naked empty
function), but still well within usable limits.

Removing calls that enable wallclock reduces this overhead considerably. You
can further reduce overhead by disabling ``wallclock`` completely by calling
``wallclock.smash()``. This is an irreversible operation which replaces the
``push`` and ``pop`` operations, the ``block`` context manager, and the
``function`` and ``trace_function`` decorators with no-op equivalents.

Project details

Release history Release notifications | RSS feed

This version


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for wallclock, version 1.0
Filename, size File type Python version Upload date Hashes
Filename, size wallclock-1.0-py2.6.egg (10.9 kB) File type Egg Python version 2.6 Upload date Hashes View
Filename, size wallclock-1.0-py2.7.egg (10.8 kB) File type Egg Python version 2.7 Upload date Hashes View
Filename, size wallclock-1.0.tar.gz (6.6 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page