Package: wallclock
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 executiontimes when the stack empties out.Simple Usage------------To time code with wallclock, use the ``push`` and ``pop`` functions providedby the wallclock module::import wallclockdef slow_function():wallclock.push('slow function')import timetime.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 toexecute ``main()``::[3.001 sec] handling one request[3.001 sec] slow functionThe ``push`` function takes one positional argument, which is the label of thetimer 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 whetherthis call to ``push`` should start timing (if it's not already started).``wallclock`` ignores calls to ``push`` until it has been enabled, anddisables 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 codethat 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 pushedwith the passed label, or until it empties the timer stack.Configuration-------------``wallclock`` exposes two module-scoped symbols that can be used to controlits behaviour:* ``wallclock.threshold`` is a number (``float``, ``int``, or ``long``) ofseconds. Any timers whose duration is strictly less than ``threshold`` willnot 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. Bydefault, it's set to ``wallclock.stderr_output``, which writes the tree tostandard error, but applications can replace this with their own callables.``wallclock`` invokes ``output`` with one  argument, which is the root timerobject. Timer objects have three readable properties:1. ``label``, which is the label passed to ``push`` when the timer wascreated.2. ``duration``, which is the total time recorded on the timer (in seconds).3. ``children``, which is a sequence of timer objects that were recordedwhile 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 notso well for leaving wallclock in place afterwards. The ``wallclock`` moduleprovides some tidier alternatives.Context Manager~~~~~~~~~~~~~~~The ``wallclock.block`` context manager automatically calls ``push`` beforeevaluating the block, and ensures ``pop`` is called after exiting the block byany means::import wallclockdef slow_function():with wallclock.block('slow function'):import timetime.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 keywordargument called ``enable`` for controlling whether the block should startwallclock (if it's not already started).Decorators~~~~~~~~~~The ``wallclock.function`` and ``wallclock.trace_function`` decoratorsautomatically call ``push`` before executing the decorated function, andautomatically call ``pop`` after the function exits, but before returning tothe caller::import wallclock@wallclock.functiondef slow_function():import timetime.sleep(3)@wallclock.trace_functiondef main():slow_function()main()Both decorators determine the label for the pushed timer by examining thecalled 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 enabledand disabled on a per-thread basis.Performance-----------Timing your code is not free. While wallclock is noticably faster than a fullprofiler, it still introduces overhead to manage the stack of pending timersand the tree of completed timers. I've found the overhead to be surprisinglylarge (a decorated empty function takes ~100x as long as a naked emptyfunction), but still well within usable limits.Removing calls that enable wallclock reduces this overhead considerably. Youcan 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.