Last active
October 21, 2022 21:16
-
-
Save dutc/38ea08a0bb6693cd9f7507421ac8e62b to your computer and use it in GitHub Desktop.
A timing context manager.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dataclasses import dataclass, field, replace | |
from collections import namedtuple, defaultdict | |
from itertools import count | |
from collections.abc import Generator | |
from contextlib import contextmanager | |
from time import perf_counter | |
from networkx import DiGraph | |
@dataclass(frozen=True) | |
class timer: | |
measure : Generator = (perf_counter() for _ in count()) | |
labels : Generator = field(default_factory=count) | |
measurements : list = field(default_factory=list) | |
parent : int = -1 | |
Measurement = namedtuple('MeasurementBase', 'label parent value') | |
@property | |
@contextmanager | |
def lap(self): | |
self.measurements.append( | |
self.Measurement(lbl := next(self.labels), parent := self.parent, next(self.measure)) | |
) | |
try: | |
yield replace(self, parent=lbl) | |
finally: | |
self.measurements.append( | |
self.Measurement(lbl, parent, next(self.measure)) | |
) | |
class Interval(namedtuple('IntervalBase', 'start stop')): | |
delta = property(lambda self: self.stop.value - self.start.value) | |
__iter__ = lambda self: iter(self.measurements) | |
def traverse(self, *, root=(_root := object())): | |
def dfs(n, *, depth=-1): | |
if n is not root: | |
yield depth, n | |
for n in g[n]: | |
yield from dfs(n, depth=depth+1) | |
g = self.as_graph | |
return dfs(root) | |
@property | |
def as_graph(self): | |
nodes = defaultdict(list) | |
for m in self: | |
nodes[m.label].append(m) | |
nodes = {k: self.Interval(*ns) for k, ns in nodes.items()} | |
(g := DiGraph()).add_edges_from( | |
(nodes.get(n.start.parent, self._root), n) for n in nodes.values() | |
) | |
return g | |
if __name__ == '__main__': | |
from time import sleep | |
with timer().lap as t: | |
sleep(.1) | |
with t.lap as t1: | |
sleep(.2) | |
with t1.lap: | |
sleep(.3) | |
with t.lap as t1: | |
sleep(.2) | |
for depth, intvl in t.traverse(): | |
print(f'{"":<{depth * 4}} \N{mathematical bold capital delta}t: {intvl.delta:.2f}s') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment