Skip to main content

sgrud

Attach to a running CPython process and watch its memory, CPU, threads, asyncio tasks, stacks and garbage collector without slowing it down.

sgrud never stops or instruments the target. It reads the interpreter's state straight out of process memory through CPython 3.15's _remote_debugging module (the same machinery behind the Tachyon sampling profiler and python -m asyncio ps) and pairs it with /proc for memory and CPU accounting. A full snapshot of stacks for every thread costs tens of microseconds on the sgrud side and nothing on the target side.

Requires Linux and CPython 3.15 or newer. The target must run the same major.minor version as sgrud itself.

Usage

sgrud PID                      one text snapshot
sgrud PID -n 0.5               keep printing every 0.5 s until the target exits
sgrud PID --json               one JSON object per line, easy to pipe elsewhere
sgrud run -- python app.py     start the target as a child and inspect it
sgrud tui PID                  interactive terminal interface
sgrud tui run -- python app.py

--no-stacks, --no-tasks and --no-gc drop sections you do not need.

sgrud PID --profile 5            sample stacks for 5 s, print the hottest functions
sgrud PID --profile 5 --mode gil count only the thread holding the GIL

Keys inside the TUI: 1-5 switch tabs, space pauses, r refreshes, + and - change the refresh interval, q quits. On the Hotspots tab s toggles self/total ordering, m toggles wall/gil mode and c clears the samples. The tab is fed by a background sampler (--rate, default 100 Hz) that keeps running while you look at the other tabs.

In wall mode every thread with a Python stack counts, so a sleeping thread weighs as much as a busy one. In gil mode only the GIL holder counts, which answers "where does the CPU time go" for CPython code.

Library

The TUI is only a front end. Everything comes from Monitor, which returns plain frozen dataclasses:

from sgrud import Monitor

with Monitor.attach(pid) as m:          # or Monitor.spawn(["python", "app.py"])
    snap = m.snapshot()                  # snapshot(stacks=..., tasks=..., gc=...)
    print(snap.process.memory.rss, snap.process.cpu_percent)
    for t in snap.threads:
        print(t.tid, t.name, t.status.describe(), t.cpu_percent, t.frames[:1])
    for task in snap.tasks:
        print(task.name, task.parent_ids, [f.funcname for f in task.frames])
    print(snap.gc[0].collections, snap.gc[0].history[:1])
    print(snap.to_dict())                # JSON friendly

Monitor.stream(interval) yields snapshots until the target exits, at which point it raises ProcessExited. CPU percentages need two snapshots, so the first one reports None.

For profiling, Sampler runs Monitor.sample_stacks() in a background thread and feeds a Hotspots aggregator:

from sgrud.sampler import Sampler

with Sampler(monitor, rate=500, mode="gil") as sampler:
    time.sleep(5)
for row in sampler.hotspots.rows(sort="self", limit=10):
    print(row.self_percent, row.funcname, row.filename)

Permissions

Memory, CPU, thread names and per-thread CPU come from /proc and work for any process you own. Stacks, GIL state, asyncio tasks, GC statistics and hotspots need to read the target's memory, which needs ptrace rights. With the default kernel.yama.ptrace_scope=1 that is only granted for child processes.

Without those rights sgrud still attaches in limited mode and shows what it can, with a banner explaining what is missing. To get everything, either start the target through sgrud run -- ..., run sgrud with sudo, grant CAP_SYS_PTRACE, or relax Yama for the session:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

Pass require_full=True to Monitor.attach to fail instead of degrading.

A target started with -X disable-remote-debug can still be inspected. That flag only disables code injection, which sgrud does not use.

Development

uv sync
uv run pytest

The tests spawn tests/target_app.py and inspect it, so they exercise the real attach path. The Textual app is tested headlessly through its pilot.

Metadata

Release files for sgrud 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sgrud 0.1.0
File Size Uploaded
sgrud-0.1.0.tar.gz 44.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sgrud 0.1.0
File Interpreter ABI Platform
sgrud-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 74.5 kB

Release files / sgrud-0.1.0.tar.gz

Download URL sgrud-0.1.0.tar.gz
Size 44.1 kB
Tags Source
SHA-256 checksum
How to use checksums
bad757dd098cf7cb06ab5414dfeb653f83a32bade8b2f25c570b633ca543fad3
BLAKE2b-256 checksum
How to use checksums
f7cd5c3d040f6bc4084b942b4b47ea64ff02bd536ce62f872dc3822ac2f060b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":null,"id":"forky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / sgrud-0.1.0-py3-none-any.whl

Download URL sgrud-0.1.0-py3-none-any.whl
Size 30.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a369c60efc0c4bea8b6bd1f219f71e8b9cda6e07d217f2bffdfbc3a34519b710
BLAKE2b-256 checksum
How to use checksums
b7488c2f58c0df3061c397da68f8527f0e85ca9f2448c834b9c18774ad65bb50
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":null,"id":"forky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page