2

I want to measure execution time of a function on the cheap, something like this:

def my_timeit(func, *args, **kwargs):
    t0 = time.time()
    result = func(*args, **kwargs)
    delta = time.time() - t0
    return delta, result

def foo():
    time.sleep(1.23)
    return 'potato'

delta, result = my_timeit(foo)

But I want to use timeit, profile or other built-in to handle whatever are the common pitfalls due to platform differences, and it would probably be also better to get the actual execution time not the wall time.

I tried using timeit.Timer(foo).timeit(number=1) but the interface seems to obscure the return value.

wim
  • 338,267
  • 99
  • 616
  • 750
  • What is your question? – Hyperboreus Jan 07 '14 at 14:31
  • Why are you trying to run the timer only *once*? That'd remove one of the advantages of the `timeit` module; running the code repeatedly to smooth out the influence of random OS and hardware events. – Martijn Pieters Jan 07 '14 at 14:33
  • Hence "on the cheap". It is just to measure execution times of my project euler implementations, I have a goal to keep them under 10 seconds or so. I don't want to wait for it to run more than once. – wim Jan 07 '14 at 14:35
  • @wim Naive question: Wouldn't `timeit` with `number = 1` do the trick? – Hyperboreus Jan 07 '14 at 14:45
  • timeit.Timer is made for running your code gazillion times to get precise measurement of small time. in this case you don't really care about the return value. Intead what you want is a @timeit decorator – Dima Tisnek Jan 07 '14 at 14:56
  • @Hyperboreus I did mention trying that already. It eats the return value. – wim Jan 07 '14 at 15:02
  • I don't want to decorate the function, because most of the time I will be wanting to call it without the wrapper – wim Jan 07 '14 at 15:03

2 Answers2

3

This is my current attempt. But I would welcome any suggestions, because this feels too hacky and could probably do with improvement.

import time
from timeit import Timer

def my_timeit(func, *args, **kwargs):
    output_container = []
    def wrapper():
        output_container.append(func(*args, **kwargs))
    timer = Timer(wrapper)
    delta = timer.timeit(1)
    return delta, output_container.pop()

def foo():
    time.sleep(1.111)
    return 'potato'

delta, result = my_timeit(foo)

edit: adapted to work as a decorator below:

def timeit_decorator(the_func):

    @functools.wraps(the_func)
    def my_timeit(*args, **kwargs):
        output_container = []
        def wrapper():
            output_container.append(the_func(*args, **kwargs))
        timer = Timer(wrapper)
        delta = timer.timeit(1)
        my_timeit.last_execution_time = delta
        return output_container.pop()

    return my_timeit
wim
  • 338,267
  • 99
  • 616
  • 750
  • Hi - I'm unfamiliar with decorators, but want to try this. Could you provide a little more to show an example calling your decorator? – Joel Apr 10 '18 at 05:54
  • @Joel just use it like a normal decorator. The `last_execution_time` attribute will be set on the function object after each call. – wim Apr 10 '18 at 13:16
0

How about

>>time python yourprogram.py < input.txt

This is the output for a python script I ran

[20:13:29] praveen:jan$ time python mtrick.py < input_mtrick.txt 
3 3 9
1 2 3 4
real    0m0.067s
user    0m0.016s
sys 0m0.012s
praveen
  • 3,193
  • 2
  • 26
  • 30