Time Trials

We’re competitive creatures. We like pitting things and ourselves against each other. We’re also mortal. We don’t have all the time in the world waiting for an algorithm to finish. It’s very useful to have a way to measure and compare execution times.

My Python time trials make use of the timeit module. It’s handy because the timer doesn’t include time elapsed on OS operations that don’t relate to the Python code.

import timeit

First, here’s my function to measure average execution time of any unsuspecting function (using 5 trials). I like it because it uses argument unpacking to make it flexible.

def average_execution_time(function, args):
    """Measures the average execution time of a function by performing five time trials.
    
    Args:
        args (tuple): the arguments to be passed into the function.  If no arguments, use ().
                      If only one argument, use (arg1,).
                      If more than two arguments, use (arg1, arg2, ...)
                      
    Returns:
        the average execution time in seconds (it'll probably look like scientific notation)
    """
    
    results = 0
    for i in range(5):
        start = timeit.default_timer()
        function(*args) # Unpack arguments to be passed into the function
        end = timeit.default_timer()
        results += end - start
    return results / 5

Let’s say I have three function calls: fun1(), fun2(arg1), and fun3(arg1, arg2). Respectively, average_execution_time is called like this: average_execution_time(fun1, ()), average_execution_time(fun2, (arg1,)), and average_execution_time(fun3, (arg1, arg2)).

Second, here’s my function that compares two functions and sees which one comes out ahead!

def compare_execution_times(function1, args1, function2, args2):
    """Compares the average execution times of two functions!"""
    
    function1_time = average_execution_time(function1, args1)
    function2_time = average_execution_time(function2, args2)
    time_diff = str(round(abs(function2_time - function1_time), 10))
    if function2_time > function1_time:
        factor = str(round(function2_time / function1_time, 3))
        print(function1.__name__ + " wins!  Time difference: " + time_diff + " seconds, factor of " + factor)
    else:
        factor = str(round(function1_time / function2_time, 3))
        print(function2.__name__ + " wins!  Time difference: " + time_diff + " seconds, factor of " + factor)

Here’s a quick demo. I spun up two simple functions: one slow, one blisteringly fast as my turtle and hare.

def slow():
    x = 0
    for i in range(100000000):
        x += 1

def fast():
    pass

Pitting them against each other with compare_execution_times shows the result:

>>> compare_execution_times(slow, (), fast, ())
<function fast at 0x0000027BA06ED940> wins!  Time difference: 3.97107448 seconds, factor of 11030757.481

Gee whiz! That’s pretty fast. I use these two functions quite often in evaluating my (usually poor) performance in writing solutions to Project Euler problems. If you want to use them, here’s my GitHub.