Profiling Python with cProfile when py-spy isn't an option
py-spy is wonderful and you should reach for it first. But sometimes
you can’t: the target runs in a restricted container, the kernel
won’t let py-spy attach with ptrace, or you’re profiling a
short-lived script where py-spy has no time to warm up. That’s
when cProfile is fine, actually.
python -m cProfile -o /tmp/run.prof your_script.py [args]
python -m pstats /tmp/run.prof
Inside the pstats shell:
% sort cumulative
% stats 30
The first 30 lines, sorted by cumulative time, tells you which
top-level call holds the wall clock. Then sort time and stats 30
again to see the leaves — the actual hot functions.
The default output is ugly. I pipe through snakeviz:
pip install snakeviz
snakeviz /tmp/run.prof
You get an interactive icicle graph in the browser, which is much
better at conveying “function X calls itself 4000 times under
Y” than the textual table.
One trap: cProfile’s overhead is ~10–30% in pure Python code and noticeably higher under heavy C-extension work. Don’t profile-then-tune in tight 5% loops — the act of measuring moves the bar.