Skip to content

timepiece

Utilities for dealing with time.

Stopwatch

Simple timer utility for measuring code execution time.

Source code in src/jetplot/timepiece.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Stopwatch:
    """Simple timer utility for measuring code execution time."""

    def __init__(self, name: str = "") -> None:
        self.name = name
        self.start = time.perf_counter()
        self.absolute_start = time.perf_counter()

    def __str__(self) -> str:
        return "\u231a  Stopwatch for: " + self.name

    @property
    def elapsed(self) -> float:
        current = time.perf_counter()
        elapsed = current - self.start
        self.start = time.perf_counter()
        return elapsed

    def checkpoint(self, name: str = "") -> None:
        print(f"{self.name} {name} took {hrtime(self.elapsed)}".strip())

    def __enter__(self) -> "Stopwatch":
        return self

    def __exit__(self, *_: object) -> None:
        total = hrtime(time.perf_counter() - self.absolute_start)
        print(f"{self.name} Finished! \u2714\nTotal elapsed time: {total}")

hrtime(t: float) -> str

Converts a time in seconds to a reasonable human readable time.

Parameters:

Name Type Description Default
t float

float, Time in seconds.

required

Returns:

Name Type Description
time str

string, Human readable formatted value of the given time.

Source code in src/jetplot/timepiece.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def hrtime(t: float) -> str:
    """Converts a time in seconds to a reasonable human readable time.

    Args:
      t: float, Time in seconds.

    Returns:
      time: string, Human readable formatted value of the given time.
    """

    # weeks
    if t >= 7 * 60 * 60 * 24:
        weeks = np.floor(t / (7 * 60 * 60 * 24))
        timestr = f"{weeks:0.0f} weeks, " + hrtime(t % (7 * 60 * 60 * 24))

    # days
    elif t >= 60 * 60 * 24:
        days = np.floor(t / (60 * 60 * 24))
        timestr = f"{days:0.0f} days, " + hrtime(t % (60 * 60 * 24))

    # hours
    elif t >= 60 * 60:
        hours = np.floor(t / (60 * 60))
        timestr = f"{hours:0.0f} hours, " + hrtime(t % (60 * 60))

    # minutes
    elif t >= 60:
        minutes = np.floor(t / 60)
        timestr = f"{minutes:0.0f} min., " + hrtime(t % 60)

    # seconds
    elif (t >= 1) | (t == 0):
        timestr = f"{t:g} s"

    # milliseconds
    elif t >= 1e-3:
        timestr = f"{t * 1e3:g} ms"

    # microseconds
    elif t >= 1e-6:
        timestr = f"{t * 1e6:g} \u03bcs"

    # nanoseconds or smaller
    else:
        timestr = f"{t * 1e9:g} ns"

    return timestr

profile(func: Callable[..., Any]) -> Callable[..., Any]

Timing (profile) decorator for a function.

Source code in src/jetplot/timepiece.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def profile(func: Callable[..., Any]) -> Callable[..., Any]:
    """Timing (profile) decorator for a function."""
    calls = list()

    @wraps(func)
    def wrapper(*args, **kwargs):
        tstart = time.perf_counter()
        results = func(*args, **kwargs)
        tstop = time.perf_counter()
        calls.append(tstop - tstart)
        return results

    def mean() -> float:
        return float(np.mean(calls))

    def serr() -> float:
        return float(np.std(calls) / np.sqrt(len(calls)))

    def summary() -> None:
        print(f"Runtimes: {hrtime(mean())} \u00b1 {hrtime(serr())}")

    wrapper.__dict__["calls"] = calls
    wrapper.__dict__["mean"] = mean
    wrapper.__dict__["serr"] = serr
    wrapper.__dict__["summary"] = summary

    return wrapper