Source code for schrodinger.application.desmond.packages.timer

"""
Facilities for timing a block of code.
Copyright Schrodinger, LLC. All rights reserved.

Example usage:

   from schrodinger.application.desmond.packages.timer import timer

   with timer("Reading the trajectory..."):
       traj.read_trj(trj_fname)

Example output:

   Reading the trajectory...
     100 frames
     Done. (0.5 sec)

In this example, we have three lines in output. Line#1 is the start message, and
line#3 is the timing message. The start-message and the format for the timing
message can be customed by the `message` and `fmt` arguments, respectively.

Arguments for `timer`:

:type    message: `str` or `None`
:type    message: The message to print out before the timing starts. Default is
                  `None` -- no message will be printed.
:type        fmt: `str`
:type        fmt: The format to print out the timing. Default is
                  "Done. (%.2f sec)". A custom format should contain 1 floating
                  number control paramter.
:type  threshold: `float`
:param threshold: Specifies a threshold. If the elapsed time is less than
                  `threshold`, no timing message will not be printed out.
:type     record: `list` or `None`
:param    record: If a list value is given, the current elapsed time will be
                  appended to the list. This is handy if you want to accumulate
                  the elapsed times.
:type     logger: A callable object.
:param    logger: Function called to print the messages.
"""

import time
from collections import namedtuple
from contextlib import contextmanager


def _default_logger(message):
    print(message)


[docs]class Timer(object): """ You can use this class to create your own timer function with custom default behavior. Example usage: from schrodinger.application.desmond.packages.timer import Timer mytimer = Timer(threshold=0.2) # Creates a timer with 0.2 threshold. with mytimer("Reading the trajectory..."): traj.read_trj(trj_fname) In this example, `mytimer` behaves exactly the same as the standard `timer` (see the docstring of this module) except for the default value of `threshold` parameter that has been customed to 0.2. """ Args = namedtuple("Args", "message threshold fmt record logger")
[docs] def __init__(self, message=None, threshold=0.1, fmt=" Done. (%.2f sec)", record=None, logger=_default_logger): self._default = Timer.Args(message, threshold, fmt, record, logger)
@contextmanager def __call__(self, *arg, **kwarg): a = list(self._default) a = list(arg) + a[len(arg):] # Updates `a' with `arg'. a = Timer.Args(*a) a = a._replace(**kwarg) # Updates `a' with `kwarg'. message, threshold, fmt, record, logger = a message and logger(message) start_time = time.time() yield elapsed_time = time.time() - start_time if elapsed_time > threshold: logger(fmt % elapsed_time) if isinstance(record, list): record.append(elapsed_time)
timer = Timer()