Timer¶
- class delu.tools.Timer[source]¶
Bases:
objectA simple pickle-friendly timer for measuring execution time.
Timeris applicable to both long-running activies (e.g. a whole program) and limited code regions (e.g. training steps).Timercan be paused/resumed to measure execution time of only relevant activities.Timercan be used as a context manager.Timeris pickle-friendly and can be saved to / loaded from a checkpoint.Timercan report the elapsed time as a human-readable string withprint,str,formatand f-strings.
Note
Under the hood,
Timerusestime.perf_counterto perform time measurements.Timeris not aware of CUDA, so things liketorch.cuda.synchronizemust be called explicitly if needed.
Usage
The common setup for all examples:
>>> from time import sleep >>> >>> def train_epoch(): sleep(0.001) >>> def evaluate_epoch(): sleep(0.001)
Measuring the execution time of a training loop:
>>> # Initially, the timer is not running. >>> timer = delu.tools.Timer() >>> assert not timer.is_running >>> >>> # Run the timer. >>> timer.run() >>> assert timer.is_running >>> >>> for epoch in range(100): ... train_epoch() ... evaluate_epoch() >>> duration = timer.elapsed()
Same as above, but using a context:
Important
When entering the context, the timer must not be running.
>>> # Or simply `with delu.tools.Timer() as timer:` >>> timer = delu.tools.Timer() >>> with timer: ... # On enter, timer.run() is called. ... assert timer.is_running ... for epoch in range(100): ... train_epoch() ... evaluate_epoch() ... >>> # On exit, timer.pause() is called. >>> assert not timer.is_running >>> duration = timer.elapsed()
Measuring the execution time only of the training activity:
>>> timer = delu.tools.Timer() >>> for epoch in range(100): ... timer.run() # Start/resume the timer. ... train_epoch() # Recorded. ... timer.pause() # Pause the timer. ... ... evaluate_epoch() # Not recorded. >>> total_training_duration = timer.elapsed()
Same as above, but using a context:
>>> timer = delu.tools.Timer() >>> for epoch in range(100): ... with timer: ... train_epoch() ... evaluate_epoch() >>> total_training_duration = timer.elapsed()
Using the timer as a global timer (the difference with using
time.perf_counterdirectly is that thestartvariable below can be safely saved to / loaded from a checkpoint):>>> timer = delu.tools.Timer() >>> timer.run() >>> ... # Other activities. >>> start = timer.elapsed() >>> sleep(0.001) >>> end = timer.elapsed() >>> duration = end - start
Resetting the timer:
>>> timer.reset() >>> assert not timer.is_running >>> timer.elapsed() == 0.0 True
Reporting the elapsed time in a human-readable format (the default format is the same as for
datetime.timedelta:[days "days" if >0] hours:minutes:seconds[.microseconds if >0]):>>> timer = delu.tools.Timer() >>> timer.run() >>> sleep(2.0) # Sleep for two seconds. >>> timer.pause() >>> >>> # print(timer) also works >>> str(timer) == format(timer) == f'{timer}' >>> >>> # Two seconds plus epsilon: >>> str(timer).startswith('0:00:02.') True >>> f'{timer:%Hh %Mm %Ss}' '00h 00m 02s' >>> format(timer, '%Hh %Mm %Ss') '00h 00m 02s'
A timer can be saved with
torch.save/pickle.dumpand loaded withtorch.load/pickle.loadtogether with other objects:>>> import tempfile >>> >>> model = nn.Linear(1, 1) >>> timer = delu.tools.Timer() >>> timer.run() >>> sleep(0.001) >>> ... >>> with tempfile.TemporaryDirectory() as tmpdir: ... path = f'{tmpdir}/checkpoint.pt' ... torch.save( ... {'model': model.state_dict(), 'timer': timer}, ... path, ... ) ... ... ... checkpoint = torch.load(path) ... model.load_state_dict(checkpoint['model']) ... # The just loaded timer is on pause, ... # so it must be explicitly resumed. ... timer = checkpoint['timer'] ... assert not timer.is_running ... timer.run()
Additional technical examples:
>>> # Implementing a pause context. >>> from contextlib import ExitStack >>> >>> timer = delu.tools.Timer() >>> timer.run() >>> ... >>> timer.pause() >>> with ExitStack() as stack: ... # Call `timer.run()` on exit. ... stack.callback(timer.run) ... ... # Some activity which is not recorded by the timer. >>> timer.is_running True
- __enter__() Timer[source]¶
Measure time within a context.
The timer must not be running when entering the context.
On enter,
Timer.runis called regardless of the current state.On exit,
Timer.pauseis called regardless of the current state.
- __format__(format_spec: str, /) str[source]¶
Format the time elapsed since the start in a human-readable string.
This is a shortcut for
time.strftime(format_str, time.gmtime(self())).- Parameters:
format_str – the format string passed to
time.strftime.- Returns:
the filled
format_str.
Usage
>>> # xdoctest: +SKIP >>> timer = delu.tools.Timer() >>> # Let's say that exactly 3661 seconds have passed. >>> assert format(timer, '%Hh %Mm %Ss') == '01h 01m 01s'
- __setstate__(state: dict[str, Any]) None[source]¶
Load the state.
A time with just loaded state is not running (basically, it is a freshly created timer which stores the elapsed time from the loaded state).
- elapsed() float[source]¶
Get the time elapsed.
The elapsed time is the time (in seconds) passed since the first
.run()call up to the.elapsed()call, minus pauses.- Returns:
The elapsed time.
- pause() None[source]¶
Pause the timer.
If the timer is running, the method pauses the timer. If the timer was never
.run()or is already on pause, the method does nothing.