Tips¶
cProfile
(implemented in C) is preferred overprofile
(implemented in Python).The profiler modules (
cProfile
andprofile
) and tools based on them (e.g.,%prun
and%%prun
for notebook) are designed to provide an execution profile for a given program, not for benchmarking purposes (for that, there istime
andtimeit
for reasonably accurate results). This particularly applies to benchmarking Python code against C code: the profilers introduce overhead for Python code, but not for C-level functions, and so the C code would seem faster than any Python one. Overall, the profiler modules and tools based on them (e.g.,%prun
and%%prun
for notebooks) might slow down your Python code up to 3 times.
time.time_ns¶
You can use time.time_ns
(since Python 3.7+) to get the current system time in nanoseconds.
This can be used to measuree the performance of Python code.
import time
import math
begin_time = time.time_ns()
for i in range(10000):
math.sqrt(i)
end_time = time.time_ns()
print("Time used:", (end_time - begin_time) / 1e9, "seconds")
timeit.timeit¶
Notice that timeit.timeit
runs a statement 1 million times to benchmark it by default.
This iss probably not what you want most of the time
especially when you have a long running task to benchmark.
Do NOT forget to set the number
parameter to an appropriate value
when you call timeit.timeit
.
import timeit
import time
import math
def sqrts():
for i in range(10_000):
math.sqrt(i)
timeit.timeit(sqrts, timer=time.perf_counter_ns, number=1) / 1e9
cProfile.run¶
This function takes a single argument that can be passed to the exec() function, and an optional file name. In all cases this routine executes:
exec(command, main.dict, main.dict) and gathers profiling statistics from the execution. If no file name is present, then this function automatically creates a Stats instance and prints a simple profiling report. If the sort value is specified, it is passed to this Stats instance to control how the results are sorted.
import cProfile
import re
cProfile.run('re.compile("foo|bar")')
ncalls for the number of calls.
tottime for the total time spent in the given function (and excluding time made in calls to sub-functions)
percall is the quotient of tottime divided by ncalls
cumtime is the cumulative time spent in this and all subfunctions (from invocation till exit). This figure is accurate even for recursive functions.
percall is the quotient of cumtime divided by primitive calls
filename:lineno(function) provides the respective data of each function
When there are two numbers in the first column (for example 3/1), it means that the function recursed. The second value is the number of primitive calls and the former is the total number of calls. Note that when the function does not recurse, these two values are the same, and only the single figure is printed.
Instead of printing the output at the end of the profile run, you can save the results to a file by specifying a filename to the run() function:
import cProfile
import re
cProfile.run('re.compile("foo|bar")', "restats")
!cat restats
The pstats.Stats class reads profile results from a file and formats them in various ways.
import pstats
pstats.Stats("restats").print_stats()
cProfile in Command-line¶
The file cProfile can also be invoked as a script to profile another script. For example:
!python3 -m cProfile -h
py-spy¶
py-spy is a sampling profiler for Python programs. It lets you visualize what your Python program is spending time on without restarting the program or modifying the code in any way. py-spy is extremely low overhead: it is written in Rust for speed and doesn't run in the same process as the profiled Python program. This means py-spy is safe to use against production Python code.
SnakeViz¶
Installation¶
!pip3 install snakeviz
!~/.local/bin/snakeviz -h
Tuna¶
Tuna is a very similar tool to SnakeViz but not as good as SnakeViz.
pyperformance¶
The pyperformance project is intended to be an authoritative source of benchmarks for all Python implementations. The focus is on real-world benchmarks, rather than synthetic benchmarks, using whole applications when possible.
Profiling Importing Time¶
https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPROFILEIMPORTTIME
python3 -X importtime your_code.py
References¶
Python Profiler for JupyterLab Notebooks
https://docs.python.org/3/library/time.html#module-time
https://vstinner.github.io/python37-pep-564-nanoseconds.html
Python Debugging and Profiling
How can you profile a Python script?
https://docs.python.org/3.7/library/profile.html
https://docs.python.org/3.7/library/profile.html#pstats.Stats
https://github.com/jiffyclub/snakeviz
https://jiffyclub.github.io/snakeviz/
https://julien.danjou.info/guide-to-python-profiling-cprofile-concrete-case-carbonara/
https://www.integralist.co.uk/posts/profiling-python/