Skip to content

skill(libtmux-profiler): Tachyon profiling workflows for libtmux/tmuxp#663

Draft
tony wants to merge 2 commits intomasterfrom
2026-04-libtmux-profiler-skill
Draft

skill(libtmux-profiler): Tachyon profiling workflows for libtmux/tmuxp#663
tony wants to merge 2 commits intomasterfrom
2026-04-libtmux-profiler-skill

Conversation

@tony
Copy link
Copy Markdown
Member

@tony tony commented Apr 29, 2026

Summary

Adds a Claude Code skill at .claude/skills/libtmux-profiler/ that documents and automates Python 3.15's stdlib profiling.sampling (Tachyon) for libtmux/tmuxp work. Pure tooling addition — no runtime code changes, no public API impact.

What's in here

The skill itself

SKILL.md documents seven workflows for libtmux/tmuxp performance investigation:

  • pstats top-N — terminal-only summary of dominant wall-time consumers
  • Automated pstats diff — structured before/after comparison via the bundled diff-pstats.py helper (replaces Python 3.15.0a8's broken --diff-flamegraph)
  • Single-call microbenchmark — tight-loop per-call timing of one libtmux API
  • Heatmap — line-level attribution within a hot function
  • Live TUI — top(1)-style real-time profiler
  • Attach to a running pytest — diagnose hangs without restart
  • Sampling mode selection guide (wall / cpu / gil / exception)

reference/flamegraph-reading.md is a visual-signature cheat sheet for plain and diff flamegraphs.

Helper scripts

Each script in .claude/skills/libtmux-profiler/scripts/ solves a single discrete problem:

setup-tachyon-venv.sh — idempotent bootstrap that creates a .venv-3.15 venv with libtmux installed editable plus the testing dep group. Skips the dev group because watchfiles has no Rust wheel for 3.15a8 yet.

init-profile-session.sh — builds the per-session output directory at /tmp/py-profiling/<TS>/<project>/<branch>/<name>/ and writes a README with HEAD short-sha so the artifact set stays reconstructable after the branch moves.

bench-libtmux-call.py — tight-loop microbench against a real tmux server. Uses a registry-of-callables design (BENCH_TARGETS dict) so the script can never execute caller-supplied Python expressions. Built-in targets: has_session, list_sessions, list_windows, session_name, show_options, list_panes.

diff-pstats.py — markdown table of cumtime deltas between two .pstats files, sorted by abs(Δ) so the biggest movers surface first. Paste-ready for PRs, issues, or chat.

Toolchain bump

.tool-versions adds Python 3.15.0a8 alongside the existing 3.10-3.14. The project's pinned Python (3.14) is unchanged — 3.15 is only used by the skill's .venv-3.15 venv.

.gitignore overrides the global .claude/ ignore so this skill ships with the repo.

What this is not

  • No runtime code changes. Nothing in src/libtmux/ is touched.
  • No new dependencies. The venv is created on demand by the bootstrap script.
  • No CI changes. The skill is invoked manually by Claude Code agents working on the repo.

Verification

The skill is non-runtime, so verification is mostly "the bootstrap is idempotent and the helpers don't crash."

The setup script is idempotent — safe to re-run, skips work when the venv already exists:

$ bash .claude/skills/libtmux-profiler/scripts/setup-tachyon-venv.sh

Smoke-test the diff helper against any two .pstats files:

$ ./.venv-3.15/bin/python .claude/skills/libtmux-profiler/scripts/diff-pstats.py path/to/baseline.pstats path/to/current.pstats --top 10

Smoke-test the microbench against the default has_session target:

$ BENCH_ITERS=100 ./.venv-3.15/bin/python .claude/skills/libtmux-profiler/scripts/bench-libtmux-call.py

Test plan

  • Bootstrap runs cleanly on a fresh checkout (requires Python 3.15.0a8 via mise)
  • Each helper script runs without errors
  • pytest is unaffected — same 885 + 1 skipped as on master

tony added 2 commits April 28, 2026 20:08
why: Python 3.15 ships the new profiling.sampling stdlib module
("Tachyon"), a statistical sampling profiler that produces flamegraphs,
heatmaps, and Gecko-format call trees with zero target instrumentation.
It works on WSL where kernel perf is unavailable. We're using it to
profile libtmux's bench-engines path and identify lag sources outside
the engine layer (e.g. tmuxp's _wait_for_pane_ready loop).
what:
- .tool-versions: append 3.15.0a8 to the python line so `mise install`
  picks it up alongside the existing 3.10-3.14 matrix. The first entry
  (3.14) remains the default for project tooling; 3.15 is for ad-hoc
  profiling
…/skills/

why: Profiling investigations against libtmux/tmuxp historically required
ad-hoc cProfile invocations and manual flamegraph wrangling. Python 3.15's
new stdlib `profiling.sampling` module (Tachyon) ships everything needed
in-tree — flamegraphs, heatmaps, line-level attribution, pstats — but the
"how to use it on this codebase" knowledge isn't discoverable from the
module help. This skill is the institutional capital that makes Tachyon
trivially repeatable on libtmux/tmuxp work.
what:
- SKILL.md with workflows for: pstats top-N (terminal-only summary),
  automated pstats diff (before/after with the bundled diff-pstats.py
  helper, replaces the broken --diff-flamegraph alpha), single-call
  microbench (per-call timing of one libtmux API), heatmap (line-level
  attribution), live TUI (top(1)-style real-time profiler), attach to a
  running pytest (diagnose hangs without restart), sampling-mode
  selection guide, output-reading cheat sheet
- scripts/setup-tachyon-venv.sh: idempotent bootstrap that creates
  `.venv-3.15` with libtmux installed editable + the testing dep group
  (skips dev because watchfiles has no Rust wheel for 3.15a8 yet)
- scripts/init-profile-session.sh: builds the per-session output
  directory at /tmp/py-profiling/<TS>/<project>/<branch>/<name>/ and
  writes a README.md with HEAD short-sha so the artifact set stays
  reconstructable after the branch moves
- scripts/bench-libtmux-call.py: tight-loop microbench against a real
  tmux server using a registry-of-callables design (BENCH_TARGETS dict)
  so the script can never execute caller-supplied Python expressions.
  Targets: has_session, list_sessions, list_windows, session_name,
  show_options, list_panes
- scripts/diff-pstats.py: structured pstats arithmetic — loads two
  .pstats files, computes per-function cumtime deltas, prints a
  markdown table sorted by abs(delta) for paste-into-PR/issue use.
  Replaces Python 3.15.0a8's broken `--diff-flamegraph` until the
  upstream UnboundLocalError is fixed
- reference/flamegraph-reading.md: visual-signature cheat sheet for
  reading plain flamegraphs (sleep loops, fixture setup, dispatch
  chains) and diff flamegraphs (when 3.15 fixes the alpha bug)
- .gitignore: override the global `.claude/` ignore so this skill
  ships with the repo
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 46.58%. Comparing base (f0ca2d7) to head (b6b40f1).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #663   +/-   ##
=======================================
  Coverage   46.58%   46.58%           
=======================================
  Files          22       22           
  Lines        2372     2372           
  Branches      390      390           
=======================================
  Hits         1105     1105           
  Misses       1098     1098           
  Partials      169      169           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant