pyinstrument

Statistical sampling CPU profiler for Python — measures where time is spent with low overhead and human-readable output. pyinstrument features: pyinstrument script.py for CLI, Profiler() context manager, profiler.start()/stop(), profiler.output_text() for terminal output, profiler.output_html() for interactive HTML flamegraph, profiler.open_in_browser() for immediate visualization, interval parameter for sampling rate (default 0.001s), async_mode for asyncio profiling, @profile decorator, pyinstrument.render_as_html(), and pytest plugin (pytest-pyinstrument). Output shows call tree with time percentages — immediately identifies bottlenecks.

Evaluated Mar 06, 2026 (0d ago) v4.x
Homepage ↗ Repo ↗ Developer Tools python pyinstrument profiler performance sampling flamegraph html
⚙ Agent Friendliness
69
/ 100
Can an agent use this?
🔒 Security
90
/ 100
Is it safe for agents?
⚡ Reliability
86
/ 100
Does it work consistently?

Score Breakdown

⚙ Agent Friendliness

MCP Quality
--
Documentation
88
Error Messages
85
Auth Simplicity
99
Rate Limits
99

🔒 Security

TLS Enforcement
92
Auth Strength
92
Scope Granularity
90
Dep. Hygiene
90
Secret Handling
85

Local profiling library with no network calls. Profile output (HTML/text) contains function names and file paths — may expose code structure. Treat profile output files as sensitive internal documentation. open_in_browser() creates temporary HTML file in OS temp directory — clean up after profiling sessions in shared environments.

⚡ Reliability

Uptime/SLA
88
Version Stability
85
Breaking Changes
85
Error Recovery
88
AF Security Reliability

Best When

Quick, readable CPU profiling of Python agent code during development — pyinstrument's HTML output is the most developer-friendly way to identify bottlenecks in complex call trees.

Avoid When

You need zero-overhead production profiling (use py-spy), memory profiling (use memray), or line-level attribution (use line_profiler).

Use Cases

  • Agent quick profiling — from pyinstrument import Profiler; profiler = Profiler(); profiler.start(); agent_function(); profiler.stop(); profiler.print() — profile specific code section; agent developer sees call tree with time percentages in terminal; slower than py-spy for production but more accessible from Python code
  • Agent HTML flamegraph — profiler = Profiler(); with profiler: run_agent_pipeline(); profiler.open_in_browser() — opens interactive flamegraph in browser; agent developer clicks through call tree; wider bars = more time; shows percentage of parent time at each level; cleaner output than cProfile for complex call trees
  • Agent async profiling — profiler = Profiler(async_mode='enabled'); async def main(): with profiler: await run_async_agent(); print(profiler.output_text()) — async_mode traces asyncio coroutines correctly; agent async code profiling shows both CPU time and async wait time; distinguishes 'running' from 'waiting for I/O'
  • Agent pytest integration — # pyproject.toml: [tool.pytest.ini_options]; addopts = '--pyinstrument'; # any slow test shows profiling output — pytest-pyinstrument shows profiler output for each test; agent slow tests identified automatically; --profile-svg generates flamegraph SVG for CI artifact
  • Agent context manager profiling — with Profiler() as profiler: expensive_preprocessing(); intermediate_result = transform(data); final = postprocess(intermediate_result); print(profiler.output_text(show_all=True)) — profile entire pipeline block; show_all=True shows all frames including library code; agent developer sees full call stack including library overhead

Not For

  • Production always-on profiling — pyinstrument overhead (1-10%) too high for always-on; use py-spy --pid for zero-overhead production profiling of running processes
  • Memory profiling — pyinstrument is CPU time only; use memray for memory allocation profiling
  • Line-level profiling — pyinstrument shows function-level time; for line-by-line profiling use line_profiler

Interface

REST API
No
GraphQL
No
gRPC
No
MCP Server
No
SDK
Yes
Webhooks
No

Authentication

Methods: none
OAuth: No Scopes: No

No auth — local profiling library.

Pricing

Model: open_source
Free tier: Yes
Requires CC: No

pyinstrument is BSD licensed. Free for all use.

Agent Metadata

Pagination
none
Idempotent
Full
Retry Guidance
Not documented

Known Gotchas

  • Statistical profiling misses short functions — pyinstrument samples every 1ms by default; functions completing in <1ms may not appear in profile; agent code with many fast utility functions shows them as 0% even if called 1M times; use interval=0.0001 for finer resolution at cost of higher overhead; or use cProfile/viztracer for deterministic profiling
  • open_in_browser() fails in headless CI — profiler.open_in_browser() tries to open browser via webbrowser module; CI/CD systems without display raise OSError or silently fail; agent CI profiling must use: with open('profile.html', 'w') as f: f.write(profiler.output_html()); or output_text() for CI-friendly terminal output
  • async_mode must be set at Profiler() creation — Profiler(async_mode='enabled') must be set at creation; cannot enable async mode after creation; agent async profiling must use context manager with async_mode set: async with Profiler(async_mode='enabled') as profiler: await agent_code(); without async_mode, async gaps show as idle time not as 'awaiting coroutine'
  • profiler.print() vs profiler.output_text() — profiler.print() is shorthand for print(profiler.output_text()); profiler.output_text() returns string; agent code saving profile to log must use output_text() not print(); profiler.output_html() returns full HTML string for file saving
  • interval=0.001 means functions < 1ms not profiled — agent code with hot utility functions (string formatting, dict lookups) not visible at default interval; these microsecond functions may be called millions of times; pyinstrument shows what consumes the most wallclock time, not call count; use line_profiler for per-call counting
  • Profiler() resets on __enter__ in context manager — using same Profiler instance twice as context manager: with profiler: fn1(); with profiler: fn2() — second with resets profiler data; agent code profiling multiple sections accumulates data only in last section; use separate Profiler() instances or profiler.start()/stop() to accumulate across sections

Alternatives

Full Evaluation Report

Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for pyinstrument.

$99

Scores are editorial opinions as of 2026-03-06.

5208
Packages Evaluated
26151
Need Evaluation
173
Need Re-evaluation
Community Powered