12

The magic command %timeit is great to measure code execution times in an interactive way. However, I want to get the result of %timeit in order to plot the results. timeit.timeit allows this as well, but does not have the automatic scaling of the number of iterations and the normalising of the result that %timeit has.

Is there a built in function that can time a piece of code, which also automatically adjusts the number of iterations it performs, and returns a normalised result?

Mark van der Wilk
  • 777
  • 1
  • 9
  • 18
  • 1
    I think there is not, but for timing you can just create a timer decorator, the iteration counter is not so easy to make it work as you would like. – Netwave Nov 26 '15 at 17:36
  • https://github.com/ipython/ipython/blob/acb2c91c5522bf1c0cb1c06c1882044a08cdf09b/IPython/core/magics/execution.py#L902 - though probably not usable from a user perspective. – Caramiriel Nov 26 '15 at 18:49

3 Answers3

9

The magic %timeit command offers a -o option:

-o: return a TimeitResult that can be stored in a variable to inspect the result in more details.

It will still print the result but also return the result so that it can be captured in a variable. The syntax for magic commands is a bit limited but you could collect different results in a list by assigning it to a variable and appending that variable to a list:

res = []
for i in range(3):
    a = %timeit -o 10*10
    res.append(a)
# 10000000 loops, best of 3: 61 ns per loop
# 10000000 loops, best of 3: 61.1 ns per loop
# 10000000 loops, best of 3: 60.8 ns per loop

and then access res:

print(res)
# [<TimeitResult : 10000000 loops, best of 3: 61.2 ns per loop>,
#  <TimeitResult : 10000000 loops, best of 3: 61.3 ns per loop>,
#  <TimeitResult : 10000000 loops, best of 3: 61.5 ns per loop>]

Each of these results has several attributes, which might be of interest:

print(res[0].all_runs)
# [0.6166532894762563, 0.6102780388983005, 0.6370787790842183]
print(res[0].best)
# 6.102780388983005e-08
print(res[0].compile_time)
# 0.00020554513866197934
print(res[0].loops)
# 10000000
print(res[0].repeat)
# 3
print(res[0].worst)
# 1.1170931449020795e-06

To plot for example the best times you need to create a new list containing the best values:

res_best_times = [result.best * 1e9 for result in res] 
# "* 1e9" to get the result in nanoseconds
print(res_best_times)
# [61.2, 61.3, 61.5]
MSeifert
  • 145,886
  • 38
  • 333
  • 352
7

Assuming you can use/import IPython, and you simply want to create a headless script that uses the %timeit magic, you could do something like the following.

Assume the following is in the file testme.py:

from IPython import get_ipython

def myfun(x):
    return x**x

val = 12.3
out = get_ipython().run_line_magic("timeit","-o myfun({})".format(val))

#do something with out, which will be a TimeitResult object

Then you can run the script non-interactively with:

ipython testme.py
svohara
  • 2,159
  • 19
  • 17
2

Using cell magic %%

In:

%%timeit -o
res = []
for i in range(5):
    a = 10*10
    res.append(a)

Out:

526 ns ± 44.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
<TimeitResult : 526 ns ± 44.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)>

The variable underscore '_' stores the last expression value

In:

result = _
result

Out:

<TimeitResult : 526 ns ± 44.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)>

And now we can get more data from attributes (help(result))

In:

print(result.average)  # 2.358365715216288e-06
print(result.stdev)  # 5.159462070683934e-07
print(result.timings)  #[3.5457100011626608e-06, ..., 2.4937099988164847e-06]
print(result.all_runs)  # [0.0003545710001162661, ... 0.00024937099988164846]
print(result.best)  # 2.003900021442676e-06
print(result.compile_time)  # 0.00030000000000995897
print(result.loops)  # 100
print(result.repeat)  # 7
print(result.worst)  # 3.5457100011626608e-06
Szczerski
  • 839
  • 11
  • 11