A powerful multiline alternative to timeit
Project description
Timerit
A powerful multiline alternative to Python’s builtin timeit module.
Docs are published at https://timerit.readthedocs.io/en/latest/ but this README and code comments contain a walkthrough.
Description
Easily do robust timings on existing blocks of code by simply indenting them. There is no need to refactor into a string representation or convert to a single line.
Installation
From pypi:
pip install timerit
From github:
pip install git+https://github.com/Erotemic/timerit.git
Examples
The quick and dirty way just requires one indent.
>>> import math
>>> from timerit import Timerit
>>> for _ in Timerit(num=200, verbose=2):
>>> math.factorial(10000)
Timing for 200 loops
Timed for: 200 loops, best of 3
time per loop: best=2.469 ms, mean=2.49 ± 0.037 ms
Use the loop variable as a context manager for more accurate timings or to incorporate an setup phase that is not timed. You can also access properties of the Timerit class to programmatically use results.
>>> import math
>>> from timerit import Timerit
>>> t1 = Timerit(num=200, verbose=2)
>>> for timer in t1:
>>> setup_vars = 10000
>>> with timer:
>>> math.factorial(setup_vars)
>>> print('t1.total_time = %r' % (t1.total_time,))
Timing for 200 loops
Timed for: 200 loops, best of 3
time per loop: best=2.064 ms, mean=2.115 ± 0.05 ms
t1.total_time = 0.4427177629695507
There is also a simple one-liner that is comparable to IPython magic:
Compare the timeit version:
>>> %timeit math.factorial(100)
564 ns ± 5.46 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
With the Timerit version:
>>> Timerit(100000).call(math.factorial, 100).print()
Timed for: 1 loops, best of 1
time per loop: best=4.828 µs, mean=4.828 ± 0.0 µs
How it works
The timerit module defines timerit.Timerit, which is an object that is iterable. It has an __iter__ method that generates timerit.TimerTimer objects, which are context managers.
>>> import math >>> from timerit import Timerit >>> for timer in Timerit(num=200, verbose=2): >>> with timer: >>> math.factorial(10000)
The timer context manager measures how much time the body of it takes by “tic”-ing __enter__ and “toc”-ing on __exit__. The underlying object has access to the context manager, so it is able to read its measurement. These measurements are stored and then we compute some statistics on them. Notably the minimum, mean, and standard-deviation of grouped (batched) running times.
Unfortunately the syntax is one line and one indent bulker than I would prefer. However, a more consice version of the synax is available.
>>> import math >>> from timerit import Timerit >>> for _ in Timerit(num=200, verbose=2): >>> math.factorial(10000)
In this case the measurement is made in the __iter__ method Timerit object itself, which I believe contains slightly more overhead than the with-statement version. (I have seen evidence that this might actually be more accurate, but it needs further testing).
Benchmark Recipe
import ubelt as ub
import pandas as pd
import timerit
def method1(x):
ret = []
for i in range(x):
ret.append(i)
return ret
def method2(x):
ret = [i for i in range(x)]
return ret
method_lut = locals() # can populate this some other way
ti = timerit.Timerit(100, bestof=10, verbose=2)
basis = {
'method': ['method1', 'method2'],
'x': list(range(7)),
# 'param_name': [param values],
}
grid_iter = ub.named_product(basis)
# For each variation of your experiment, create a row.
rows = []
for params in grid_iter:
key = ub.repr2(params, compact=1, si=1)
kwargs = params.copy()
method_key = kwargs.pop('method')
method = method_lut[method_key]
# Timerit will run some user-specified number of loops.
# and compute time stats with similar methodology to timeit
for timer in ti.reset(key):
# Put any setup logic you dont want to time here.
# ...
with timer:
# Put the logic you want to time here
method(**kwargs)
row = {
'mean': ti.mean(),
'min': ti.min(),
'key': key,
**params,
}
rows.append(row)
# The rows define a long-form pandas data array.
# Data in long-form makes it very easy to use seaborn.
data = pd.DataFrame(rows)
print(data)
plot = True
if plot:
# import seaborn as sns
# kwplot autosns works well for IPython and script execution.
# not sure about notebooks.
import kwplot
sns = kwplot.autosns()
# Your variables may change
ax = kwplot.figure(fnum=1, doclf=True).gca()
sns.lineplot(data=data, x='x', y='min', hue='method', marker='o', ax=ax)
ax.set_title('Benchmark')
ax.set_xlabel('A better x-variable description')
ax.set_ylabel('A better y-variable description')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file timerit-1.0.0.tar.gz
.
File metadata
- Download URL: timerit-1.0.0.tar.gz
- Upload date:
- Size: 17.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | fe6ebb4f0821f7996a61f851f54647905fc6b9b7f403a34233d2efd900820899 |
|
MD5 | 97cf08e76993f288ea815278606f4454 |
|
BLAKE2b-256 | 9400741370e9d9ffb227189ce87c8a772af1292d309e8859e65a901bb67c0a5b |
File details
Details for the file timerit-1.0.0-py3-none-any.whl
.
File metadata
- Download URL: timerit-1.0.0-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 943efe6c112b60a927b1bf58a9562bb990ef81b5a4e64e5deb4d0c45b0b10126 |
|
MD5 | c46b172800eedd9230e4a4c64548f92c |
|
BLAKE2b-256 | d3d48024debf0627267125fa78503ff6cb9c0874983b57311feadb90d7da668d |