skills: start the daemon in the samply and drive.sh harnesses #413

Merged
natsukium merged 3 commits from skills/samply-systemd into main 2026-09-25 05:18:20 +09:00
Owner

Closes #394.

On a systemd desktop the client's autospawn hands the daemon to systemd-run --user, so samply-profile.sh (samply launch mode on the client) never saw the daemon, and drive.sh never got the daemon's log lines. Both harnesses now start felis-daemon serve --socket $SOCK themselves: under samply for the profile, with stderr in $LOG for drive.sh. They wait for the bind (and confirm the daemon is still alive) before pointing the client at that socket, with SHELL set on the client, since the session shell comes from the client's environment.

Other changes in the same scripts:

  • samply-profile.sh reports a profile only if a kitten __benchmark__ run completed in the window, samply exited 0, and the output passes gzip -t. Otherwise it exits 1 and shows the client or samply log.
  • Both scripts launch the daemon with NOTIFY_SOCKET unset. An inherited one makes serve exit right after its bind when the readiness send fails.
  • On exit the client is stopped and waited for before the daemon, so a reconnect cannot autospawn a replacement outside samply or outside the log. samply itself is killed if it is still running after an early exit.
  • The SKILL.md passages describe the new launch.

Verification (Linux, niri)

  • drive.sh end to end with a Kitty graphics escape: the log holds both the daemon's (listening, dispatch_apc_bodies) and the client's (image header) lines; only the run's own daemon is killed; the user's daemon is untouched. Also passes with a stale NOTIFY_SOCKET exported, and fails cleanly (exit 1, no leftover process) with a daemon binary that never binds.
  • samply-profile.sh: real samply cannot run on this host (perf_event_paranoid = 2, no sudo), so the launch plumbing was run with a stand-in samply on PATH that runs the command after -- and writes the output when the child exits. Results:
    • the daemon is the profiler's child and accrues CPU under kitten __benchmark__;
    • daemon stop --force ends it and the profile is written;
    • a missing kitten gives exit 1 and no output;
    • a failing samply gives exit 1;
    • a samply that never launches the daemon leaves no process behind;
    • a TMPDIR containing a space works;
    • the felis-daemon count after a run is back to its pre-run value.
  • The same launch shape with perf record in place of samply (user-mode cycles:u with LBR stacks) produced the daemon profiles posted on #399.

Still to check on a host with perf_event_paranoid <= 1: one real samply run.

Review

pi sol review rounds: 1 BLOCKED (3 findings), 2 BLOCKED (3), 3 BLOCKED (2), 4 BLOCKED (1), 5 PASS. Every finding was verified and fixed; none were rejected.

