CPU Profiling with `cProfile`
`cProfile` is Python’s built-in deterministic profiler for collecting function call counts and timing statistics. Use it on representative workloads to identify costly call paths, then validate any optimization with separate measurements.
`cProfile` is Python’s built-in deterministic profiler. It observes function calls and returns while the program runs, collecting call counts and timing statistics. It is useful for locating CPU-intensive paths, but profiling adds overhead, so measured durations are not identical to unprofiled production latency.
A typical workflow is to profile a representative workload, save or inspect the statistics, and sort them by a useful measure. Cumulative time highlights functions whose own work plus callees’ work accounts for substantial elapsed time; total (self) time excludes time spent in callees. Call counts can reveal unexpectedly repeated work.
Use `python -m cProfile -o profile.out your_script.py` to write profile data, then inspect it with `pstats` or a compatible visualization tool. For a long-running service, profile a bounded, representative operation rather than assuming that startup behavior reflects request handling.
Profiling results are evidence for where to investigate, not a diagnosis by themselves. High cumulative time may come from a function calling expensive dependencies, while high self time suggests work attributed directly to that function. Consider workload variation, profiler overhead, and whether time is spent waiting on I/O before deciding on an optimization.
Key points
- Use `cProfile` to collect function call counts and timing statistics during execution.
- Sort by cumulative time to find costly call paths, and by self time to find functions doing substantial direct work.
- Profile representative inputs; profiling overhead and workload differences affect measurements.
- Treat profile output as a lead for investigation, then validate optimizations with repeatable measurements.
Interview questions
What is `cProfile`, and how would you use it to investigate a slow Python program?
`cProfile` records function calls and timing statistics during execution, making it useful for finding expensive call paths and excessive repetition. I would run it against a representative workload, then sort the results by cumulative time or self time depending on the question. The output narrows down where to investigate; it does not by itself explain why code is slow. I would validate a proposed change with an appropriate benchmark.
How do self time and cumulative time differ in profiler output?
Self time, also called total time in common profiler reports, is attributed to the function itself and excludes its callees. Cumulative time includes time attributed to the function and its subcalls. A function with high cumulative time may be an important entry point into a slow path without doing much work itself. I would inspect its callers and callees before deciding where to optimize.
How would you profile a Python service safely and turn the results into an optimization?
I would define a representative request or task, collect a bounded profile under realistic inputs, and avoid treating profiler timings as production latency measurements. I would inspect call counts and both self and cumulative time, then correlate findings with service-level metrics and workload characteristics. After changing code, I would compare behavior with a repeatable benchmark or controlled load test. For latency dominated by waiting, I would use tools suited to I/O and concurrency analysis as well as CPU profiling.
How can you collect and inspect a `cProfile` profile?
The command `python -m cProfile -o profile.out app.py` profiles a script and saves data for later inspection. The `pstats` module can load that file and sort or print statistics, while `cProfile.Profile` can be used in code to profile a selected call. For a service, I would instrument a bounded operation or workload rather than profile indefinitely. The chosen method depends on whether I need a whole-program view or a focused measurement.