SIGUSR1 live observer dump: ask a running process how it's progressing (fixes #660)#696
Merged
InauguralPhysicist merged 2 commits intoJul 22, 2026
Conversation
InauguralSystems#660) kill -USR1 <pid> prints one row per live binding to stderr at the next loop safepoint: name | value | when=<assigns> | entropy=<H> | dH=<dH> | trajectory The sigaction handler (SA_RESTART, installed by the CLI) only sets a volatile sig_atomic_t; the dump runs in normal thread context at the loop-cap per-iteration check (interpreter LOOP_STALL/CAP_CHECK cases + the shared eigs_loop_*_step cores the JIT/AOT call), so idle cost is one flag test — unmeasurable on bench_dmg_shape (166ms -> 163ms n=5 medians), so no EIGS_OBSERVE gate. First thread to see the flag dumps (atomic test-and-clear), covering module scope (root of the env chain) plus the dumping thread's live call frame; the module walk holds the existing InauguralSystems#607 g_module_env_lock under MT — no new locking scheme. Every row carries its assign count so a fresh per-call binding (when=1) reads differently from a settled one — the issue's silent-tolerance failure mode. env->assign_counts alone can't back that: the SET_LOCAL fast path never bumps it (the compiler only keeps it consistent for interrogated names), so the dump prints max(assign_counts, obs_age), which vm_park_call_env resets per call. Unobserved slots say "unobserved" rather than borrowing a window-less verdict. Test: tests/test_sigusr1_dump.sh (suite block [99d]) drives the signal against a live process — observable READY/DONE barriers, no sleeps — asserts the row shapes incl. when= counts single-threaded and with a spawned task, and requires DONE + exit 0 afterward. Suite: 3143/3143 release (baseline 3130/3130), 3147/3147 under make asan (ASan+UBSan+detect_leaks); freestanding-check green. Co-Authored-By: Kimi K3 <noreply@kimi.com>
…cation marker Addresses the CodeQL annotation on InauguralSystems#696; no behavior change. Round-trip check compares bit patterns (memcmp) — exact, -0.0-preserving. Co-Authored-By: Kimi K2.7 Code <noreply@kimi.com>
Contributor
Author
|
Addressed both CodeQL annotations in b991531 (src/vm.c only, no behavior change):
Suites re-run on the amended head: release |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #660 v1:
kill -USR1 <pid>on a running program prints one row per live binding to stderr at the next loop safepoint, then the program continues unchanged:Shape (per the issue's sketch)
sigaction,SA_RESTART); it ONLY sets avolatile sig_atomic_t— no allocation or I/O in the handler. Embedders viaeigs_embeddon't get it.LOOP_STALL_CHECK/LOOP_CAP_CHECKcases + the shared cores the JIT/AOT call), mirroring theeigs_loop_cap_stepcost profile. CAS test-and-clear → exactly one dump per signal under MT.__*bindings and builtins filtered; containers as<type:count>(dict-held config is invisible to the observer by design — issue Scope §2); strings capped. The dump path allocates nothing.g_module_env_lock; frame envs are the dumping thread's own view (the issue's allowed option). No new locking scheme.--observer-socket, periodic auto-report.One honest deviation:
when=ismax(assign_counts, obs_age)The issue says
Env.assign_countsbackswhen— verified on main, that's only half true: theSET_LOCALfast path never bumpsassign_counts(the compiler keepswhen is xcorrect only by forcing interrogated names onto the slow paths —interrogatedNameSet, compiler.c). A plain fn-local assigned 300k times readsassign_counts == 0, which would be exactly the "confident wrong answer" Scope §1 forbids.obs_ageIS bumped once per compiled assignment and resets per call env, so the dump merges both. Verified live: a parameter printswhen=1next toloss | ... | when=3214in the same frame.Requirements from the issue's "Done when"
when=1visibly distinct from settled bindings.bench_dmg_shape.eigsn=5 medians 166ms (main) → 163ms (branch), re-measured independently at 164 vs 163-164 interleaved — no measurable cost, so noEIGS_OBSERVEgate (issue: gate only "if it measures").tests/test_sigusr1_dump.sh(suite block [99d], 13 checks): drives a real SIGUSR1 against a live process, waits on observable READY/DONE markers (no sleeps), asserts row shapes incl.when=counts, single-threaded and with a spawned task. Mutation-verified: neutering the safepoint check fails 6 of its checks.Suites: release
3143/3143,make asan3147/3147, freestanding gate green.Pre-existing findings surfaced while in there (filed, not fixed here)
observer_slot_update_egrowsenv->obswith an unlocked realloc whileREPORT_NAMEreaders walk it.value_to_stringevaluates the(long long)cast before the range check (UB for |n| ≥ 2^63); the dump's own formatter orders it safely.Inherent bound worth stating: a program stuck in a long syscall or loop-free straight-line code only dumps at its next loop safepoint — that's the issue's safepoint design, not a gap. And
SIGUSR1no longer terminates eigenscript CLI processes (that's the feature).Generated by Claude Fable 5 (brief, review), Kimi K3 (implementation)