Closes #394. On a systemd desktop the client's autospawn hands the daemon to `systemd-run --user`, so `samply-profile.sh` (samply launch mode on the client) never saw the daemon, and `drive.sh` never got the daemon's log lines. Both harnesses now start `felis-daemon serve --socket $SOCK` themselves: under samply for the profile, with stderr in `$LOG` for drive.sh. They wait for the bind (and confirm the daemon is still alive) before pointing the client at that socket, with `SHELL` set on the client, since the session shell comes from the client's environment. Other changes in the same scripts: - `samply-profile.sh` reports a profile only if a `kitten __benchmark__` run completed in the window, samply exited 0, and the output passes `gzip -t`. Otherwise it exits 1 and shows the client or samply log. - Both scripts launch the daemon with `NOTIFY_SOCKET` unset. An inherited one makes `serve` exit right after its bind when the readiness send fails. - On exit the client is stopped and waited for before the daemon, so a reconnect cannot autospawn a replacement outside samply or outside the log. samply itself is killed if it is still running after an early exit. - The SKILL.md passages describe the new launch. ## Verification (Linux, niri) - `drive.sh` end to end with a Kitty graphics escape: the log holds both the daemon's (`listening`, `dispatch_apc_bodies`) and the client's (`image header`) lines; only the run's own daemon is killed; the user's daemon is untouched. Also passes with a stale `NOTIFY_SOCKET` exported, and fails cleanly (exit 1, no leftover process) with a daemon binary that never binds. - `samply-profile.sh`: real samply cannot run on this host (`perf_event_paranoid` = 2, no sudo), so the launch plumbing was run with a stand-in `samply` on `PATH` that runs the command after `--` and writes the output when the child exits. Results: - the daemon is the profiler's child and accrues CPU under `kitten __benchmark__`; - `daemon stop --force` ends it and the profile is written; - a missing kitten gives exit 1 and no output; - a failing samply gives exit 1; - a samply that never launches the daemon leaves no process behind; - a `TMPDIR` containing a space works; - the felis-daemon count after a run is back to its pre-run value. - The same launch shape with `perf record` in place of samply (user-mode `cycles:u` with LBR stacks) produced the daemon profiles posted on #399. Still to check on a host with `perf_event_paranoid <= 1`: one real samply run. ## Review pi sol review rounds: 1 BLOCKED (3 findings), 2 BLOCKED (3), 3 BLOCKED (2), 4 BLOCKED (1), 5 **PASS**. Every finding was verified and fixed; none were rejected.
skills: start the daemon in the samply and drive.sh harnesses
All checks were successful
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 4s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m4s
pr / nix flake check (pull_request) Successful in 27s
pr / wire schema is compatible with the base (pull_request) Successful in 12s
bench / Criterion regression gate (pull_request) Successful in 2m15s
darwin / build felis (aarch64-darwin) (pull_request) Successful in 53s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m36s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 1m18s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 4s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 12s
windows / cargo nextest (Windows) (pull_request) Successful in 3m39s
windows / frontend smoke (Windows) (pull_request) Successful in 1m27s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
f75fca3b57
On a systemd desktop the client's autospawn hands the daemon to
`systemd-run --user`, so it runs in a transient unit rather than as the
client's child. samply's launch mode, run on the client, then never
sees the daemon, and drive.sh never received the daemon's log lines:
an autospawned daemon's stderr is /dev/null, or the journal once the
user manager takes it.

Both harnesses now start `felis-daemon serve --socket` themselves
(under samply for the profile, with stderr in $LOG for drive.sh), wait
for the socket so the client cannot autospawn a second daemon, and
point the client at it with SHELL set on the client, since the session
shell comes from the client's environment. Attaching samply to the
hand-off daemon instead is not an option: attach mode fails on the
perf_event_mlock_kb limit.

samply-profile.sh reports a profile only when a benchmark run
completed in the window and samply exited cleanly with a readable
file, since a client that failed to open its session, or a missing
kitten, would otherwise leave an idle daemon's profile that reads as a
valid one. Both scripts start the daemon without NOTIFY_SOCKET: an
inherited one makes serve exit right after its bind when the readiness
send fails, which the socket wait alone would not notice.

On the way out the client is stopped before the daemon: a client that
outlives its daemon reconnects, and the reconnect autospawns a
replacement on the same socket, outside samply and outside the log.

Assisted-by: Claude Code
main now starts felis-daemon from drive.sh itself and documents the
systemd-run hand-off in both skills. This resolution keeps main's
FELIS_DAEMON_BIN and prose, and adds only what the branch still
contributes: samply-profile.sh launching the daemon under samply, and
drive.sh's NOTIFY_SOCKET clearing, readiness check, and client-first
cleanup. samply-profile.sh adopts main's FELIS_DAEMON_BIN name so the
two harnesses take the same variable.

Assisted-by: Claude Code
skills: pair samply-profile.sh's daemon with the client build
All checks were successful
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Successful in 2m18s
darwin / detect relevant changes (pull_request) Successful in 4s
pr / wire schema is compatible with the base (pull_request) Successful in 12s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 1m33s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 3s
windows / frontend smoke (Windows) (pull_request) Successful in 1m38s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 54s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m18s
pr / nix flake check (pull_request) Successful in 31s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m57s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 12s
windows / cargo nextest (Windows) (pull_request) Successful in 3m59s
8d1218b2a7
With a fixed ./target/release default, pointing FELIS_BIN at a debug or
experimental build still profiled the release daemon, and the script
reported a valid profile of a build nobody asked for. Taking the
client's sibling keeps the pair from one build unless FELIS_DAEMON_BIN
says otherwise.

Assisted-by: Claude Code
natsukium deleted branch skills/samply-systemd 2026-09-25 05:18:20 +09:00
Commenting is not possible because the repository is archived.
No description provided.