Skip to content

Changelog

All notable changes between releases land here. Format roughly follows Keep a Changelog; entries are grouped under Added / Changed / Fixed / Removed.

Unreleased

Added

  • Profiler is public API. The measurement engine — previously the internal _MonitoringProfiler — is now exported as Profiler and documented. Use it directly with start() / stop(), as a context manager (with Profiler() as p:), or via the new print_stats() convenience method.
  • Targeted profiling from Python. profit(targets=[fn, ...]) restricts measurement to the functions you name, mirroring the CLI's -p.
  • Documentation site built with Zensical and published on Read the Docs: a task guide per use case, CLI and Python API references, a Reading the output page, and terminal screenshots generated with shotty.

Changed

  • profit is now a factory. profit() returns a Profiler, replacing the old with profit as p: context-manager form. The @profit decorator is unchanged. (breaking)
  • profit run hides its own runpy launcher frames. The <frozen runpy> wrappers profit uses to execute your script no longer clutter the table, the same way it already omits its own profiler frames. Your script's actual imports are still shown — those are real startup cost, not harness.
  • Targeted runs ignore unrelated callables. When you profile specific functions, profit no longer tracks everything else, cutting overhead and noise.

Fixed

  • Cumulative time inflated by recursion. A recursive or otherwise re-entrant function's wall time was added once per stack frame, so its Total could come out many times larger than the whole script's runtime. Cumulative time is now counted once per top-level call.
  • Thread safety. Call stacks are now per-thread, so profiling code that spawns threads no longer mixes up timings and call counts.
  • Exception timing. Functions that raise are now timed correctly — measurement uses sys.monitoring's PY_UNWIND event instead of RAISE, so timing isn't cut off at the raise point.

0.1.0 — 2026-05-01

Initial release.

Added

  • sys.monitoring-based profiler (Python 3.12+) that tracks both Python functions and C-extension calls, measuring cumulative wall time with low overhead.
  • profit run to profile a script or module: -p to focus on specific functions, -b to compare against a baseline (adding a Delta column), and --sort / --limit to shape the table.
  • profit timeit to profile a statement run in a loop, with --setup and an automatic or fixed (-n) iteration count.
  • Per-call statistics — calls, mean ± σ, min, max, total — with primitive-vs- recursive call counts shown as N/P in the Calls column.
  • @profit decorator and profit context manager for profiling directly from Python.