Skip to main content

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
time.sleep(3)
wallclock.pop('slow function')

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

main()

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.

Configuration
-------------

``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
created.
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
time.sleep(3)

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

main()

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).

Decorators
~~~~~~~~~~

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

@wallclock.function
def slow_function():
import time
time.sleep(3)

@wallclock.trace_function
def main():
slow_function()

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.

Threads
-------

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.

Performance
-----------

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

1.0

Download files

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

Source Distribution

wallclock-1.0.tar.gz (6.6 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

wallclock-1.0-py2.7.egg (10.8 kB view details)

Uploaded Egg

wallclock-1.0-py2.6.egg (10.9 kB view details)

Uploaded Egg

File details

Details for the file wallclock-1.0.tar.gz.

File metadata

  • Download URL: wallclock-1.0.tar.gz
  • Upload date:
  • Size: 6.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for wallclock-1.0.tar.gz
Algorithm Hash digest
SHA256 25a1f3aa8551392c602a19e48bac0c6a719d686e577569ba260121d28b083418
MD5 07b3186ff53567d6bf8f1f4610e151fa
BLAKE2b-256 7939402785560101aa5f7f8e3d8cf4144580417df4d720afc899983e17a740ae

See more details on using hashes here.

File details

Details for the file wallclock-1.0-py2.7.egg.

File metadata

  • Download URL: wallclock-1.0-py2.7.egg
  • Upload date:
  • Size: 10.8 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for wallclock-1.0-py2.7.egg
Algorithm Hash digest
SHA256 fa88dc8bdc20384e41776c5fcec097e40fafb1dc3fc41899c2488a07a293326e
MD5 2248010db058a6e2573d7a3cdd118889
BLAKE2b-256 d31cee52c7fe898fa94eba4ea30cfc78f3957cd31288c671076ba7ef9aef0865

See more details on using hashes here.

File details

Details for the file wallclock-1.0-py2.6.egg.

File metadata

  • Download URL: wallclock-1.0-py2.6.egg
  • Upload date:
  • Size: 10.9 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for wallclock-1.0-py2.6.egg
Algorithm Hash digest
SHA256 d617a8d33578d018a3d2b2a403d4a392e6b7fd16888a29e808b1c45786201ee0
MD5 b289c3f230c8bc87506dd9e2e9bbe215
BLAKE2b-256 5ac96cdeb6a24c017278f220f580a39ca618a3b185ac255b8dd24e6c3f0a3315

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page