Notes & Tools

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.