Source code for capytaine.tools.timer

"""A simple timer class used to measure the time spent in various parts of the BEM solver."""

from functools import wraps
import time
import contextlib

import pandas as pd

[docs] class Timer: """A timer class that can be used as context manager or as decorator using `wraps_function` method. Several timing measurement can be nested. Attributes ---------- timings: List[Dict]] List of records of each timing measurement. The record is a dict with a 'timing' key and any number of other metadata keys. default_tags: Optional[Dict] Tags added to all the timing measurements. _start_times: List[float] Start times of the ongoing timing measurements. Example ------- :: from time import sleep # For testing timer = Timer() with timer(tag="run 1"): sleep(1.0) print(timer.total) # 1.0... @timer.wraps_function(tag="run function") def my_function(): sleep(0.5) my_function() print(timer.total) # 1.5... my_function() print(timer.total) # 2.0... with timer(tag="outer"): sleep(0.3) with timer(tag="inner"): sleep(0.3) sleep(0.3) """ def __init__(self, *, default_tags=None): self.timings = [] if default_tags is None: default_tags = {} self.default_tags = default_tags self._start_times = [] # Starting time of ongoing sub-timers def __repr__(self): return f"Timer({self.timings})"
[docs] def add_data_from_other_timer(self, other, **supplementary_tags): self.timings.extend([{**t, **supplementary_tags} for t in other.timings])
@contextlib.contextmanager def __call__(self, **tags): self._start_times.append(time.perf_counter()) try: yield finally: timing = time.perf_counter() - self._start_times.pop() self.timings.append({'timing': timing, **tags, **self.default_tags})
[docs] def wraps_function(self, **tags): def wrapper(f): @wraps(f) def wrapped_f(*args, **kwargs): with self(**tags): out = f(*args, **kwargs) return out return wrapped_f return wrapper
[docs] def as_dataframe(self): if len(self.timings) == 0: return pd.DataFrame([{'timing': 0.0}]) else: return pd.DataFrame(self.timings)
@property def total(self): return self.as_dataframe()['timing'].sum()