feat(scheduler-sim-decision-trace): hook the allocator loop

Task 3.1: when the sim publishes trace settings, sched_allocator() counts
job positions, starts a record for wanted jobs with their selection and
cluster-wide limits, pushes no-decision kinds as trace-only decisions,
and attaches the captured outcome to built decisions; every handoff
clears core->trace_rec. Live (trace_ctl NULL) is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-08 11:10:28 +00:00
parent 144a01982e
commit ed7b889bb7
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
4 changed files with 617 additions and 1 deletions

View file

@ -124,7 +124,7 @@
- _Depends: 2.3_
- [ ] 3. Allocator-thread hooks at the decision seams
- [ ] 3.1 Hook the allocator loop: position, record lifecycle, selection and no-decision paths (P)
- [x] 3.1 Hook the allocator loop: position, record lifecycle, selection and no-decision paths (P)
- **Position:** when session settings are present, every real job pop increments it.
- **Record start:** a wanted job starts a record with its selection facts; its cluster-wide limits are added after election.
- **No-decision paths:**
@ -360,3 +360,4 @@
- 2.2 OPEN for 6.2: if `limit_row()` runs out of memory, `sched_trace_check_rows` returns early, so that row's LIMIT bit and later rows' SHORTFALL bits are lost. The verdict derived from rows then becomes SELECT and the Req 9.3 counts are off. This needs fault injection to test, so fix it in 6.2: keep setting the verdict bits and continue.
- 2.3: the outcome capture functions are `sched_trace_capture_dispatch`, `sched_trace_capture_pend` and `sched_trace_rec_reconstructed`, declared in trace.h; 3.x and 5.3 call them. Limit charges are classified by the limit flag or a `limit=` prefix and resolved via glimits (shared) or the worker's hlimits (host, worker looked up by host name). An unresolved charge has `limited_res == NULL`, which is the raw-number fallback. Shared pend entries carry host "" and are treated as host-less. For 4.1: limit totals over omitted hosts have a scope without the host, and a NULL host name yields the scope "h=". Follow-up (low): capture's `key_find`/`vget` on resmgr/workers run without the RTTI read lock that `sched_get_worker` takes. That is safe while the sim runs in lock-step; the 2.4 split may wrap them.
- 2.4: the trace sources are now sched_trace.c (record, arena, entries, budget, requirement/plan/check), sched_trace_scan.c (positions, host verdicts/rows, tallies, rollback, commit, search end), sched_trace_capture.c, sched_trace_outcome.c (dispatch, pend, reconstructed) and sched_trace_internal.h (12 shared `sti_` helpers). Every target that compiles one trace .c file needs all four. Later tasks that extend the trace must keep each file under 800 lines and add new files to the core isolation scan.
- 3.1: allocator-loop hooks live in `sched_allocator()` (sched_election.c), with helpers `sched_trace_push_no_decision()` and `sched_trace_attach()`. Selection is captured at job lookup, before election, so NO_SCHEDOBJ still has its selection; cluster-wide limits are captured after election. The position counter (`ctl->position`) is not SCHED_TRACE-gated (it creates the record) and counts only real pops. `sched_sim_isolation_lib` stays without the trace sources (unresolved references in a static archive are harmless); 5.1 decides whether to add them. `core->decisions` holds 5 items, so trace-only decisions take FIFO slots and cannot reorder real ones.