-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the ExecTiming wiki!
ExecTiming is a package for Python the provides an easy way to measure the execution time of pieces of code. Several cool features include decorators, best-fit-curve determination, graphing features, and the ability to redirect the output to any file-like object.
pip install exectiming
# scipy, numpy, and scikit-learn are required for best-fit-curve determination
# matplotlib is needed for plotting
pip install --no-deps exectiming # can be used if the best-fit-curve and plotting parts will not be used
from exectiming.exectiming import StaticTimer
@StaticTimer.decorate()
def factorial(n):
if n <= 1:
return 1
else:
return n * factorial.__wrapped__(n-1)
factorial(50)
# 0.02175 ms - factorial ... [runs= 1, iterations= 1]
.decorate()
can be used to wrap any function, even a recursive one, such that the function will be timed whenever it is called. .__wrapped__(n-1)
is used so that the decorator is by-passed on the recursive call, which is necessary to avoid unpredictable behavior.
StaticTimer
is intended for quick tests where the output is immediately displayed or returned and doesn't need to be retained. Other important methods for StaticTimer
are .start()
, .elapsed()
, and .time_it()
.
from exectiming.exectiming import Timer
from time import sleep
timer = Timer(split=True)
timer.start()
sleep(1.0)
timer.log()
timer.output()
# Split:
# 1000.43591 ms - Log ... [runs= 1, iterations= 1]
Timer()
retains measured times and a method like .output()
must be called to get any output. .start()
and .elapsed()
can be used to measure the execution time of statements that aren't in a function. Timer()
organizes data into splits which contain runs. Splits are used to separate the measured times of different sections of code.
from exectiming.exectiming import Timer
timer = Timer()
@timer.decorate(runs=100, iterations_per_run=5, log_arguments=True, call_callable_args=True)
def binary_search(sorted_array, element):
lower, upper = 0, len(sorted_array)
middle = upper // 2
while middle >= lower and middle != upper:
if element == sorted_array[middle]:
return middle
elif element > sorted_array[middle]:
lower = middle + 1 # lower must be beyond middle because the middle wasn't right
else:
upper = middle - 1 # upper must be lower than the middle because the middle wasn't right
middle = (upper + lower) // 2
return None # couldn't find it
binary_search(lambda: [i for i in range(randint(0, 10000))], lambda: randint(0, 10000))
timer.plot(plot_curve=True, curve=timer.best_fit_curve(exclude={1}, transformers=len), key=0,
transformer=len, time_unit=timer.US, x_label="List Length", equation_rounding=4,
title="Binary Search - Random Size, Random Element")
Above, a function named binary_search
is wrapped with a decorator that executes the function for 500 runs, each with 5 iterations. The time for each run is the sum of the execution time of the 5 iterations. iterations_per_run
can be important in situations like this where the runtime is very quick and so repeating the call a couple of times can help make sure the measured time is more accurate.
binary_search
is called with two anonymous functions but requires a list and integer according to the function definition. However, the decorator has call_callable_args=True
, meaning binary_search
is actually passed the return values of calls to the anonymous functions. The same return value is used for all the iterations, but each run will result in a new set of parameters. The option to replace parameters with the return value of a call to them allows greater testing through randomized data.
After binary_search
executes, the best-fit-curve is determined. All arguments must be integers and many of the best-fit-curve options require there to be only one independent variable. This is accomplished by transforming the first parameter, the list, to be its length, which is done with transformers=len
. The second parameter, at index 1
is excluded with exclude={1}
.
Finally, the measured times and best-fit-curve are plotted using matplotlib
. Again, there can only be one independent variable for plotting and it must be an integer, so .plot()
is passed key=0
and transformer=len
to use the positional argument at index 0 and to transform it into an integer using len
. The best-fit-curve data is passed in as well.