profiling — Python profilers¶
Added in version 3.15.
Source code:Lib/profiling/
Introduction to profiling¶
Aprofile is a set of statistics that describes how often and for howlong various parts of a program execute. These statistics help identifyperformance bottlenecks and guide optimization efforts. Python provides twofundamentally different approaches to collecting this information: statisticalsampling and deterministic tracing.
Theprofiling package organizes Python’s built-in profiling tools undera single namespace. It contains two submodules, each implementing a differentprofiling methodology:
profiling.samplingA statistical profiler that periodically samples the call stack. Run scriptsdirectly or attach to running processes by PID. Provides multiple outputformats (flame graphs, heatmaps, Firefox Profiler), GIL analysis, GC tracking,and multiple profiling modes (wall-clock, CPU, GIL) with virtually no overhead.
profiling.tracingA deterministic profiler that traces every function call, return, andexception event. Provides exact call counts and precise timing information,capturing every invocation including very fast functions.
Note
The profiler modules are designed to provide an execution profile for agiven program, not for benchmarking purposes. For benchmarking, use thetimeit module, which provides reasonably accurate timingmeasurements. This distinction is particularly important when comparingPython code against C code: deterministic profilers introduce overhead forPython code but not for C-level functions, which can skew comparisons.
Choosing a profiler¶
For most performance analysis, use the statistical profiler(profiling.sampling). It has minimal overhead, works for both developmentand production, and provides rich visualization options including flamegraphs,heatmaps, GIL analysis, and more.
Use the deterministic profiler (profiling.tracing) when you needexactcall counts and cannot afford to miss any function calls. Since it instrumentsevery function call and return, it will capture even very fast functions thatcomplete between sampling intervals. The tradeoff is higher overhead.
The following table summarizes the key differences:
Feature | Statistical sampling( | Deterministic( |
|---|---|---|
Overhead | Virtually none | Moderate |
Accuracy | Statistical estimate | Exact call counts |
Output formats | pstats, flamegraph, heatmap,gecko, collapsed | pstats |
Profiling modes | Wall-clock, CPU, GIL | Wall-clock |
Special frames | GC, native (C extensions) | N/A |
Attach to PID | Yes | No |
When to use statistical sampling¶
The statistical profiler (profiling.sampling) is recommended for mostperformance analysis tasks. Use it the same way you would useprofiling.tracing:
python -m profiling.sampling run script.pyOne of the main strengths of the sampling profiler is its variety of outputformats. Beyond traditional pstats tables, it can generate interactiveflamegraphs that visualize call hierarchies, line-level source heatmaps thatshow exactly where time is spent in your code, and Firefox Profiler output fortimeline-based analysis.
The profiler also provides insight into Python interpreter behavior thatdeterministic profiling cannot capture. Use--modegil to identify GILcontention in multi-threaded code,--modecpu to measure actual CPU timeexcluding I/O waits, or inspect<GC> frames to understand garbage collectionoverhead. The--native option reveals time spent in C extensions, helpingdistinguish Python overhead from library performance.
For multi-threaded applications, the-a option samples all threadssimultaneously, showing how work is distributed. And for production debugging,theattach command connects to any running Python process by PID withoutrequiring a restart or code changes.
When to use deterministic tracing¶
The deterministic profiler (profiling.tracing) instruments every functioncall and return. This approach has higher overhead than sampling, but guaranteescomplete coverage of program execution.
The primary reason to choose deterministic tracing is when you need exact callcounts. Statistical profiling estimates frequency based on sampling, which mayundercount short-lived functions that complete between samples. If you need toverify that an optimization actually reduced the number of function calls, orif you want to trace the complete call graph to understand caller-calleerelationships, deterministic tracing is the right choice.
Deterministic tracing also excels at capturing functions that execute inmicroseconds. Such functions may not appear frequently enough in statisticalsamples, but deterministic tracing records every invocation regardless ofduration.
Quick start¶
This section provides the minimal steps needed to start profiling. For completedocumentation, see the dedicated pages for each profiler.
Statistical profiling¶
To profile a script, use theprofiling.sampling module with theruncommand:
python -m profiling.sampling run script.pypython -m profiling.sampling run -m mypackage.module
This runs the script under the profiler and prints a summary of where time wasspent. For an interactive flamegraph:
python -m profiling.sampling run --flamegraph script.pyTo profile an already-running process, use theattach command with theprocess ID:
python -m profiling.sampling attach 1234For custom settings, specify the sampling interval (in microseconds) andduration (in seconds):
python -m profiling.sampling run -i 50 -d 30 script.pyDeterministic profiling¶
To profile a script from the command line:
python -m profiling.tracing script.pyTo profile a piece of code programmatically:
importprofiling.tracingprofiling.tracing.run('my_function()')
This executes the given code under the profiler and prints a summary showingexact function call counts and timing.
Understanding profile output¶
Both profilers collect function-level statistics, though they present them indifferent formats. The sampling profiler offers multiple visualizations(flamegraphs, heatmaps, Firefox Profiler, pstats tables), while thedeterministic profiler produces pstats-compatible output. Regardless of format,the underlying concepts are the same.
Key profiling concepts:
- Direct time (also calledself time ortottime)
Time spent executing code in the function itself, excluding time spent infunctions it called. High direct time indicates the function containsexpensive operations.
- Cumulative time (also calledtotal time orcumtime)
Time spent in the function and all functions it called. This measures thetotal cost of calling a function, including its entire call subtree.
- Call count (also calledncalls orsamples)
How many times the function was called (deterministic) or sampled(statistical). In deterministic profiling, this is exact. In statisticalprofiling, it represents the number of times the function appeared in astack sample.
- Primitive calls
Calls that are not induced by recursion. When a function recurses, the totalcall count includes recursive invocations, but primitive calls counts onlythe initial entry. Displayed as
total/primitive(for example,3/1means three total calls, one primitive).- Caller/Callee relationships
Which functions called a given function (callers) and which functions itcalled (callees). Flamegraphs visualize this as nested rectangles; pstatscan display it via the
print_callers()andprint_callees()methods.
Legacy compatibility¶
For backward compatibility, thecProfile module remains available as analias toprofiling.tracing. Existing code usingimportcProfile willcontinue to work without modification in all future Python versions.
Deprecated since version 3.15:The pure Pythonprofile module is deprecated and will be removed inPython 3.17. Useprofiling.tracing (or its aliascProfile)instead. Seeprofile for migration guidance.
See also
profiling.samplingStatistical sampling profiler with flamegraphs, heatmaps, and GIL analysis.Recommended for most users.
profiling.tracingDeterministic tracing profiler for exact call counts.
pstatsStatistics analysis and formatting for profile data.
timeitModule for measuring execution time of small code snippets.
Submodules