Did you know — Python Tips
Measure the execution time of your Python codes
As we start becoming proficient in a programming language, we aspire to not only deliver the end objective but also to make our programs efficient.
In this tutorial of Did you know series we will learn about a few Ipython’s magic commands which can help us time profile our Python codes.
Note that, for the purpose of this tutorial, it is recommended to use Anaconda distribution.
1.) Profiling a single line of code
To check the execution time of a single line of python code, use %timeit. A simple example below to see how it works:
#### Simple usage of magics command %timeit
%timeit [num for num in range(20)]#### Output
1.08 µs ± 43 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Key notes:
- Use %timeit just before the line of code to be profiled
- It returns the average and standard deviation of code run time calculated over r number or runs and n number of loops within each run. In the above example, the list comprehension was evaluated for 7 runs with each run having 1 million loops (default behaviour). This took an average of 1.08 microsecond with a standard deviation of 43 nanoseconds.
- One can customise the number of runs and loops while calling the magic command. The example is below for reference:
#### Customizing number of runs and loops in %timeit magic command
%timeit -r5 -n100 [num for num in range(20)]1.01 µs ± 5.75 ns per loop (mean ± std. dev. of 5 runs, 100 loops each)
Using command options -r and -n, indicating # of runs and count of loops respectively, we have customised the time profile operation to 5 runs and 100 loops within each run.
2.) Profiling multiple lines of code
This section takes a step forward and explains how one can profile a complete code block. By making a small modification to %timeit magic command, replacing single percentage (%) with double percentage (%%), one can profile a complete code block. A sample demonstration for reference below:
#### Time profiling the code block using %%timeit
%%timeit -r5 -n1000
for i in range(10):
n = i**2
m = i**3
o = abs(i)#### Output
10.5 µs ± 226 ns per loop (mean ± std. dev. of 5 runs, 1000 loops each)
It can be observed that the average execution time of the for loop is 10.5 microseconds. Note that the same command options -r and -n are use to control the count of runs and # of loops within each run respectively.
3.) Time profiling each line of code within a code block
Till now, we have only looked at summary stats when profiling single line of code or a complete code block. What if we want to evaluate the performance of each line of code within the code block? Line profiler package to the rescue!!!
Line_profiler package can be used to perform line by line profiling of any function. To work with line_profiler package, take the following steps:
- Install package — The line profiler package can be installed with a simple call to pip or conda install. If one is using anaconda distribution for Python, using conda install is recommended
#### Installing line_profiler package
conda install line_profiler
- Load Extension — Once installed, you can use IPython to load the line_profiler IPython extension, offered as part of this package:
#### Loading line_profiler's Ipython extension
%load_ext line_profiler
- Time Profile the Function — Once loaded, use the following syntax to time profile any predefined function
%lprun -f function_name_only function_call_with_arguments
Syntax details:
- The call to line_profiler starts with keyword %lprun and is followed by command option -f
- The command option is then followed by the function name and then the function call
For the purpose of this exercise, we will define a function accepting list of heights (in meter) and weight (in lbs) as inputs and converts these in to centimetre and kg respectively.
#### Defining the function
def conversion(ht_mtrs, wt_lbs ):
ht_cms = [ht*100 for ht in ht_mtrs]
wt_kgs = [wt*.4535 for wt in wt_lbs]#### Defining the height and weight lists:
ht = [5,5,4,7,6]
wt = [108, 120, 110, 98]#### Profiling the function using line_profiler
%lprun -f conversion conversion(ht,wt)---------------------------------------------------------------
#### Output
Total time: 1.46e-05 sFile: <ipython-input-13-41e195af43a9>Function: conversion at line 2Line # Hits Time Per Hit % Time Line Contents
==============================================================
2 1 105.0 105.0 71.9 ht_cms = [ht*100 for ht in ht_mtrs]
3 1 41.0 41.0 28.1 wt_kgs = [wt*.4535 for wt in wt_lbs]
Output Details:
- Complete time profile is done in units of 14.6 microseconds (refer to the first line of output)
The table generated, has 6 columns:
- Column 1 (Line #) — Line number of code (note that line # 1 is deliberately omitted from output as it was just the function definition statement)
- Column 2 (Hits) — Number of times the line was called
- Column 3 (Time) — Number of time units (each time unit is 14.6 micro seconds) spent on the line of code
- Column 4 (Per Hit)- Column 3 divided by Column 2
- Column 5 (%Time) — Of the total time spent, what % of time was spent on that particular line of code
- Column 6 (Content)- Content of the line of code
One can clearly notice that conversion of height from meter to centimetre has taken almost 72% of the total time spent.
Closing note
With the execution time of each line of code at our disposal, we can deploy strategies to make our code efficient. In our next 3 tutorials, we will share some best practices to help you make your codes efficient.
I hope this tutorial of Did you know series was informative and you learned something new.
Will try and bring more interesting topics in future tutorials. Till then:
HAPPY LEARNING! ! ! !