fix(scheduler): --sim-verify false-flagged every DISPATCH decision on wall-clock drift (bug-1842)
sim_verify_alloc_eq() compared xce_alloc_t.from, which make_alloc() (xcealloc.c) stamps with the real OS wall clock (time(NULL)), not core.c's virtualized sim clock. The recorded (expected) value is whatever real second the original run happened to execute in; the freshly-rebuilt (actual) value is whatever real second the replay executes in -- two unrelated real-world timestamps, so every otherwise-correct DISPATCH decision failed verification whenever a replay ran even one wall-clock second away from its own recording. Drop `from` from the comparison -- it's reservation bookkeeping, not part of a decision's semantic identity. Verified against a real captured .replay file: 120/120 false DISPATCH mismatches -> 0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
e592e92178
commit
7901db57d4
4 changed files with 126 additions and 8 deletions
|
|
@ -93,6 +93,22 @@ static int sim_verify_str_eq(const char* a, const char* b)
|
|||
* plain `==`: both sides are exact copies (decode/construction, no
|
||||
* arithmetic in between) of the same double, so bit-exact comparison is
|
||||
* correct here, not the usual floating-point-tolerance concern.
|
||||
*
|
||||
* `from` is DELIBERATELY excluded (bug-1838-followup): make_alloc()
|
||||
* (xcealloc.c) unconditionally stamps it with time(NULL), the real OS wall
|
||||
* clock, not core.c's virtualized sim clock. `expected->from` is whatever
|
||||
* real second the ORIGINAL recording happened to run in; `actual->from` is
|
||||
* whatever real second THIS replay happens to run in -- two independent
|
||||
* real-world timestamps with no reason to agree, even though the decision
|
||||
* they're attached to is semantically identical (same job, same host, same
|
||||
* resource, same amount). Comparing them made every genuinely-correct live
|
||||
* DISPATCH decision report a false --sim-verify MISMATCH whenever a replay
|
||||
* runs so much as one wall-clock second away from its own recording --
|
||||
* i.e. essentially always, for any replay of a real, non-synthetic
|
||||
* recording. `from` is reservation bookkeeping (when this grant started, for
|
||||
* expiry/accounting purposes), not part of the decision's own identity --
|
||||
* unlike `duration`, which IS a deterministic, request-derived value and
|
||||
* stays part of this comparison.
|
||||
*/
|
||||
static int sim_verify_alloc_eq(const xce_alloc_t* a, const xce_alloc_t* b)
|
||||
{
|
||||
|
|
@ -104,7 +120,7 @@ static int sim_verify_alloc_eq(const xce_alloc_t* a, const xce_alloc_t* b)
|
|||
}
|
||||
|
||||
return (a->instid == b->instid) && (a->value == b->value)
|
||||
&& (a->from == b->from) && (a->duration == b->duration)
|
||||
&& (a->duration == b->duration)
|
||||
&& sim_verify_str_eq(a->resname, b->resname)
|
||||
&& sim_verify_str_eq(a->reserve, b->reserve);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -713,13 +713,15 @@ test_sim_verify_no_false_mismatch_after_live_dispatch_and_later_confirmation(
|
|||
* sched_make_allocs() (scheduler.c) always defaults every entry's
|
||||
* duration to -1 today.
|
||||
* `from` (wall-clock time(NULL), set unconditionally by make_alloc()
|
||||
* itself) is NOT independently reproduced here -- it is expected to
|
||||
* agree with the live path's own call by virtue of both happening
|
||||
* within the same sub-second test execution window, not by
|
||||
* construction; this is a real, if practically negligible, source of
|
||||
* flakiness inherent to comparing a genuinely-live-dispatched
|
||||
* decision's wall-clock-stamped fields via --sim-verify, orthogonal
|
||||
* to anything bug-1838 changed. */
|
||||
* itself) is left at whatever value make_alloc() happens to stamp it
|
||||
* with here -- it no longer needs to agree with the live path's own
|
||||
* call. bug-1838-followup removed `from` from sim_verify_alloc_eq()'s
|
||||
* comparison entirely (sim_verify.c): it is a real-wall-clock
|
||||
* reservation-start stamp, not part of a decision's semantic identity,
|
||||
* and comparing it made --sim-verify false-flag every genuine
|
||||
* live-dispatched decision replayed more than a wall-clock second away
|
||||
* from its own recording. What used to be accepted same-second-window
|
||||
* flakiness here is now a non-issue by construction. */
|
||||
{
|
||||
xce_alloc_t* a = make_alloc((char*)"slots", NULL, 1, 1.0,
|
||||
-1);
|
||||
|
|
|
|||
|
|
@ -624,6 +624,41 @@ static void test_dispatch_decisions_differing_resource_value_mismatch(void)
|
|||
"PASS\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* test_dispatch_decisions_differing_from_timestamp_still_match -
|
||||
* bug-1838-followup regression: `from` (xce_alloc_t's wall-clock reservation-
|
||||
* start stamp, set unconditionally by make_alloc() via time(NULL) --
|
||||
* xcealloc.c) is real-OS-clock-derived, not part of a decision's semantic
|
||||
* identity. `expected`'s `from` is whatever second the ORIGINAL recording
|
||||
* ran in; `actual`'s is whatever second THIS run rebuilds the allocation in
|
||||
* -- two independent real-world timestamps that will essentially never
|
||||
* agree for any replay of a real recording, even when the decision itself
|
||||
* (job/host/resource/value/duration) is byte-for-byte the one that was
|
||||
* recorded. Uses two `from` values far enough apart (a Unix-epoch-plausible
|
||||
* value vs. 1) that they could never coincidentally collide, proving this
|
||||
* is deliberate exclusion, not a fluke of nearby clock reads.
|
||||
*/
|
||||
static void test_dispatch_decisions_differing_from_timestamp_still_match(void)
|
||||
{
|
||||
xce_alloc_t* res_a[1]
|
||||
= { make_test_alloc("gpu", "resv1", 1, 2.0, 1790000000ULL, 1800) };
|
||||
xce_host_alloc_t* host_a[1] = { make_test_host_alloc("hostA", res_a, 1) };
|
||||
xce_job_alloc_t* expected_alloc = make_test_job_alloc(42, host_a, 1);
|
||||
|
||||
xce_alloc_t* res_b[1] = { make_test_alloc("gpu", "resv1", 1, 2.0, 1ULL,
|
||||
1800) };
|
||||
xce_host_alloc_t* host_b[1] = { make_test_host_alloc("hostA", res_b, 1) };
|
||||
xce_job_alloc_t* actual_alloc = make_test_job_alloc(42, host_b, 1);
|
||||
|
||||
replay_decision_t expected = make_replay_dispatch_decision(expected_alloc);
|
||||
xce_decision_t* actual = make_dispatch_decision(actual_alloc);
|
||||
|
||||
TEST_ASSERT_TRUE(sim_decision_eq(&expected, actual));
|
||||
|
||||
printf("test_dispatch_decisions_differing_from_timestamp_still_match: "
|
||||
"PASS\n");
|
||||
}
|
||||
|
||||
static void test_pend_decisions_with_identical_content_match(void)
|
||||
{
|
||||
replay_decision_t expected = make_replay_pend_decision(9001ULL, 3);
|
||||
|
|
@ -1748,6 +1783,7 @@ int main(void)
|
|||
RUN_TEST(test_dispatch_decisions_differing_jobid_mismatch);
|
||||
RUN_TEST(test_dispatch_decisions_differing_host_mismatch);
|
||||
RUN_TEST(test_dispatch_decisions_differing_resource_value_mismatch);
|
||||
RUN_TEST(test_dispatch_decisions_differing_from_timestamp_still_match);
|
||||
RUN_TEST(test_pend_decisions_with_identical_content_match);
|
||||
RUN_TEST(test_pend_decisions_differing_jobid_mismatch);
|
||||
RUN_TEST(test_pend_decisions_differing_main_reason_mismatch);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue