line_profiler
line_profiler
is a Python package for line-level profiling. It is a command-line profiler, that can also be used within Jupyter Notebooks. Functions marked with the @profile
decorator are profiled when line_profiler
is enabled during execution.
QuickStart
1. line_profiler
can be installed via pip
or conda
.
# install via pip (may not work on MacOS)
pip install line_profiler[all]
# or
# install via conda
conda install conda-forge::line_profiler
2. Functions to be profiler should be marked with the @profile
decorator.
# Import the @profile decorator
from line_profiler import profile
# Import sys for runtime arguments
import sys
# Attach the decorator to the functions to be profiled
@profile
def is_prime(number):
if number < 2:
return False
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
return False
return True
print(is_prime(int(sys.argv[1])))
3. Run the Python code via line_profiler
.
If you would normally execute your script as
python my_script.py 1087
You can call line_profiler
with the below, including any required runtime arguments as normal.
python -m kernprof -lvr my_script.py 1087
Interpreting Output
At exit, a table will be printed to the command-line for the profiling results of each targeted function.
If running this in a terminal, you should see rich output with highlight colours.
Wrote profile results to my_script.py.lprof
Timer unit: 1e-06 s
Total time: 1.65e-05 s
File: my_script.py
Function: is_prime at line 3
Line # Hits Time Per Hit % Time Line Contents
==============================================================
3 @profile
4 def is_prime(number):
5 1 0.4 0.4 2.4 if number < 2:
6 return False
7 32 8.4 0.3 50.9 for i in range(2, int(number**0.5) + 1):
8 31 7.4 0.2 44.8 if number % i == 0:
9 return False
10 1 0.3 0.3 1.8 return True
The columns have the following definitions:
Column | Definition |
---|---|
Line # |
The line number of the relevant line within the file (specified above the table). |
Hits |
The total number of times the line was executed. |
Time |
The total time spent executing that line, including child function calls. |
Per Hit |
The average time per call, including child function calls (Time /Hits ). |
% Time |
The time spent executing the line, including child function calls, relative to the other lines of the function. |
Line Contents |
A copy of the line from the file. |
Jupyter Notebooks
If you’re more familiar with writing Python inside Jupyter notebooks you can use line_profiler
directly from inside notebooks. However it is still necessary for the code you wish to profile to be placed within a function.
First line_profiler
must be installed and it’s extension loaded.
!pip install line_profiler
%load_ext line_profiler
Following this, you call line_profiler
with %lprun
.
%lprun -f profiled_function_name entry_function_call()
The functions to be line profiled are specified with -f <function name>
, this is repeated for each individual function that you would otherwise apply the @profile
decorator to.
This is followed by calling the function which runs the full code to be profiled.
For the above is_prime example it would be:
%lprun -f is_prime is_prime(1087)
This will then create an output cell with any output from the profiled code, followed by the standard output from line_profiler
. It is not currently possible to get the rich/coloured output from line_profiler
within notebooks.
Limitations
line_profiler
does not support line profiling a whole Python application, if your Python code to be profiled exists in the root of a Python file, you will need to move it inside a function prior to profiling.
As a deterministic profiler, rather than a sampling profiler, it captures data about every executed line. Therefore, it can lead to the profiling execution being significantly slower if profiling large functions due to the overhead of data collection.