Source code for dgs.utils.timer

"""
Models, functions and helpers for timing operations.
"""

import time
from collections import UserDict, UserList
from datetime import timedelta


[docs] class DifferenceTimer(UserList): """A simple timer based on time differences, with a few helper functions.""" data: list[float] """A list containing time differences in seconds."""
[docs] def __init__(self) -> None: super().__init__()
[docs] def add(self, prev_time: float, now: float = None) -> float: """Append the difference between a previous time and the current time to this timer. Args: prev_time: The previous time in seconds. The value is used to compute the time difference in seconds to now. now: The current time in seconds. If not provided, the current time is used. Can be used to make sure, that the time difference is computed relative to a specific time when computing multiple values. Returns: diff: The difference between now and the previous value in seconds. """ if now is None: now = time.time() diff = now - prev_time self.data.append(diff) return diff
[docs] def average(self) -> float: """Return the average time in seconds.""" if len(self.data) == 0: return 0.0 return self.sum() / len(self.data)
[docs] def sum(self) -> float: """Return the absolute sum of all the individual timings in seconds.""" if len(self.data) == 0: return 0.0 return sum(self.data)
[docs] def avg_hms(self) -> str: """Get the total average time and return it as str with `HH:MM:SS`.""" return str(timedelta(seconds=round(self.average())))
[docs] def sum_hms(self) -> str: """Get the summed-up time and return it as str with `HH:MM:SS`.""" return str(timedelta(seconds=round(self.sum())))
[docs] def print(self, name: str, prepend: str, hms: bool = False) -> str: # pragma: no cover """Generate string for printing, containing average and total time.""" if hms: return ( f"{str(prepend)}: " f"{str(name)} time average: {self.avg_hms()} [H:MM:SS], " f"{str(name)} time total: {self.sum_hms()} [H:MM:SS]" ) return ( f"{str(prepend)}: " f"{str(name)} time average: {self.average():.1f} [s], " f"{str(name)} time total: {self.sum():.1f} [s]" )
[docs] class DifferenceTimers(UserDict): """Object to store the information of multiple :class:`DifferenceTimer` objects.""" data: dict[str, DifferenceTimer]
[docs] def __init__(self, names: list[str] = None) -> None: super().__init__({name: DifferenceTimer() for name in names or []})
def __getitem__(self, item) -> DifferenceTimer: return self.data[item]
[docs] def add(self, name: str, prev_time: float, now: float = None) -> float: """Add a new time difference to the timer with the given name. Creates a new timer if it does not exist yet. Args: name: The name of the timer. prev_time: The previous time in seconds. This value is used to compute the time difference in seconds relative to now. now: The current time in seconds. Returns: The difference between now and the previous value in seconds. """ if now is None: now = time.time() if name not in self.data: self.data[name] = DifferenceTimer() return self.data[name].add(prev_time=prev_time, now=now)
[docs] def add_multiple(self, prev_times: dict[str, float]) -> dict[str, float]: """Add a bunch of new time differences to the respective timers. Creates new timers if they do not exist yet. Args: prev_times: A dict mapping the name of the timer to the previous time in seconds. Returns: A dict containing the time differences in seconds for each of the named timers. """ diffs = {} now = time.time() for name, prev_time in prev_times.items(): if name not in self.data: self.data[name] = DifferenceTimer() diffs[name] = self.data[name].add(prev_time=prev_time, now=now) return diffs
[docs] def print(self, prepend: str, hms: bool = False) -> str: # pragma: no cover """Generate a string for printing, containing average and total time for all timers.""" s = prepend + ":\n" for name, timer in self.data.items(): s += timer.print(name, prepend="", hms=hms) + "\n" return s
[docs] def get_sums(self) -> dict[str, float]: """Return the summed-up times for all timers.""" return {name: timer.sum() for name, timer in self.data.items()}
[docs] def get_avgs(self) -> dict[str, float]: """Return the average times for all timers.""" return {name: timer.average() for name, timer in self.data.items()}
[docs] def get_last(self) -> dict[str, float]: """Return the last time difference for all timers.""" return {name: timer.data[-1] for name, timer in self.data.items()}