Timing
In conjunction with profiling, timing information is useful in determining which algorithms or implementations run faster as compared to others, and how those run times scale with problem size. For Python code, useful functionality is provided by the timeit
and time
libraries, as well as the IPython magic function %timeit
.
timeit and %timeit
The timeit module in the Python Standard Library provides information on the run time required to execute a Python statement,
similar to the way that the cProfile
module provides profiling information associated with a Python statement. In its simplest form, the module provides a timeit
function that executes the specified expression a stated number of times, returning the total time required for all those evaluations.
Reproducing from the online documentation:
This simple form is sufficient if one is accessing Python functions and objects that reside in the built-in namespace, but is a bit more clunky if one wants to time a function in a module that must be imported to Python. For example, if we wanted to time the integrate_lorenz()
that was profiled on the previous page, we would need to pass an additional keyword argument as timeit's setup
:
This tells us that it took approximately 33.47 seconds to run the integrate_lorenz() function 100 times.
As we have seen previously, the enhanced IPython interpreter offers similar functionality through its %timeit
magic function, which includes more features and has a more convenient interface.
The %timeit
magic decides how many times to run the specified expression based on its run time, and provides information not just about mean run time, but also the standard deviation over the ensemble of runs. In cases where the run times of individual executions have severe outliers and do not appear to be normally distributed, %timeit
will issue a warning that the run time statistics appear odd and that other factors such as cache misses might be impacting the timing results. It should also be noted that a setup argument is not required, as it is in the timeit.timeit
function; %timeit
can access the required function from the namespace into which it has been imported. The %timeit
command makes benchmarking code snippets large and small very straightforward and convenient. If you run some of the %timeit
examples shown throughout this topic, you will not see identical numbers to those reported here (due to differences in hardware, linked software libraries, and statistical fluctuations, among other things).
time
The time module in the Standard Library is more low-level but provides useful support for fine-grained timing information. It is intended to both provide access to the current time as well as conversions between different representations of times. Of primary interest here is the function time.time()
, which returns the current time in seconds since the epoch. We are not so much concerned with time elapsed since the epoch, but instead with time elapsed between different parts of our code. By instrumenting code with successive calls to time.time()
and calculating differences between those instants, we might be able to pin down where precisely in some block of code the bulk of time is being spent, as in this contrived example: