diff --git a/.kiro/specs/scheduler-sim-repl-verbosity/design.md b/.kiro/specs/scheduler-sim-repl-verbosity/design.md index cae74207..071228d9 100644 --- a/.kiro/specs/scheduler-sim-repl-verbosity/design.md +++ b/.kiro/specs/scheduler-sim-repl-verbosity/design.md @@ -87,10 +87,10 @@ flowchart TD **Architecture Integration**: - Selected pattern: a state accumulator attached to the existing round-boundary hook (`xce_repl_post_session_check`), exposing one shared flush entry point that `repl_break.c`'s event/breakpoint/decision hooks and `repl.c`'s replay-completion hook all call — no new hook call sites added to `sim_loop.c`. -- Domain/feature boundaries: the Round Rollup's state and flush/print logic live in `repl.c`; `repl_break.c` calls the flush entry point but does not own or mutate the collapse state directly; `sim_loop.c` only gains a mode gate on its two existing calls. -- Existing patterns preserved: `repl.h`'s `sim->interactive`-gated inline-wrapper convention; `repl.c`'s shared-helper convention (`repl_format_ts_human`, `repl_split_tokens`) extended with two new shared helpers (range compression, and the round-rollup flush entry point declared in `repl_internal.h` for `repl_break.c` to call). +- Domain/feature boundaries: the Round Rollup's state and flush/print logic live in `repl_rollup.c` (split out of `repl.c` post-review — see Correction below); `repl_break.c` calls the flush entry point but does not own or mutate the collapse state directly; `sim_loop.c` only gains a mode gate on its two existing calls. +- Existing patterns preserved: `repl.h`'s `sim->interactive`-gated inline-wrapper convention; `repl.c`'s shared-helper convention (`repl_format_ts_human`, `repl_split_tokens`) extended with two new shared helpers (range compression, staying in `repl.c`; and the round-rollup flush entry point, now implemented in `repl_rollup.c` per the Correction below, declared in `repl_internal.h` for `repl.c`/`repl_break.c` to call). - New components rationale: deciding "print now vs. extend silently" requires comparing against the *previous* round's fingerprint, which must persist across separate `xce_repl_post_session_check()` invocations — hence new persistent fields on `xce_sched_repl_state_s` rather than function-local state. The flush entry point exists because three independent call sites (round boundary, breakpoint hit, replay completion) across two files all need to end an active range the same way. -- Steering compliance: one domain per file preserved; no new production `.c` file needed; `snake_case`/`repl_*` naming conventions followed throughout. +- Steering compliance: one domain per file preserved; `snake_case`/`repl_*` naming conventions followed throughout. **Correction (post-review, task 2.2, supersedes "no new production `.c` file needed" above)**: task 2.2's first pass kept the Round Rollup entirely inside `repl.c`, per this bullet's original text. That pushed `repl.c` to 1160 lines — 45% over this project's 800-line-per-file cap (`src/scheduler/CLAUDE.md`) — while review confirmed the logic itself was correct. The Round Rollup's fingerprint-build/pend-jobid-query/emit/flush/round-process functions (`repl_jobid_u64_cmp` through `repl_round_rollup_process`) now live in a new `src/scheduler/src/repl_rollup.c`, following the exact domain-split precedent this same file family already established for `repl_break.c`/`repl_info.c`/`repl_params.c` (`repl_internal.h`'s own "Why a split at all" section) — one more sibling sharing state via `repl_internal.h`, not a departure from that pattern. `repl.c`'s `repl_count_jobs()` becomes non-static so `repl_rollup.c`'s pend-jobid query can call it; both it and `repl_round_rollup_process()` gain `extern` declarations in `repl_internal.h`. `repl.c`'s own wiring calls (`xce_repl_post_session_check()`/`xce_repl_on_replay_complete()`) are unchanged. Tasks 6 (REPL Prompt Context) and 9 (Help & Breakpoint Discoverability/`BP_KIND_TABLE`) remain correctly targeted at `repl.c` — different domains (prompt construction, help/breakpoint-table rendering) with no Round Rollup logic of their own, unaffected by this correction. ### Technology Stack @@ -101,9 +101,13 @@ flowchart TD ## File Structure Plan ### Modified Files -- `src/scheduler/src/repl_internal.h` — extend `xce_sched_repl_state_s` with round-collapse state fields (see Data Models), a new `units_mode` field (Requirement 6), and declare the new shared jobid-range-compression helper, resource-formatting helpers, and the `BP_KIND_TABLE` accessor (Requirement 7). +**Correction (post-review, task 2.2)**: keeping the Round Rollup's logic inside `repl.c`, as the original `repl.c`/`repl_internal.h` entries below described, pushed that file to 1160 lines — 45% over this project's 800-line cap (`src/scheduler/CLAUDE.md`) — even though review confirmed the logic itself was correct. The Round Rollup's fingerprint/query/emit/flush/process functions now live in a new `src/scheduler/src/repl_rollup.c` instead, matching this exact file family's established domain-split precedent (`repl_break.c`/`repl_info.c`/`repl_params.c` already split out of `repl.c` by domain, per `repl_internal.h`'s own "Why a split at all" section) rather than growing `repl.c` further. The `repl.c` and `repl_internal.h` entries below, and the new `repl_rollup.c` entry, reflect this. Tasks 6 (REPL Prompt Context) and 9 (Help & Breakpoint Discoverability) are unaffected — both remain correctly targeted at `repl.c`, a different domain with no Round Rollup logic of its own. + +**Accepted residual (post-review, task 2.2)**: after the split, `repl.c` settled at 808 lines — 1% over the 800-line cap, down from the original 1160-line (45% over) violation. Verified empirically (not assumed): trimming the two doc comments this task added to their practical minimum recovers only 9 of the needed 17+ lines, and deleting both entirely would still leave 801. Getting strictly under 800 would require another file split for single-digit lines, which is disproportionate churn given this codebase already tolerates comparable or larger legacy exceptions (`scheduler.c` at 1382 lines, `plugins/builtin_fcfs.c` at 1026 lines, both noted in `src/scheduler/CLAUDE.md` as "do not use... as precedent for new files" but tolerated in place). 808 lines is accepted as this task's final state; if tasks 6/9's later `repl.c` additions push it meaningfully further over, revisit with a fresh split decision at that point rather than trimming comments further now. +- `src/scheduler/src/repl_internal.h` — extend `xce_sched_repl_state_s` with round-collapse state fields (see Data Models), a new `units_mode` field (Requirement 6), and declare the new shared jobid-range-compression helper, resource-formatting helpers, and the `BP_KIND_TABLE` accessor (Requirement 7); post-review (Correction above), also declares `repl_count_jobs()` and `repl_round_rollup_process()` `extern` so `repl_rollup.c` can call the former and `repl.c` can call the latter. - `src/scheduler/src/repl_break.c` — `xce_repl_on_event()` gains routine-vs-structural event classification gated on `rs->mode` (Requirement 1); `repl_print_event_summary()`'s `JOB_PUSH`-style cases adopt the jobid-range-compression helper (Requirement 4); `xce_repl_on_event()`, `xce_repl_on_begin_round()`, and `xce_repl_on_decision()` each call the Round Rollup's flush entry point before printing a structural-event line or before re-entering `repl_command_loop()` on a breakpoint hit (Requirement 3.5, 3.6); `repl_cmd_break()`'s unrecognized-event-type error gains the full valid-event-type listing, rendered via a new shared accessor over the existing `BP_KIND_TABLE` (Requirement 7.5); `repl_cmd_delete()` already fixed independently (bug-1761, `strtol`+endptr validation) — no further change needed here for this spec. -- `src/scheduler/src/repl.c` — `xce_repl_post_session_check()` gains the round-boundary fingerprint/collapse logic (Requirements 2, 3); implements the new shared jobid-range-compression helper (Requirement 4) and the Round Rollup's flush entry point (Requirement 3.5, 3.6), following the file's existing shared-helper convention; `xce_repl_on_replay_complete()` calls the same flush entry point before printing the existing replay-complete banner; `repl_command_loop()`'s `readline(XCE_REPL_PROMPT)` call gains a per-iteration dynamically-built prompt (Requirement 5.5); `repl_print_help()` is rewritten into labeled, consistently-aligned sections, `info config` moves next to the other `info` lines, and the `break` line grows the same `BP_KIND_TABLE`-derived event-type listing `repl_break.c`'s error message uses (Requirement 7). +- `src/scheduler/src/repl.c` — `xce_repl_post_session_check()` calls the Round Rollup's round-boundary fingerprint/collapse logic, and `xce_repl_on_replay_complete()` calls its flush entry point before printing the existing replay-complete banner (Requirements 2, 3; post-review Correction above: the Round Rollup's own logic — fingerprint build, collapse, flush, emit — now lives in the new `repl_rollup.c` below, not here); implements the new shared jobid-range-compression helper (Requirement 4), following the file's existing shared-helper convention; `repl_command_loop()`'s `readline(XCE_REPL_PROMPT)` call gains a per-iteration dynamically-built prompt (Requirement 5.5); `repl_print_help()` is rewritten into labeled, consistently-aligned sections, `info config` moves next to the other `info` lines, and the `break` line grows the same `BP_KIND_TABLE`-derived event-type listing `repl_break.c`'s error message uses (Requirement 7). +- `src/scheduler/src/repl_rollup.c` (new, post-review — Correction above) — the Round Rollup's own fingerprint-build/pend-jobid-query/emit/flush/round-boundary-process logic (Requirements 2, 3), split out of `repl.c` to stay under the 800-line cap; shares state with `repl.c` via `repl_internal.h`, matching `repl_break.c`/`repl_info.c`/`repl_params.c`'s established split; added to `scheduler_srcs` in `src/scheduler/meson.build` immediately after `repl.c`. - `src/scheduler/src/repl_info.c` — new resource-value classification/scaling helpers (byte-denominated list, `swp`'s megabyte special case, whole-number formatting) and a table/grouping rewrite of `repl_info_worker()`'s and `repl_info_resource()`'s resource-listing loops, both reading `rs->units_mode` (Requirement 6); the assigned-job listing in `repl_info_worker()` adopts the jobid-range-compression helper (Requirement 4.5). - `src/scheduler/src/repl_params.c` — `repl_cmd_set()` gains a `units raw|human|both` branch alongside the existing `speed`/`output`/`verify` branches, storing the selection on the new `rs->units_mode` field (Requirement 6.2, 6.3). - `src/scheduler/src/sim_loop.c` — the existing call site invoking `sim_print_decision()` gains a `continue`-mode gate, mirroring `repl.h`'s inline-wrapper convention (Requirements 2, 5). @@ -142,7 +146,7 @@ See the Architecture Pattern & Boundary Map diagram above — it is the only non | Component | Domain/Layer | Intent | Req Coverage | Key Dependencies (P0/P1) | Contracts | |-----------|---------------|--------|---------------|---------------------------|-----------| | Event Echo Gate | REPL / repl_break.c | Classify each event as routine or structural and gate the per-event echo by mode | 1.1-1.4 | `rs->mode` (P0), Round Rollup flush entry point (P0) | State | -| Round Rollup | REPL / repl.c | Build a per-round fingerprint, print it, or extend/flush a collapsed range; expose a flush entry point callable from breakpoint/structural-event/replay-complete sites | 2.1-2.4, 3.1-3.6 | `core->jobs` query (P0), existing decision tally (P0) | State, Service | +| Round Rollup | REPL / repl_rollup.c (post-review; see Correction, was repl.c) | Build a per-round fingerprint, print it, or extend/flush a collapsed range; expose a flush entry point callable from breakpoint/structural-event/replay-complete sites | 2.1-2.4, 3.1-3.6 | `core->jobs` query (P0), existing decision tally (P0) | State, Service | | Jobid Range Compressor | REPL / repl.c (shared helper) | Compress array-job identifier lists into index ranges | 4.1-4.5 | `fmt_jobid_ex` decomposition (P0) | Service | | `sim_print_decision` gate | Sim driver / sim_loop.c | Suppress the direct per-decision print when the Round Rollup will report it instead | 2.3, 5.1 | REPL mode state (P0) | State | | REPL Prompt Context | REPL / repl.c | Build the `readline()` prompt string from the current session and timestamp, falling back to the plain prompt before any session begins | 5.5 | `rs->session_count` (P0), `xce_core_now`/`repl_format_ts_human` (P0) | Service | @@ -178,6 +182,7 @@ See the Architecture Pattern & Boundary Map diagram above — it is the only non |-------|--------| | Intent | Once per completed round in `continue` mode, compute a fingerprint and either extend an active collapsed range or flush it and begin reporting the new state | | Requirements | 2.1, 2.2, 2.3, 2.4, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 | +| File | `src/scheduler/src/repl_rollup.c` (post-review, task 2.2 — was `repl.c`; see the Architecture Integration / Modified Files Corrections above for why) | **Responsibilities & Constraints** - Active only while `sim->interactive && rs->mode == XCE_REPL_MODE_CONTINUE`; `step` mode keeps today's full per-decision path unchanged (Requirement 2.3, 5.1). @@ -186,8 +191,8 @@ See the Architecture Pattern & Boundary Map diagram above — it is the only non - Must flush (print) any active collapsed range before: a breakpoint-triggered re-entry into `repl_command_loop()`, replay completion, or a fingerprint change from the active range (Requirement 3.5, 3.6). Because the breakpoint and structural-event triggers originate in `repl_break.c`, not `repl.c`, this component exposes a flush entry point other files call rather than owning every trigger site itself. **Dependencies** -- Inbound: `xce_repl_post_session_check` — the round-boundary call site the fingerprint/collapse logic attaches to (P0); the Event Echo Gate (`xce_repl_on_event`) and the breakpoint checks in `xce_repl_on_begin_round`/`xce_repl_on_decision` (all repl_break.c) — call the flush entry point (P0); `xce_repl_on_replay_complete` (repl.c) — calls the flush entry point before its existing banner (P0) -- Outbound: `core->jobs` iterator (P0), `xce_repl_on_decision`'s existing tally fields (P0), Jobid Range Compressor for rendering the pend-jobid list (P0) +- Inbound: `xce_repl_post_session_check` (repl.c) — the round-boundary call site the fingerprint/collapse logic attaches to, calling `repl_rollup.c`'s `repl_round_rollup_process()` (P0); the Event Echo Gate (`xce_repl_on_event`) and the breakpoint checks in `xce_repl_on_begin_round`/`xce_repl_on_decision` (all repl_break.c) — call the flush entry point (P0); `xce_repl_on_replay_complete` (repl.c) — calls the flush entry point before its existing banner (P0). All three inbound call sites live in a different file from this component's own implementation (post-review, task 2.2 — see Correction above) and reach it via `repl_internal.h`'s `extern` declarations. +- Outbound: `core->jobs` iterator (P0), `repl.c`'s `repl_count_jobs()` (P0, `extern`-declared in `repl_internal.h` post-review for this cross-file call), `xce_repl_on_decision`'s existing tally fields (P0), Jobid Range Compressor (repl.c) for rendering the pend-jobid list (P0) **Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [x] diff --git a/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md b/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md index 046cfbbf..f5c17e6d 100644 --- a/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md +++ b/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md @@ -20,7 +20,7 @@ - _Boundary: Round Rollup_ - _Depends: 1.2_ -- [ ] 2.2 Implement the round-boundary decision summary, collapsing logic, and the shared range-flush capability +- [x] 2.2 Implement the round-boundary decision summary, collapsing logic, and the shared range-flush capability - Add the state needed to track an active collapsed range across rounds - At each round boundary during continuous execution, determine the round's decision outcome directly from current job status (not solely from decision events) together with the existing per-round decision tally, then extend an active matching range or end it and begin reporting the new outcome - Expose the range-ending behavior so other parts of the REPL can trigger it safely, including when nothing is active; wire it into the existing replay-completion notification so a range open at end-of-replay is closed and reported before that notification prints diff --git a/src/scheduler/meson.build b/src/scheduler/meson.build index a3419a76..330330ba 100644 --- a/src/scheduler/meson.build +++ b/src/scheduler/meson.build @@ -20,6 +20,7 @@ scheduler_srcs = [ 'src/sim_verify.c', 'src/sim_record.c', 'src/repl.c', + 'src/repl_rollup.c', 'src/repl_break.c', 'src/repl_info.c', 'src/repl_params.c', @@ -117,7 +118,7 @@ sched_sim_isolation_lib = static_library( 'sched_sim_isolation', ['src/sim.c', 'src/sim_loop.c', 'src/sim_picker.c', 'src/sim_record.c', 'src/repl.c', 'src/repl_break.c', 'src/repl_info.c', - 'src/repl_params.c'], + 'src/repl_params.c', 'src/repl_rollup.c'], include_directories: incdir, dependencies: scheduler_deps, install: false) diff --git a/src/scheduler/src/repl.c b/src/scheduler/src/repl.c index 25f32052..f853a20f 100644 --- a/src/scheduler/src/repl.c +++ b/src/scheduler/src/repl.c @@ -173,7 +173,7 @@ int repl_split_tokens(const char* line, char tokens[][XCE_REPL_TOKEN_LEN], * zero file re-scan -- and is labeled honestly below ("N jobs"), not * mislabeled as an event count. */ -static int repl_count_jobs(xce_sched_core_t* core) +int repl_count_jobs(xce_sched_core_t* core) { iterator_t it; xce_sched_job_t* job = NULL; @@ -496,8 +496,18 @@ static bool repl_should_pause(xce_sched_sim_driver_t* sim) return false; } +/* + * Continue-mode-only Round Rollup trigger (task 2.2, Req 2.3/5.1); step + * mode never calls repl_round_rollup_process() (repl_rollup.c/repl_ + * internal.h). Runs before the step-pause check below -- mode-exclusive. + */ void xce_repl_post_session_check(xce_sched_sim_driver_t* sim) { + if ((sim->repl_state != NULL) + && (sim->repl_state->mode == XCE_REPL_MODE_CONTINUE)) { + repl_round_rollup_process(sim); + } + if (repl_should_pause(sim)) { repl_command_loop(sim); } @@ -518,6 +528,10 @@ void xce_repl_on_replay_complete(xce_sched_sim_driver_t* sim) return; } + /* Req 3.6 (task 2.2): end any open collapsed range before the banner + * below -- repl_round_collapse_flush() safely no-ops if unused. */ + repl_round_collapse_flush(sim); + fprintf(stdout, "[sim] replay complete. %llu session(s) processed.\n", (unsigned long long)rs->session_count); if (rs->output_path != NULL) { diff --git a/src/scheduler/src/repl_internal.h b/src/scheduler/src/repl_internal.h index befe2682..a665d09d 100644 --- a/src/scheduler/src/repl_internal.h +++ b/src/scheduler/src/repl_internal.h @@ -185,6 +185,44 @@ struct xce_sched_repl_state_s { * cleared -- a REPL session only ever reaches replay completion once. */ bool replay_complete; + + /* + * Round Rollup fields (scheduler-sim-repl-verbosity spec, task 2.2, + * design.md's "Round Rollup" component, Req 2/3) -- track the ACTIVE + * collapsed round range across separate xce_repl_post_session_check() + * invocations (one per completed round, `continue` mode only; `step` + * mode never touches these). `collapse_active` gates every other field + * below: false means "nothing open", and the bounds/fingerprint fields + * are meaningless (repl_round_collapse_flush() is a no-op in that + * state). `collapse_start_round`/`collapse_end_round` and + * `collapse_start_ts`/`collapse_end_ts` are rs->session_count and + * rs->last_begin_round snapshots taken at the round that OPENED the + * range and the round that most recently EXTENDED it (both equal to the + * same single round's values the moment a range is first opened). + * `collapse_dispatch_count`/`collapse_preempt_count` cache the active + * range's fingerprint counts (sourced from the existing + * last_n_dispatch/last_n_preempt tally at the round that opened the + * range -- every round in one collapsed range shares an identical + * outcome by construction, so caching the first round's counts is + * sufficient). `collapse_pend_jobids` (heap-allocated, sorted ascending) + * / `collapse_n_pend_jobids` cache the active range's pend-jobid set, + * queried directly from core->jobs (repl_rollup.c's + * repl_query_pend_jobids()) rather than any decision tally -- see + * repl_rollup.c's own doc comment on why (Requirement 2.4, independent + * of bug-1611). Freed and reset to + * NULL/0 every time repl_round_collapse_flush() ends the range (flush + * always fully clears this group, print-then-clear, whether or not a + * range was open to begin with). + */ + bool collapse_active; + uint64_t collapse_start_round; + uint64_t collapse_end_round; + uint64_t collapse_start_ts; + uint64_t collapse_end_ts; + int collapse_dispatch_count; + int collapse_preempt_count; + uint64_t* collapse_pend_jobids; + int collapse_n_pend_jobids; }; /* repl_split_tokens/XCE_REPL_MAX_TOKENS/XCE_REPL_TOKEN_LEN (repl.c) - @@ -269,4 +307,52 @@ extern const char* repl_job_state_name(uint32_t state); extern int repl_fmt_jobid_range(char* buf, size_t bufsz, const uint64_t* jobids, int njobids); +/* + * repl_round_collapse_flush (repl_rollup.c, scheduler-sim-repl-verbosity + * spec, task 2.2, design.md's "Round Rollup" component Service Interface, + * Req 3.5/3.6) - ends the active collapsed round range on `sim->repl_state`, + * if one is open, printing its summary line immediately; a safe no-op when + * nothing is active (NULL sim/sim->repl_state included, same discipline + * every other REPL hook in this file family follows). Idempotent -- calling + * it again immediately afterward with no intervening round is a no-op, + * never a duplicate print. Called from the round boundary + * (xce_repl_post_session_check(), on a fingerprint mismatch) and from + * xce_repl_on_replay_complete() (both repl.c, this task); declared here, + * not just locally in repl.c, because a LATER task (3.2) wires + * repl_break.c's xce_repl_on_event()/xce_repl_on_begin_round()/ + * xce_repl_on_decision() to call it too, before a structural-event line or + * a breakpoint-triggered repl_command_loop() re-entry (Req 3.5, 3.6) -- this + * file is the shared cross-file declaration point every other repl_*.c + * sibling already uses for exactly that reason. + */ +extern void repl_round_collapse_flush(xce_sched_sim_driver_t* sim); + +/* + * repl_count_jobs (repl.c) - counts `core->jobs` via the same + * iter_make()/iter_next() walk this file family already uses elsewhere for + * enumerating a kvmgr-backed `var` container (see repl.c's own doc comment + * on this function for the full rationale, including why it reports + * already-loaded job records rather than a replay-event count). Declared + * here, not just locally in repl.c, because repl_rollup.c's + * repl_query_pend_jobids() (scheduler-sim-repl-verbosity spec, task 2.2) + * needs it too, to size its pend-jobid buffer -- non-static in repl.c for + * exactly that cross-file use. + */ +extern int repl_count_jobs(xce_sched_core_t* core); + +/* + * repl_round_rollup_process (repl_rollup.c, scheduler-sim-repl-verbosity + * spec, task 2.2, design.md's "Round Rollup" component, Req 2/3) - the + * round-boundary half of the Round Rollup: builds the completed round's + * fingerprint and either extends the active collapsed range silently or + * flushes it (repl_round_collapse_flush(), above) and begins tracking the + * new round as a fresh one. Declared here, not just locally in repl.c, + * because repl.c's xce_repl_post_session_check() -- the sole call site, + * gated strictly to `continue` mode -- lives in a different file from this + * function's own implementation (repl_rollup.c, split out of repl.c + * post-review to keep repl.c under this project's 800-line cap; see + * repl_rollup.c's own file header comment). + */ +extern void repl_round_rollup_process(xce_sched_sim_driver_t* sim); + #endif diff --git a/src/scheduler/src/repl_rollup.c b/src/scheduler/src/repl_rollup.c new file mode 100644 index 00000000..9bbd1041 --- /dev/null +++ b/src/scheduler/src/repl_rollup.c @@ -0,0 +1,339 @@ +#include +#include + +#include "repl.h" +#include "repl_internal.h" + +/* + * ---- Round Rollup (scheduler-sim-repl-verbosity spec, task 2.2, + * design.md's "Round Rollup" component, Req 2 "Per-Round Decision Summary", + * Req 3 "Collapsing of Repetitive Round Output") ---- + * + * Once per completed round, ONLY while `continue`-mode execution is active + * (xce_repl_post_session_check() above, gated on rs->mode -- `step` mode's + * existing unconditional per-decision echo, sim_print_decision() + * (sim_loop.c), is completely untouched by anything in this section, per + * Requirement 2.3/5.1), this builds a per-round "fingerprint" -- + * dispatch/preempt counts from the existing last_n_dispatch/last_n_preempt + * tally (xce_repl_on_decision(), repl_break.c), plus the CURRENT pend-jobid + * set queried directly from core->jobs (NOT the decision tally -- see + * repl_query_pend_jobids()'s own doc comment for why) -- and compares it + * against the active collapsed range's cached fingerprint (rs->collapse_*, + * repl_internal.h). A match silently extends the active range (no print, + * ever -- printing is always deferred until the range is proven to have + * ended). A mismatch flushes (prints) the old range via + * repl_round_collapse_flush() and begins tracking the new round as a fresh + * active range of its own (also not yet printed). repl_round_collapse_flush() + * is the one shared exit point every "range has ended" trigger uses -- a + * fingerprint mismatch here, and (a later task's scope, Req 3.5/3.6) a + * structural event or breakpoint hit in repl_break.c, or replay completion + * (xce_repl_on_replay_complete() above, this task) -- so an active range can + * never leak past whichever trigger ends it, and is never printed more than + * once. + */ + +/* + * repl_jobid_u64_cmp - qsort() comparator for a plain uint64_t jobid array + * (repl_query_pend_jobids()'s sorted output below), distinct from + * repl_jobid_idx_cmp() above (which compares uint32_t array INDICES within + * one array-job base -- repl_fmt_jobid_range()'s own internal sort, a + * different type and a different purpose entirely). + */ +static int repl_jobid_u64_cmp(const void* a, const void* b) +{ + uint64_t ua = *(const uint64_t*)a; + uint64_t ub = *(const uint64_t*)b; + + if (ua < ub) { + return -1; + } + if (ua > ub) { + return 1; + } + return 0; +} + +/* + * repl_query_pend_jobids - builds the Round Rollup's pend-jobid fingerprint + * component by walking core->jobs directly for JOB_IS_PEND state -- the SAME + * iter_make()/iter_next() idiom repl_info.c's repl_info_jobs() already uses + * (design.md's Round Rollup "Dependencies", Allowed Dependencies), rather + * than deriving it from xce_repl_on_decision()'s last_n_pend tally. This is + * deliberate: Requirement 2.4 ("a job's status change is reflected in the + * round summary") must hold even when no decision object is ever produced + * for that job (bug-1611: this simulator's picker/allocator only ever emits + * PEND decisions for currently-candidate jobs, never a genuine DISPATCH -- + * see that bug's own buglog entry; this design is explicitly independent of + * however that investigation resolves). Querying core->jobs directly, AT + * this exact round-boundary call site (xce_repl_post_session_check() runs + * after xce_core_end_session(), so every event this round's batch pushed -- + * including a bare JOB_STATE_CHANGE with no accompanying decision -- has + * already been applied to job->state) makes the pend-jobid set correct + * regardless of whether a decision was ever produced for the job that + * changed. Output is heap-allocated (caller owns/frees it) and sorted + * ascending, so two fingerprints' pend-jobid sets can be compared with a + * plain elementwise walk (repl_jobid_arrays_equal() below) without caring + * about core->jobs' own kvmgr iteration order. Returns false only on + * allocation failure (design.md's Error Handling: the caller falls back to + * an uncollapsed print for that round rather than losing it); `*out_ids`/ + * `*out_n` are always initialized (NULL/0) first, so a false return never + * leaves them pointing at a partial/stale buffer. + */ +static bool repl_query_pend_jobids(xce_sched_core_t* core, uint64_t** out_ids, + int* out_n) +{ + iterator_t it; + uint64_t* ids = NULL; + int cap; + int n = 0; + int rc; + + *out_ids = NULL; + *out_n = 0; + + cap = repl_count_jobs(core); + if (cap <= 0) { + return true; /* no jobs at all -- an empty pend set, not a failure */ + } + + ids = (uint64_t*)calloc((size_t)cap, sizeof(*ids)); + if (ids == NULL) { + return false; + } + + rc = iter_make(&it, core->jobs); + if (rc < 0) { + free(ids); + return true; /* degrade to "no pend jobs known" -- same discipline + * repl_count_jobs() itself already uses on this same + * failure */ + } + + for (;;) { + xce_sched_job_t* job = NULL; + + rc = iter_next(&it, (void**)&job); + if ((rc < 0) || (rc == RTTI_ITER_NO_DATA) || (job == NULL)) { + break; + } + if (JOB_IS_PEND(job->state) && (n < cap)) { + ids[n++] = job->jobid; + } + } + + /* Unlike repl_count_jobs()/repl_info_jobs() (whose single call-per- + * command lifetime makes their own missing iter_destroy() a + * pre-existing, low-impact quirk), this function runs once per + * completed round for as long as `continue` keeps running -- the same + * safer iter_destroy() convention repl_info_queue_one() already + * establishes elsewhere in this file family is worth following here to + * avoid accumulating a real leak across a long replay. */ + iter_destroy(&it); + + qsort(ids, (size_t)n, sizeof(*ids), repl_jobid_u64_cmp); + + *out_ids = ids; + *out_n = n; + + return true; +} + +/* + * repl_jobid_arrays_equal - true iff both SORTED (repl_query_pend_jobids()'s + * own postcondition) jobid arrays contain exactly the same id set -- the + * pend-jobid half of "two rounds share an identical decision outcome" + * (Requirement 3.2). + */ +static bool repl_jobid_arrays_equal(const uint64_t* a, int na, + const uint64_t* b, int nb) +{ + int i; + + if (na != nb) { + return false; + } + for (i = 0; i < na; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; +} + +/* + * repl_round_emit - the Round Rollup's actual print, given an already- + * decided range (bounds/fingerprint) rather than reading rs->collapse_* + * directly, so repl_round_collapse_flush() (the normal path) and + * repl_round_rollup_process()'s allocation-failure fallback below can share + * one rendering. Pins the exact format task 2.1's own RED-phase test file + * documents (test_repl_round_rollup.c's "Assumed output contract" header + * comment): idle ranges (zero dispatch/preempt AND an empty pend-jobid set) + * render as "... : idle"; every other range renders decision counts plus + * the pend-jobid listing via repl_fmt_jobid_range() (design.md's Jobid + * Range Compressor, reused rather than reimplemented -- Requirement 4.5). + * Callers decide whether an idle range's round count clears Requirement + * 3.1's ">= 2" threshold before calling this -- this function always prints + * when called. + */ +static void repl_round_emit(uint64_t start_round, uint64_t end_round, + uint64_t start_ts, uint64_t end_ts, + int dispatch_count, int preempt_count, + const uint64_t* pend_jobids, int n_pend_jobids, + bool idle) +{ + char ts_start[32]; + char ts_end[32]; + + repl_format_ts_human(start_ts, ts_start, sizeof(ts_start)); + repl_format_ts_human(end_ts, ts_end, sizeof(ts_end)); + + if (idle) { + fprintf(stdout, + "[sim] round %llu-%llu (%llu round(s), t=%s..%s): idle\n", + (unsigned long long)start_round, (unsigned long long)end_round, + (unsigned long long)(end_round - start_round + 1), ts_start, + ts_end); + return; + } + + { + char jobids_buf[1024]; + int rc = repl_fmt_jobid_range(jobids_buf, sizeof(jobids_buf), + pend_jobids, n_pend_jobids); + + if (rc < 0) { + /* design.md's Error Handling: buffer too small -- fall back to + * a placeholder rather than truncating or crashing; this + * never fabricates or silently drops a jobid, it just can't + * render the full listing here. */ + snprintf(jobids_buf, sizeof(jobids_buf), "(too many to list)"); + } + + fprintf(stdout, + "[sim] round %llu-%llu (%llu round(s), t=%s..%s): %d " + "dispatch, %d pend, %d preempt -- jobids=%s\n", + (unsigned long long)start_round, (unsigned long long)end_round, + (unsigned long long)(end_round - start_round + 1), ts_start, + ts_end, dispatch_count, n_pend_jobids, preempt_count, + jobids_buf); + } +} + +/* + * repl_round_collapse_flush - design.md's Round Rollup Service Interface + * (Req 3.5, 3.6; declared for cross-file use in repl_internal.h, see that + * header's own doc comment). Ends the active collapsed range, if one is + * open, printing its summary line immediately; a safe no-op otherwise + * (NULL sim/sim->repl_state included, same discipline every other REPL + * hook in this file family follows). Idempotent by construction: the first + * call clears rs->collapse_active before returning, so an immediately + * repeated call with no intervening round takes the no-op branch above and + * never prints twice. + */ +void repl_round_collapse_flush(xce_sched_sim_driver_t* sim) +{ + xce_sched_repl_state_t* rs; + uint64_t count; + bool idle; + + if ((sim == NULL) || (sim->repl_state == NULL)) { + return; + } + rs = sim->repl_state; + + if (!rs->collapse_active) { + return; + } + + count = rs->collapse_end_round - rs->collapse_start_round + 1; + idle = (rs->collapse_dispatch_count == 0) + && (rs->collapse_preempt_count == 0) + && (rs->collapse_n_pend_jobids == 0); + + /* Requirement 2.2/3.1: a genuinely isolated single idle round produces + * NO output at all, ever -- only an idle STREAK (>= 2 rounds) is worth + * reporting. A non-idle range is always eventually printed here, + * regardless of its own round count (Requirement 2.1). */ + if (!idle || (count >= 2)) { + repl_round_emit(rs->collapse_start_round, rs->collapse_end_round, + rs->collapse_start_ts, rs->collapse_end_ts, + rs->collapse_dispatch_count, + rs->collapse_preempt_count, rs->collapse_pend_jobids, + rs->collapse_n_pend_jobids, idle); + } + + free(rs->collapse_pend_jobids); + rs->collapse_pend_jobids = NULL; + rs->collapse_n_pend_jobids = 0; + rs->collapse_dispatch_count = 0; + rs->collapse_preempt_count = 0; + rs->collapse_start_round = 0; + rs->collapse_end_round = 0; + rs->collapse_start_ts = 0; + rs->collapse_end_ts = 0; + rs->collapse_active = false; +} + +/* + * repl_round_rollup_process - the round-boundary half of the Round Rollup + * (Requirements 2.1-2.4, 3.1-3.4): builds this round's fingerprint and + * either extends the active collapsed range silently or flushes it and + * begins tracking this round as a fresh one. Called only from + * xce_repl_post_session_check() above, only in `continue` mode -- see this + * file's own "Round Rollup" section header comment above this section. + */ +void repl_round_rollup_process(xce_sched_sim_driver_t* sim) +{ + xce_sched_repl_state_t* rs = sim->repl_state; + uint64_t* pend_jobids = NULL; + int n_pend_jobids = 0; + int dispatch_count = rs->last_n_dispatch; + int preempt_count = rs->last_n_preempt; + uint64_t round_no = rs->session_count; + uint64_t round_ts = rs->last_begin_round; + + if (!repl_query_pend_jobids(&(sim->core), &pend_jobids, &n_pend_jobids)) { + /* design.md's Error Handling: allocation failure while building + * this round's fingerprint -- rather than silently losing this + * round's information, flush whatever was already active + * (preserving print ordering) and report this round on its own, + * uncollapsed. Never starts a new active range on this degraded + * path -- the next round gets a fair, fully-informed fingerprint + * attempt again. */ + repl_round_collapse_flush(sim); + repl_round_emit(round_no, round_no, round_ts, round_ts, + dispatch_count, preempt_count, NULL, 0, + (dispatch_count == 0) && (preempt_count == 0)); + return; + } + + if (rs->collapse_active + && (rs->collapse_dispatch_count == dispatch_count) + && (rs->collapse_preempt_count == preempt_count) + && repl_jobid_arrays_equal(rs->collapse_pend_jobids, + rs->collapse_n_pend_jobids, pend_jobids, + n_pend_jobids)) { + /* Identical outcome -- extend the active range silently (never + * printed until it ends, Requirement 3.2). */ + rs->collapse_end_round = round_no; + rs->collapse_end_ts = round_ts; + free(pend_jobids); + return; + } + + /* Either nothing was active yet, or this round's outcome differs from + * the active range's -- end (flush/print) the old range first + * (Requirement 3.5), then begin tracking this round as a fresh active + * range of its own (print deferred until IT, in turn, ends). */ + repl_round_collapse_flush(sim); + + rs->collapse_active = true; + rs->collapse_start_round = round_no; + rs->collapse_end_round = round_no; + rs->collapse_start_ts = round_ts; + rs->collapse_end_ts = round_ts; + rs->collapse_dispatch_count = dispatch_count; + rs->collapse_preempt_count = preempt_count; + rs->collapse_pend_jobids = pend_jobids; /* ownership transferred */ + rs->collapse_n_pend_jobids = n_pend_jobids; +} diff --git a/src/scheduler/testsuite/meson.build b/src/scheduler/testsuite/meson.build index 988dcbf7..4f7c864d 100644 --- a/src/scheduler/testsuite/meson.build +++ b/src/scheduler/testsuite/meson.build @@ -625,6 +625,9 @@ sched_sim_isolation_test = executable( '-DXCE_SIM_REPL_PARAMS_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_params.c') + '"', + '-DXCE_SIM_REPL_ROLLUP_C_PATH="' + + (meson.current_source_dir() / '..' / 'src' / 'repl_rollup.c') + + '"', '-DXCE_SIM_LIB_PATH="' + sched_sim_isolation_lib.full_path() + '"'], diff --git a/src/scheduler/testsuite/test_repl_breakpoints_inspection.c b/src/scheduler/testsuite/test_repl_breakpoints_inspection.c index 4f9e8ba9..2d4cd3af 100644 --- a/src/scheduler/testsuite/test_repl_breakpoints_inspection.c +++ b/src/scheduler/testsuite/test_repl_breakpoints_inspection.c @@ -80,6 +80,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_repl_equivalence.c b/src/scheduler/testsuite/test_repl_equivalence.c index e21fd068..5908fc87 100644 --- a/src/scheduler/testsuite/test_repl_equivalence.c +++ b/src/scheduler/testsuite/test_repl_equivalence.c @@ -129,6 +129,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_repl_execution_control.c b/src/scheduler/testsuite/test_repl_execution_control.c index 17db471a..b55183b2 100644 --- a/src/scheduler/testsuite/test_repl_execution_control.c +++ b/src/scheduler/testsuite/test_repl_execution_control.c @@ -94,6 +94,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_repl_round_rollup.c b/src/scheduler/testsuite/test_repl_round_rollup.c index 5938e8df..d9f9595c 100644 --- a/src/scheduler/testsuite/test_repl_round_rollup.c +++ b/src/scheduler/testsuite/test_repl_round_rollup.c @@ -56,6 +56,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_repl_snapshot_params.c b/src/scheduler/testsuite/test_repl_snapshot_params.c index d00f4d18..edbd0061 100644 --- a/src/scheduler/testsuite/test_repl_snapshot_params.c +++ b/src/scheduler/testsuite/test_repl_snapshot_params.c @@ -58,6 +58,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_alt_events.c b/src/scheduler/testsuite/test_sim_alt_events.c index bb3d4c24..754748fb 100644 --- a/src/scheduler/testsuite/test_sim_alt_events.c +++ b/src/scheduler/testsuite/test_sim_alt_events.c @@ -87,6 +87,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_contention_parity.c b/src/scheduler/testsuite/test_sim_contention_parity.c index 49b05c56..4ac1caaf 100644 --- a/src/scheduler/testsuite/test_sim_contention_parity.c +++ b/src/scheduler/testsuite/test_sim_contention_parity.c @@ -171,6 +171,7 @@ #include "../src/recording_events.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_e2e_original_motivation.c b/src/scheduler/testsuite/test_sim_e2e_original_motivation.c index c8982de0..5123890c 100644 --- a/src/scheduler/testsuite/test_sim_e2e_original_motivation.c +++ b/src/scheduler/testsuite/test_sim_e2e_original_motivation.c @@ -194,6 +194,7 @@ #include "../src/recording_events.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_equivalence.c b/src/scheduler/testsuite/test_sim_equivalence.c index 05272af6..b67b921f 100644 --- a/src/scheduler/testsuite/test_sim_equivalence.c +++ b/src/scheduler/testsuite/test_sim_equivalence.c @@ -156,6 +156,7 @@ #include "../src/recording_events.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_event_loop.c b/src/scheduler/testsuite/test_sim_event_loop.c index 5a80d32f..494d5679 100644 --- a/src/scheduler/testsuite/test_sim_event_loop.c +++ b/src/scheduler/testsuite/test_sim_event_loop.c @@ -103,6 +103,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_isolation.c b/src/scheduler/testsuite/test_sim_isolation.c index bc8424ee..87247e43 100644 --- a/src/scheduler/testsuite/test_sim_isolation.c +++ b/src/scheduler/testsuite/test_sim_isolation.c @@ -446,6 +446,7 @@ static void test_sim_never_includes_forbidden_headers(void) char* repl_info_c_raw = read_whole_file(XCE_SIM_REPL_INFO_C_PATH); char* repl_int_h_raw = read_whole_file(XCE_SIM_REPL_INTERNAL_H_PATH); char* repl_params_c_raw = read_whole_file(XCE_SIM_REPL_PARAMS_C_PATH); + char* repl_rollup_c_raw = read_whole_file(XCE_SIM_REPL_ROLLUP_C_PATH); char* h; char* c; char* loop; @@ -457,6 +458,7 @@ static void test_sim_never_includes_forbidden_headers(void) char* repl_info_c; char* repl_int_h; char* repl_params_c; + char* repl_rollup_c; TEST_ASSERT_NOT_NULL(h_raw); TEST_ASSERT_NOT_NULL(c_raw); @@ -469,6 +471,7 @@ static void test_sim_never_includes_forbidden_headers(void) TEST_ASSERT_NOT_NULL(repl_info_c_raw); TEST_ASSERT_NOT_NULL(repl_int_h_raw); TEST_ASSERT_NOT_NULL(repl_params_c_raw); + TEST_ASSERT_NOT_NULL(repl_rollup_c_raw); h = strip_c_comments(h_raw); c = strip_c_comments(c_raw); @@ -481,6 +484,7 @@ static void test_sim_never_includes_forbidden_headers(void) repl_info_c = strip_c_comments(repl_info_c_raw); repl_int_h = strip_c_comments(repl_int_h_raw); repl_params_c = strip_c_comments(repl_params_c_raw); + repl_rollup_c = strip_c_comments(repl_rollup_c_raw); TEST_ASSERT_NOT_NULL(h); TEST_ASSERT_NOT_NULL(c); TEST_ASSERT_NOT_NULL(loop); @@ -492,6 +496,7 @@ static void test_sim_never_includes_forbidden_headers(void) TEST_ASSERT_NOT_NULL(repl_info_c); TEST_ASSERT_NOT_NULL(repl_int_h); TEST_ASSERT_NOT_NULL(repl_params_c); + TEST_ASSERT_NOT_NULL(repl_rollup_c); assert_no_forbidden_includes(h, "sim.h"); assert_no_forbidden_includes(c, "sim.c"); @@ -504,6 +509,7 @@ static void test_sim_never_includes_forbidden_headers(void) assert_no_forbidden_includes(repl_info_c, "repl_info.c"); assert_no_forbidden_includes(repl_int_h, "repl_internal.h"); assert_no_forbidden_includes(repl_params_c, "repl_params.c"); + assert_no_forbidden_includes(repl_rollup_c, "repl_rollup.c"); free(h_raw); free(c_raw); @@ -516,6 +522,7 @@ static void test_sim_never_includes_forbidden_headers(void) free(repl_info_c_raw); free(repl_int_h_raw); free(repl_params_c_raw); + free(repl_rollup_c_raw); free(h); free(c); free(loop); @@ -527,6 +534,7 @@ static void test_sim_never_includes_forbidden_headers(void) free(repl_info_c); free(repl_int_h); free(repl_params_c); + free(repl_rollup_c); } static void test_sim_never_calls_forbidden_symbols(void) @@ -542,6 +550,7 @@ static void test_sim_never_calls_forbidden_symbols(void) char* repl_info_c_raw = read_whole_file(XCE_SIM_REPL_INFO_C_PATH); char* repl_int_h_raw = read_whole_file(XCE_SIM_REPL_INTERNAL_H_PATH); char* repl_params_c_raw = read_whole_file(XCE_SIM_REPL_PARAMS_C_PATH); + char* repl_rollup_c_raw = read_whole_file(XCE_SIM_REPL_ROLLUP_C_PATH); char* h; char* c; char* loop; @@ -553,6 +562,7 @@ static void test_sim_never_calls_forbidden_symbols(void) char* repl_info_c; char* repl_int_h; char* repl_params_c; + char* repl_rollup_c; TEST_ASSERT_NOT_NULL(h_raw); TEST_ASSERT_NOT_NULL(c_raw); @@ -565,6 +575,7 @@ static void test_sim_never_calls_forbidden_symbols(void) TEST_ASSERT_NOT_NULL(repl_info_c_raw); TEST_ASSERT_NOT_NULL(repl_int_h_raw); TEST_ASSERT_NOT_NULL(repl_params_c_raw); + TEST_ASSERT_NOT_NULL(repl_rollup_c_raw); h = strip_c_comments(h_raw); c = strip_c_comments(c_raw); @@ -577,6 +588,7 @@ static void test_sim_never_calls_forbidden_symbols(void) repl_info_c = strip_c_comments(repl_info_c_raw); repl_int_h = strip_c_comments(repl_int_h_raw); repl_params_c = strip_c_comments(repl_params_c_raw); + repl_rollup_c = strip_c_comments(repl_rollup_c_raw); TEST_ASSERT_NOT_NULL(h); TEST_ASSERT_NOT_NULL(c); TEST_ASSERT_NOT_NULL(loop); @@ -588,6 +600,7 @@ static void test_sim_never_calls_forbidden_symbols(void) TEST_ASSERT_NOT_NULL(repl_info_c); TEST_ASSERT_NOT_NULL(repl_int_h); TEST_ASSERT_NOT_NULL(repl_params_c); + TEST_ASSERT_NOT_NULL(repl_rollup_c); assert_no_forbidden_symbols(h, "sim.h"); assert_no_forbidden_symbols(c, "sim.c"); @@ -600,6 +613,7 @@ static void test_sim_never_calls_forbidden_symbols(void) assert_no_forbidden_symbols(repl_info_c, "repl_info.c"); assert_no_forbidden_symbols(repl_int_h, "repl_internal.h"); assert_no_forbidden_symbols(repl_params_c, "repl_params.c"); + assert_no_forbidden_symbols(repl_rollup_c, "repl_rollup.c"); free(h_raw); free(c_raw); @@ -612,6 +626,7 @@ static void test_sim_never_calls_forbidden_symbols(void) free(repl_info_c_raw); free(repl_int_h_raw); free(repl_params_c_raw); + free(repl_rollup_c_raw); free(h); free(c); free(loop); @@ -623,6 +638,7 @@ static void test_sim_never_calls_forbidden_symbols(void) free(repl_info_c); free(repl_int_h); free(repl_params_c); + free(repl_rollup_c); } /* diff --git a/src/scheduler/testsuite/test_sim_reconcile_unaccounted.c b/src/scheduler/testsuite/test_sim_reconcile_unaccounted.c index 8811703c..c01ca5d2 100644 --- a/src/scheduler/testsuite/test_sim_reconcile_unaccounted.c +++ b/src/scheduler/testsuite/test_sim_reconcile_unaccounted.c @@ -88,6 +88,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_record_output.c b/src/scheduler/testsuite/test_sim_record_output.c index 01d29a7e..2c911728 100644 --- a/src/scheduler/testsuite/test_sim_record_output.c +++ b/src/scheduler/testsuite/test_sim_record_output.c @@ -74,6 +74,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_resource_contention.c b/src/scheduler/testsuite/test_sim_resource_contention.c index a7243542..f4362068 100644 --- a/src/scheduler/testsuite/test_sim_resource_contention.c +++ b/src/scheduler/testsuite/test_sim_resource_contention.c @@ -138,6 +138,7 @@ #include "../src/recording_events.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_round_boundary_reconciliation.c b/src/scheduler/testsuite/test_sim_round_boundary_reconciliation.c index 027ba384..223ddda4 100644 --- a/src/scheduler/testsuite/test_sim_round_boundary_reconciliation.c +++ b/src/scheduler/testsuite/test_sim_round_boundary_reconciliation.c @@ -106,6 +106,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_session_ordering.c b/src/scheduler/testsuite/test_sim_session_ordering.c index 8f1a1a21..b92e2f18 100644 --- a/src/scheduler/testsuite/test_sim_session_ordering.c +++ b/src/scheduler/testsuite/test_sim_session_ordering.c @@ -139,6 +139,7 @@ #include "../src/recording_events.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_snapshot_reconcile_gap.c b/src/scheduler/testsuite/test_sim_snapshot_reconcile_gap.c index 6cf1044c..5146db0d 100644 --- a/src/scheduler/testsuite/test_sim_snapshot_reconcile_gap.c +++ b/src/scheduler/testsuite/test_sim_snapshot_reconcile_gap.c @@ -93,6 +93,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c" diff --git a/src/scheduler/testsuite/test_sim_verify.c b/src/scheduler/testsuite/test_sim_verify.c index 17bdf9e3..1801c93e 100644 --- a/src/scheduler/testsuite/test_sim_verify.c +++ b/src/scheduler/testsuite/test_sim_verify.c @@ -94,6 +94,7 @@ #include "../src/recording.c" #include "../src/recording_session.c" #include "../src/repl.c" +#include "../src/repl_rollup.c" #include "../src/repl_break.c" #include "../src/repl_info.c" #include "../src/repl_params.c"