refactor(scheduler-allocator-runner): describe the framework runner, not the removed my_alloc() (task 5.1)
Comments in scheduler sources and tests that presented the deleted my_alloc()/parjob claim helpers as current code now name sched_allocator_run() and its runner helpers; test helpers and tests named after my_alloc are renamed. No logic or expectation changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
65679285ba
commit
d006de3853
12 changed files with 104 additions and 103 deletions
|
|
@ -78,7 +78,7 @@
|
|||
- _Requirements: 1.1, 1.2, 1.5, 1.6, 3.6, 3.7, 5.1, 5.3, 5.5, 7.1_
|
||||
|
||||
- [ ] 5. Validation and closure
|
||||
- [ ] 5.1 Remove stale references to the removed routines
|
||||
- [x] 5.1 Remove stale references to the removed routines
|
||||
- Rewrite comments in both allocator plugins and the simulation allocator bootstrap that describe the removed private routines, so they describe the framework routine
|
||||
- Rewrite testsuite comments that describe current behaviour in terms of the removed routines (host-iterator, simulation limit fan-out, election simulation fixture and parjob end-to-end multi-slot tests); comments that record history may keep the old names
|
||||
- Done when no scheduler source or test comment presents the removed routines as current code, and the suite still passes
|
||||
|
|
|
|||
|
|
@ -408,13 +408,13 @@ extern xce_alloc_t** sched_make_allocs(xce_scheduler_t*, char*, int, int*,
|
|||
* seqjob_allocator.c's pre-rewrap xlist_find() call site -- both now
|
||||
* deleted) so both seqjob_allocator.c and parjob_allocator.c can call this
|
||||
* shared Composition-Algorithm try_alloc leaf directly with real
|
||||
* parameters, instead of each carrying its own private copy. */
|
||||
* parameters, instead of each carrying its own private copy (today its
|
||||
* one allocator caller is the framework routine in alloc_runner.c). */
|
||||
/* scheduler-sim-live-allocation spec, task 2.1 (Core-Safe Allocation
|
||||
* Chain): retyped from xce_scheduler_t* to xce_sched_core_t* -- callers
|
||||
* still owning an xce_scheduler_t* (e.g. seqjob_allocator.c's/parjob_
|
||||
* allocator.c's my_alloc()/parjob_try_plan_(), which derive their own
|
||||
* `sched` from the plugin's separate, untouched xce_sched_plugin_t.sched
|
||||
* field) pass &(sched->core); both xce_scheduler_t and
|
||||
* still owning an xce_scheduler_t* pass &(sched->core) (the framework
|
||||
* routine sched_allocator_run(), alloc_runner.c, instead passes the
|
||||
* plugin's own `core` field straight through); both xce_scheduler_t and
|
||||
* xce_sched_sim_driver_t embed xce_sched_core_t core as their first-class
|
||||
* field, so either driver's own core state satisfies this signature
|
||||
* identically. */
|
||||
|
|
|
|||
|
|
@ -162,8 +162,8 @@ sched_primary_cache_obj_(xce_sched_ctx_t* ctx,
|
|||
* every allocator-exhaustion path already uses to create/populate a pend
|
||||
* reason (make_pendreason() + add_job_preason(), never a direct calloc()/
|
||||
* field write -- see preason.h/preason.c and e.g. resource.c's
|
||||
* sched_try_alloc_on_host_() or seqjob_allocator.c's/parjob_allocator.c's
|
||||
* my_alloc(), all of which follow this exact "if (ctx->reason == NULL) {
|
||||
* sched_try_alloc_on_host_() or alloc_runner.c's sched_allocator_run(),
|
||||
* all of which follow this exact "if (ctx->reason == NULL) {
|
||||
* ctx->reason = make_pendreason(0); }" pattern). add_job_preason(reasons,
|
||||
* code, NULL, NULL) is that same function's own "set main reason" branch
|
||||
* (preason.c) -- the identical call shape design.md's cache_insert()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
* needed a genuine xce_scheduler_t*. Because that registration path
|
||||
* (plugin_register()) also sets the plugin instance's own `core` field
|
||||
* (task 1.2) to `&(wrapper.core)`, every later prepare_allocation_hook
|
||||
* fan-out reached during a real dispatch attempt (my_alloc() ->
|
||||
* fan-out reached during a real dispatch attempt (then my_alloc() ->
|
||||
* sched_try_alloc_on_host_() -> plugin_prepare_allocation(), resource.c/
|
||||
* plugin.c) iterated the WRAPPER's own separate core->plugins registry --
|
||||
* which held only the allocator plugin itself -- never reaching a plugin
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
*
|
||||
* ── The fix (task 4.3) ────────────────────────────────────────────────────
|
||||
* seqjob_allocator_init()/parjob_allocator_init() (and every runtime hook
|
||||
* these plugins register -- seqjob_prepare_allocation()/my_alloc(),
|
||||
* parjob_prepare_allocation()/my_alloc()/parjob_try_plan_()) now read the
|
||||
* these plugins register, plus the framework routine sched_allocator_run()
|
||||
* in alloc_runner.c that both allocate through today) read the
|
||||
* plugin's own honestly-typed `core` field (task 1.2) instead of deriving
|
||||
* an `xce_scheduler_t*` from `plugin->sched` -- mirroring task 2.3's
|
||||
* plugins/limit.c migration exactly. `core` is set by BOTH registration
|
||||
|
|
@ -59,14 +59,14 @@
|
|||
* separate wrapper registry stands in for the fan-out anymore.
|
||||
*
|
||||
* A narrow exception remains, by necessity, not oversight:
|
||||
* seqjob_allocator.c's/parjob_allocator.c's own my_alloc() still calls
|
||||
* the framework routine sched_allocator_run() (alloc_runner.c) still calls
|
||||
* sched_make_allocs() (scheduler.c, out of this task's file boundary) to
|
||||
* build the final xce_alloc_t records for the winning host -- a pre-
|
||||
* existing, real dependency this task did not introduce and cannot retype
|
||||
* (scheduler.c is off-limits). sched_make_allocs()'s own body only ever
|
||||
* reads `sched->core.resmgr` (to resolve a resource idx to its name) and
|
||||
* calls sched_get_id(sched) (`sched->core.lock`/`.nextid`, a fresh
|
||||
* allocation-id counter) -- both my_alloc()'s own honest `core` parameter
|
||||
* allocation-id counter) -- both the runner's own honest `core` argument
|
||||
* AND this narrow legacy need are satisfied by keeping a small,
|
||||
* long-lived throwaway `xce_scheduler_t` wrapper (bug-1884: only `lock`,
|
||||
* `nextid` and `resmgr` are set up -- a full xce_sched_core_init() here
|
||||
|
|
@ -172,7 +172,7 @@ void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim)
|
|||
|
||||
/* plugin->sched: deliberately set AFTER registration -- init_fn no
|
||||
* longer reads it (see seqjob_allocator_init()). Narrow, remaining use:
|
||||
* my_alloc()'s own sched_make_allocs() calls only (never the plugin
|
||||
* sched_allocator_run()'s sched_make_allocs() calls only (never the plugin
|
||||
* registry/fan-out path fixed above). */
|
||||
plugin->sched = wrapper;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1795,8 +1795,8 @@ sched_alloc_runner_result_test = executable(
|
|||
install: false)
|
||||
|
||||
# Task 3.2 (scheduler-allocation spec, Req 9.1): the dedicated pre/post-
|
||||
# rewrap host-selection EQUIVALENCE proof for seqjob_allocator.c's
|
||||
# my_alloc() -- fixture states task 3.1's own smoke test does not cover
|
||||
# rewrap host-selection EQUIVALENCE proof for seqjob allocation (today via
|
||||
# sched_allocator_run()) -- fixture states task 3.1's smoke test does not cover
|
||||
# (multiple candidate hosts with only one resource-satisfying, a host
|
||||
# failing the select filter specifically despite abundant resources,
|
||||
# iteration-order sensitivity across two equally-valid hosts, and a
|
||||
|
|
@ -1817,14 +1817,14 @@ sched_seqjob_rewrap_equivalence_test = executable(
|
|||
# ceil/floor partition per host-count, descending bucket order within
|
||||
# each plan, a stable exhaustion signal, and a real pthread_testcancel()
|
||||
# cancellation point. White-box #include of
|
||||
# ../src/plugins/parjob_allocator.c itself (the file under test) --
|
||||
# simpler than sched_seqjob_allocator_test's own white-box stack since
|
||||
# parjob_allocator.c's still-stubbed my_alloc()/parjob_prepare_allocation()
|
||||
# bodies (untouched by this task -- task 4.2's job) make no calls into
|
||||
# core.c/resource.c/schedobj.c/host_iter.c at all, so none of those need
|
||||
# to be pulled in here. Only my_alloc()/prepare_allocation() themselves
|
||||
# are never called by this file's tests -- they exercise
|
||||
# parjob_plan_iter_init()/_next()/_fini() directly.
|
||||
# ../src/plugins/parjob_allocator.c itself (the file under test). Task 4.2
|
||||
# added the per-bucket allocation loop tests, which pull in core.c/
|
||||
# resource.c/schedobj.c/host_iter.c the same way
|
||||
# sched_seqjob_allocator_test does; since scheduler-allocator-runner task
|
||||
# 4.1 that loop is the framework routine sched_allocator_run(), so
|
||||
# ../src/alloc_runner.c is white-box included too. Task 4.1's own tests
|
||||
# still exercise parjob_plan_iter_init()/_next()/_fini() directly
|
||||
# (see the file's header comment).
|
||||
sched_parjob_combinatorial_test = executable(
|
||||
'sched_parjob_combinatorial_test',
|
||||
['test_parjob_combinatorial.c'],
|
||||
|
|
@ -2096,7 +2096,7 @@ test('scheduler cache dispatch compound test',
|
|||
# maxTasks>1 parallel job through the full production dispatch path
|
||||
# (sched_init()'s real, live sched_allocator() thread -> the real, `static`
|
||||
# sched_make_allocation()/sched_make_primary_alloc_() choke point -> the
|
||||
# real parjob_allocator.c my_alloc() -> the real host_iter.c host iterator
|
||||
# real sched_allocator_run() (parjob's entry) -> the real host_iter.c host iterator
|
||||
# -> a real multi-host xce_job_alloc_t commit), asserting the resulting
|
||||
# job->allocs/decision->u.alloc spans exactly 2 hosts with the correct
|
||||
# per-host slot counts. Same real-scheduler_srcs link technique as
|
||||
|
|
|
|||
|
|
@ -624,8 +624,8 @@ static void test_init_rejects_missing_ctx(void)
|
|||
* scheduler-sim-live-allocation spec, task 2.1 (Core-Safe Allocation
|
||||
* Chain): sched_try_alloc_on_host_() (resource.c) -- the per-host
|
||||
* allocation-attempt leaf that both host_iter.c's own capacity checks
|
||||
* ultimately mirror and that parjob_allocator.c's/seqjob_allocator.c's
|
||||
* my_alloc() call once per candidate -- is now core-typed. This drives it
|
||||
* ultimately mirror and that the framework routine sched_allocator_run()
|
||||
* calls once per candidate -- is now core-typed. This drives it
|
||||
* end to end (real sched_ctx_get_uncomit_host()/sched_check_host_satisfy(),
|
||||
* schedobj.c+resource.c, this file's own plugin_prepare_allocation() no-op
|
||||
* stub above) against BOTH a normal-mode-shaped (xce_scheduler_t) and a
|
||||
|
|
@ -659,10 +659,10 @@ static int try_alloc_once(xce_sched_core_t* core, xce_sched_worker_t* w,
|
|||
|
||||
/* sched_try_alloc_on_host_()'s resource-unmet branch assumes
|
||||
* ctx->reason already exists (unlike its select-mismatch branch, which
|
||||
* lazily creates one) -- my_alloc() always creates one before ever
|
||||
* lazily creates one) -- the runner always creates one before ever
|
||||
* reaching this leaf in production; this test calls the leaf directly,
|
||||
* bypassing that step, so it must set one up itself. Same pattern
|
||||
* test_parjob_combinatorial.c's own direct parjob_try_plan_() call
|
||||
* test_parjob_combinatorial.c's own direct sched_try_plan_() call
|
||||
* already established for the identical reason. */
|
||||
ctx.reason = make_pendreason(0);
|
||||
TEST_ASSERT_NOT_NULL(ctx.reason);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
* test_parjob_combinatorial.c - tasks 4.1 + 4.2 (scheduler-allocation
|
||||
* spec): unit tests for parjob_allocator.c's REAL combinatorial
|
||||
* xce_alloc_plan_iter_t implementation (Req 2 AC 1-6, Req 4 AC 1) AND
|
||||
* (task 4.2, this pass) the real per-bucket allocation loop
|
||||
* (my_alloc()/parjob_try_plan_()/parjob_prepare_allocation(), Req 4 AC
|
||||
* 2/4/5/6/7).
|
||||
* (task 4.2) the real per-bucket allocation loop (then my_alloc()/
|
||||
* parjob_try_plan_(); today sched_allocator_run()/sched_try_plan_() in
|
||||
* alloc_runner.c, plus parjob_prepare_allocation(), Req 4 AC 2/4/5/6/7).
|
||||
*
|
||||
* Task 4.1's own tests below never call my_alloc() -- they drive
|
||||
* Task 4.1's own tests below never call the allocator -- they drive
|
||||
* parjob_plan_iter_init()/_next()/_fini() (static, hence the white-box
|
||||
* #include) directly, and needed no fixture beyond a bare
|
||||
* xce_primary_resreq_t, since the pre-4.2 my_alloc()/parjob_prepare_
|
||||
|
|
@ -49,11 +49,11 @@
|
|||
* test_host_iter.c already established for host_iter_next().
|
||||
*
|
||||
* Covers (task 4.2, new):
|
||||
* - multi-bucket success through the real my_alloc() end to end (Req
|
||||
* - multi-bucket success through the real runner end to end (Req
|
||||
* 4 AC 2/AC 3), including per-bucket resource want scaling with that
|
||||
* bucket's own slot count, not a fixed value (Req 4 AC 5/AC 6)
|
||||
* - the descending-vs-ascending worked example from requirements.md's
|
||||
* Composition Algorithm, driven directly through parjob_try_plan_()
|
||||
* Composition Algorithm, driven directly through sched_try_plan_()
|
||||
* with a hand-built plan for each order against the identical host
|
||||
* pool (Req 4 AC 2)
|
||||
* - a mid-plan bucket failure correctly reversing the earlier
|
||||
|
|
@ -103,8 +103,8 @@
|
|||
/* plugin_register()/plugin_unregister() are referenced by
|
||||
* register_parjob_allocator() (parjob_allocator.c) and core.c
|
||||
* respectively, but no test below calls register_parjob_allocator() --
|
||||
* the plan iterator and my_alloc()/parjob_try_plan_() are exercised
|
||||
* directly. Never actually invoked by anything this file's tests
|
||||
* the plan iterator and sched_allocator_run()/sched_try_plan_() are
|
||||
* exercised directly. Never invoked by anything this file's tests
|
||||
* exercise; provided only so the TU links. */
|
||||
int plugin_register(void* sched, void* plugin)
|
||||
{
|
||||
|
|
@ -177,7 +177,7 @@ int plugin_job_rusage_update(void* s, xce_sched_job_t* j, xce_job_rusages_t* r)
|
|||
}
|
||||
|
||||
/* Avoids white-box-including the rest of scheduler.c just to build the
|
||||
* leaf xce_alloc_t records my_alloc()'s success path constructs -- same
|
||||
* leaf xce_alloc_t records the runner's success path constructs -- same
|
||||
* rationale/shape as test_seqjob_allocator.c's identical stub. This
|
||||
* file's own quantitative per-host assertions go through
|
||||
* assert_uncommitted_host_debit() (real ctx->uncomitted state, untouched
|
||||
|
|
@ -310,7 +310,7 @@ static void init_primary_obj(xce_sched_obj_t* obj,
|
|||
obj->u.primary = primary_obj;
|
||||
}
|
||||
|
||||
/* drive_my_alloc - the exact production sequence a job's allocation
|
||||
/* drive_allocator - the exact production sequence a job's allocation
|
||||
* attempt runs: sched_ctx_init() -> sched_ctx_set_primary() (the real
|
||||
* call that stages ctx->alloc_req.shared via plugin_prepare_allocation()'s
|
||||
* ctx->worker==NULL branch, exactly as sched_make_primary_allocation()
|
||||
|
|
@ -318,8 +318,8 @@ static void init_primary_obj(xce_sched_obj_t* obj,
|
|||
* sched_allocator_run(). Returns its return code; ctx is left
|
||||
* initialized (caller must sched_ctx_fini()). Identical to
|
||||
* test_seqjob_rewrap_equivalence.c's own helper. */
|
||||
static int drive_my_alloc(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
||||
xce_primary_resreq_t* primary, xce_sched_ctx_t* ctx)
|
||||
static int drive_allocator(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
||||
xce_primary_resreq_t* primary, xce_sched_ctx_t* ctx)
|
||||
{
|
||||
xce_sched_plugin_t plugin;
|
||||
|
||||
|
|
@ -665,7 +665,7 @@ static void test_next_has_a_real_cancellation_point(void)
|
|||
|
||||
/*
|
||||
* Req 4 AC 2/AC 3/AC 5/AC 6: a real multi-bucket plan, driven end to end
|
||||
* through the real my_alloc() (not parjob_try_plan_() directly). Two
|
||||
* through the real sched_allocator_run() (not sched_try_plan_()). Two
|
||||
* hosts are engineered so the outcome is deterministic REGARDLESS of
|
||||
* sched->core.workers' own hash-based iteration order: host-A has exactly
|
||||
* 2 free slots (only it can satisfy a "need 2" bucket -- host-B's 1 free
|
||||
|
|
@ -679,7 +679,7 @@ static void test_next_has_a_real_cancellation_point(void)
|
|||
* fixed-value bug would either allocate nothing or debit the wrong
|
||||
* amount, and assert_uncommitted_host_debit() below would catch either.
|
||||
*/
|
||||
static void test_multi_bucket_plan_succeeds_through_real_my_alloc(void)
|
||||
static void test_multi_bucket_plan_succeeds_through_real_runner(void)
|
||||
{
|
||||
xce_scheduler_t sched;
|
||||
xce_resource_t* slots_res;
|
||||
|
|
@ -712,7 +712,7 @@ static void test_multi_bucket_plan_succeeds_through_real_my_alloc(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -749,7 +749,7 @@ static void test_multi_bucket_plan_succeeds_through_real_my_alloc(void)
|
|||
* onto the job whatever the rc). ASAN catches a double free or use after
|
||||
* free on the cleanup path.
|
||||
*/
|
||||
static void test_my_alloc_reports_enomem_when_allocs_cannot_be_built(void)
|
||||
static void test_allocator_reports_enomem_when_allocs_cannot_be_built(void)
|
||||
{
|
||||
int fail_at;
|
||||
|
||||
|
|
@ -779,7 +779,7 @@ static void test_my_alloc_reports_enomem_when_allocs_cannot_be_built(void)
|
|||
|
||||
g_make_allocs_calls = 0;
|
||||
g_make_allocs_fail_at = fail_at;
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
g_make_allocs_fail_at = -1;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, rc);
|
||||
|
|
@ -803,13 +803,13 @@ static void test_my_alloc_reports_enomem_when_allocs_cannot_be_built(void)
|
|||
* for a small bucket greedily claims whatever it encounters first that
|
||||
* already satisfies it).
|
||||
*
|
||||
* Driven directly through parjob_try_plan_() (not the real plan
|
||||
* Driven directly through sched_try_plan_() (not the real plan
|
||||
* iterator, which only ever generates descending order) with a
|
||||
* hand-built xce_alloc_plan_t for each order, against the SAME
|
||||
* unmodified host pool (the descending attempt's claims are rolled back
|
||||
* before the ascending attempt runs) -- this is the seam task 4.2's own
|
||||
* bucket-loop factoring (out of my_alloc()) exists to make testable
|
||||
* without reimplementing the loop in the test.
|
||||
* before the ascending attempt runs) -- the seam the runner's
|
||||
* per-plan helper exists to make testable without reimplementing the
|
||||
* loop in the test.
|
||||
*/
|
||||
static void test_descending_bucket_order_succeeds_where_ascending_fails(void)
|
||||
{
|
||||
|
|
@ -993,7 +993,7 @@ test_mid_plan_bucket_failure_rolls_back_before_later_plan_succeeds(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -1035,7 +1035,7 @@ test_mid_plan_bucket_failure_rolls_back_before_later_plan_succeeds(void)
|
|||
|
||||
/*
|
||||
* Req 4 AC 4: when every candidate plan is exhausted without a full
|
||||
* success, my_alloc() returns the same not-satisfied signal (0) the old
|
||||
* success, the runner returns the same not-satisfied signal (0) the old
|
||||
* stub always returned, unconditionally -- pend-reason handling
|
||||
* downstream is unaffected by this task's change.
|
||||
*/
|
||||
|
|
@ -1067,7 +1067,7 @@ static void test_returns_zero_when_every_plan_is_exhausted(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
TEST_ASSERT_NULL(ctx.alloc);
|
||||
|
|
@ -1081,7 +1081,7 @@ static void test_returns_zero_when_every_plan_is_exhausted(void)
|
|||
* many hosts were used." Task 4.2's fixtures only ever used a per-host
|
||||
* ("slots") resource -- this test drives a job carrying BOTH a per-host
|
||||
* resource AND a genuinely job-level/shared (XCE_RESF_GLOBAL) resource
|
||||
* through a real multi-host my_alloc() success and asserts the shared
|
||||
* through a real multi-host runner success and asserts the shared
|
||||
* resource is debited exactly ONCE at the job level, not once per claimed
|
||||
* host/bucket.
|
||||
*
|
||||
|
|
@ -1109,7 +1109,7 @@ static void test_returns_zero_when_every_plan_is_exhausted(void)
|
|||
* by direct dynamic count rather than code inspection alone, that the
|
||||
* job-level (ctx->worker == NULL) prepare pass fires exactly once for this
|
||||
* whole 4-host allocation attempt -- confirming sched_ctx_set_primary()'s
|
||||
* single call site (schedobj.c), not my_alloc()'s plan/bucket loop, is what
|
||||
* single call site (schedobj.c), not the runner's plan/bucket loop, is what
|
||||
* drives it.
|
||||
*/
|
||||
static void test_shared_resource_debited_once_regardless_of_host_count(void)
|
||||
|
|
@ -1170,7 +1170,7 @@ static void test_shared_resource_debited_once_regardless_of_host_count(void)
|
|||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
g_job_level_prepare_calls = 0;
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -1229,8 +1229,8 @@ int main(void)
|
|||
RUN_TEST(test_plan_generation_ignores_core_state);
|
||||
RUN_TEST(test_init_rejects_invalid_input);
|
||||
RUN_TEST(test_next_has_a_real_cancellation_point);
|
||||
RUN_TEST(test_multi_bucket_plan_succeeds_through_real_my_alloc);
|
||||
RUN_TEST(test_my_alloc_reports_enomem_when_allocs_cannot_be_built);
|
||||
RUN_TEST(test_multi_bucket_plan_succeeds_through_real_runner);
|
||||
RUN_TEST(test_allocator_reports_enomem_when_allocs_cannot_be_built);
|
||||
RUN_TEST(test_descending_bucket_order_succeeds_where_ascending_fails);
|
||||
RUN_TEST(
|
||||
test_mid_plan_bucket_failure_rolls_back_before_later_plan_succeeds);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* test_host_iter.c, test_alloc_cache.c, test_seqjob_rewrap_equivalence.c,
|
||||
* test_scheduler_cache_dispatch*.c) is white-box: it either #includes the
|
||||
* unit under test directly, or hand-builds an `xce_sched_ctx_t`/worker set
|
||||
* and calls a plugin's `my_alloc()`/`prepare_allocation_hook` directly. This
|
||||
* and calls the allocator routine/`prepare_allocation_hook` directly. This
|
||||
* file does neither. It links the REAL, whole `scheduler_srcs` object list
|
||||
* (meson.build's `scheduler_deps`) and drives a real job from submission to
|
||||
* a committed allocation through the SAME functions production jobs use:
|
||||
|
|
@ -26,7 +26,8 @@
|
|||
* sched_make_primary_alloc_() [task 5.1's
|
||||
* cache-wrapped choke point] ->
|
||||
* sched_make_parjob_allocation() -> the REAL
|
||||
* parjob_allocator.c my_alloc() -> the REAL
|
||||
* sched_allocator_run() (alloc_runner.c,
|
||||
* parjob's registered entry) -> the REAL
|
||||
* host_iter.c host iterator -> the REAL
|
||||
* resource.c sched_try_alloc_on_host_() ->
|
||||
* a REAL multi-host xce_job_alloc_t commit
|
||||
|
|
@ -135,7 +136,7 @@
|
|||
* 2-host combinatorial split can. This is the same "no host alone
|
||||
* suffices, but two together do" shape task 4.2's own worked example
|
||||
* establishes, now proven through the REAL production dispatch path
|
||||
* instead of a direct parjob_try_plan_() call.
|
||||
* instead of a direct sched_try_plan_() call.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
|
|
|||
|
|
@ -221,13 +221,13 @@ test_sched_election_thread_pair_runs_against_bare_core_fixture(void)
|
|||
* carries no task-count clause. A maxTasks of 0 (not 1) routes
|
||||
* sched_make_primary_alloc_()'s dispatch (scheduler.c) to
|
||||
* sched_make_parjob_allocation() instead of sched_make_seqjob_
|
||||
* allocation() -- and parjob_allocator.c's own my_alloc() deliberately
|
||||
* bails out for maxTasks <= 1 BEFORE ever creating a pend reason (its
|
||||
* own "Bailing out here, before ctx->reason is ever created" comment),
|
||||
* allocation() -- and parjob's acceptance guard (parjob_accepts())
|
||||
* rejects maxTasks <= 1, which sched_allocator_run() checks BEFORE
|
||||
* ever creating a pend reason,
|
||||
* exactly reproducing the "pend reason is NULL" WARN this test is
|
||||
* written to avoid. Set both fields directly so this fixture
|
||||
* deterministically exercises the seqjob path instead, whose own
|
||||
* my_alloc() unconditionally creates a reason at entry. */
|
||||
* deterministically exercises the seqjob path instead, which has no
|
||||
* guard, so the runner always creates a reason for it. */
|
||||
TEST_ASSERT_EQUAL_INT(XCE_RESREQ_PRIMARY, job->schedobj->tag);
|
||||
job->schedobj->u.primary->resreq->minTasks = 1;
|
||||
job->schedobj->u.primary->resreq->maxTasks = 1;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* seqjob_prepare_allocation() (Req 4.6).
|
||||
*
|
||||
* This is the task-3.1-level smoke coverage only -- proving the rewrapped
|
||||
* my_alloc() actually runs end to end through the shared iterators (not
|
||||
* allocator actually runs end to end through the shared iterators (not
|
||||
* just that it compiles) and that the guard closes the fan-out gap Req
|
||||
* 4.6 describes. The exhaustive pre/post-rewrap equivalence proof across
|
||||
* multiple candidate hosts (including a select-filter failure) is task
|
||||
|
|
@ -15,10 +15,10 @@
|
|||
* White-box #include convention: same combination test_host_iter.c (task
|
||||
* 2.1) already established (core.c + resource.c + schedobj.c +
|
||||
* host_iter.c) for a real worker/resmgr/select/availability fixture, plus
|
||||
* ../src/plugins/seqjob_allocator.c itself so this file can call its
|
||||
* `static` my_alloc()/seqjob_prepare_allocation() directly.
|
||||
* ../src/plugins/seqjob_allocator.c and ../src/alloc_runner.c so this file
|
||||
* can call sched_allocator_run()/seqjob_prepare_allocation() directly.
|
||||
*
|
||||
* seqjob_allocator.c's my_alloc() calls the real, exported
|
||||
* The runner, sched_allocator_run(), calls the real, exported
|
||||
* plugin_prepare_allocation() (plugin.c) to (re-)populate
|
||||
* ctx->alloc_req.host per candidate host -- plugin.c itself is NOT
|
||||
* white-box included here (it needs the full plugins kvmgr/registration
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
/* plugin_register()/plugin_unregister() are referenced by
|
||||
* register_seqjob_allocator()/core.c respectively, but this file never
|
||||
* calls register_seqjob_allocator() (it calls my_alloc()/
|
||||
* calls register_seqjob_allocator() (it calls sched_allocator_run()/
|
||||
* seqjob_prepare_allocation() directly, avoiding the full plugins kvmgr
|
||||
* this codebase's real plugin_register() needs) -- never actually
|
||||
* invoked by anything this file's tests exercise. */
|
||||
|
|
@ -129,7 +129,7 @@ int plugin_job_rusage_update(void* s, xce_sched_job_t* j, xce_job_rusages_t* r)
|
|||
/* Link-satisfying stub for sched_make_allocs() (scheduler.c) -- avoids
|
||||
* white-box-including the rest of that 1382-line file (job/queue/picker
|
||||
* machinery unrelated to seqjob_allocator.c) just to build the leaf
|
||||
* xce_alloc_t records my_alloc()'s success path constructs. Returns one
|
||||
* xce_alloc_t records the runner's success path constructs. Returns one
|
||||
* non-NULL, zeroed xce_alloc_t per requested resource index -- sufficient
|
||||
* for this file's assertions, which check WHICH host got allocated and
|
||||
* how many resource entries it carries, not the internal xce_alloc_t
|
||||
|
|
@ -253,14 +253,14 @@ static void init_primary_obj(xce_sched_obj_t* obj,
|
|||
|
||||
/*
|
||||
* Req 9.1: a maxTasks==1 job with one available, matching host is still
|
||||
* allocated correctly through the REWRAPPED my_alloc() -- driven through
|
||||
* allocated correctly through the framework runner -- driven through
|
||||
* the real shared plan_iter -> host_iter composition (seqjob_plan_iter_*,
|
||||
* sched_host_iter_*), not a re-implementation of any of it. Proves the
|
||||
* rewrap actually runs end to end (host selected, resource debited,
|
||||
* ctx->alloc populated), not just that it compiles.
|
||||
*/
|
||||
static void
|
||||
test_my_alloc_allocates_single_matching_host_through_shared_iterators(void)
|
||||
test_allocator_allocates_single_matching_host_through_shared_iterators(void)
|
||||
{
|
||||
xce_scheduler_t sched;
|
||||
xce_resource_t* slots_res;
|
||||
|
|
@ -291,15 +291,14 @@ test_my_alloc_allocates_single_matching_host_through_shared_iterators(void)
|
|||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &(sched.core), &obj));
|
||||
/* Real call -- exercises plugin_prepare_allocation()'s ctx->worker ==
|
||||
* NULL branch exactly as sched_make_primary_allocation() does today,
|
||||
* populating ctx->alloc_req.shared before my_alloc() ever runs. */
|
||||
* populating ctx->alloc_req.shared before the runner ever runs. */
|
||||
sched_ctx_set_primary(&ctx, &primary);
|
||||
|
||||
memset(&plugin, 0, sizeof(plugin));
|
||||
plugin.sched = &sched;
|
||||
/* scheduler-sim-live-allocation spec, task 4.3: my_alloc() now reads
|
||||
* plugin->core (honestly typed, task 1.2) for every core-safe call,
|
||||
* alongside the still-needed plugin->sched (sched_make_allocs(),
|
||||
* scheduler.c, unchanged). */
|
||||
/* the runner reads plugin->core (honestly typed) for every core-safe
|
||||
* call, plugin->sched (sched_make_allocs(), scheduler.c) and seqjob's
|
||||
* allocator contract. */
|
||||
plugin.core = &(sched.core);
|
||||
plugin.allocator_iface = &seqjob_alloc_iface;
|
||||
|
||||
|
|
@ -392,11 +391,11 @@ test_seqjob_prepare_allocation_guards_against_maxtasks_gt_1_fanout(void)
|
|||
|
||||
/*
|
||||
* bug-1882: when the allocation records cannot be built (sched_make_allocs()
|
||||
* returns NULL), my_alloc() must report -ENOMEM and leave ctx->alloc NULL
|
||||
* returns NULL), the runner must report -ENOMEM and leave ctx->alloc NULL
|
||||
* -- sched_make_primary_allocation() moves ctx.alloc onto the job whatever
|
||||
* the rc, so a half-built allocation there would be dispatched.
|
||||
*/
|
||||
static void test_my_alloc_reports_enomem_when_allocs_cannot_be_built(void)
|
||||
static void test_allocator_reports_enomem_when_allocs_cannot_be_built(void)
|
||||
{
|
||||
xce_scheduler_t sched;
|
||||
xce_resource_t* slots_res;
|
||||
|
|
@ -440,9 +439,9 @@ static void test_my_alloc_reports_enomem_when_allocs_cannot_be_built(void)
|
|||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_my_alloc_reports_enomem_when_allocs_cannot_be_built);
|
||||
RUN_TEST(test_allocator_reports_enomem_when_allocs_cannot_be_built);
|
||||
RUN_TEST(
|
||||
test_my_alloc_allocates_single_matching_host_through_shared_iterators);
|
||||
test_allocator_allocates_single_matching_host_through_shared_iterators);
|
||||
RUN_TEST(test_seqjob_prepare_allocation_guards_against_maxtasks_gt_1_fanout);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
* test_seqjob_rewrap_equivalence.c - task 3.2 (scheduler-allocation spec):
|
||||
* the dedicated pre/post-rewrap host-selection EQUIVALENCE proof for
|
||||
* seqjob_allocator.c's my_alloc() (Req 9.1).
|
||||
* seqjob allocation (Req 9.1) -- then seqjob_allocator.c's my_alloc(),
|
||||
* today the framework routine sched_allocator_run() (alloc_runner.c).
|
||||
*
|
||||
* task 3.1's own test_seqjob_allocator.c only proves the rewrapped
|
||||
* my_alloc() still runs end to end through the shared plan_iter/host_iter
|
||||
* allocator still runs end to end through the shared plan_iter/host_iter
|
||||
* composition (a single-obvious-host smoke case) and that the new
|
||||
* maxTasks==1 guard (Req 4.6) works. Req 9.1's actual claim is narrower
|
||||
* and harder to prove: "which host a job lands on, given the same
|
||||
|
|
@ -22,7 +23,7 @@
|
|||
* derives the expected pick from the two well-defined, already-unit-tested
|
||||
* primitives the composition is built from -- sched_meet_host_selection()
|
||||
* and sched_check_host_satisfy() (both resource.c, unmodified by the
|
||||
* rewrap) -- and asserts my_alloc()'s real behavior against that
|
||||
* rewrap) -- and asserts the allocator's real behavior against that
|
||||
* derivation. This is valid because both the old and new code paths are
|
||||
* confirmed (by reading resource.c) to funnel every host decision through
|
||||
* the exact same leaf, sched_try_alloc_on_host_(): pre-rewrap it was
|
||||
|
|
@ -158,7 +159,7 @@ int plugin_job_rusage_update(void* s, xce_sched_job_t* j, xce_job_rusages_t* r)
|
|||
|
||||
/* Same rationale as test_seqjob_allocator.c's identical stub: avoids
|
||||
* white-box-including the rest of scheduler.c just to build the leaf
|
||||
* xce_alloc_t records my_alloc()'s success path constructs. */
|
||||
* xce_alloc_t records the runner's success path constructs. */
|
||||
xce_alloc_t** sched_make_allocs(xce_scheduler_t* sched, char* reserve,
|
||||
int nres, int* idxs, float* vals,
|
||||
int* duration)
|
||||
|
|
@ -303,14 +304,15 @@ static void init_primary_obj(xce_sched_obj_t* obj,
|
|||
obj->u.primary = primary_obj;
|
||||
}
|
||||
|
||||
/* drive_my_alloc - the exact production sequence a job's allocation
|
||||
/* drive_allocator - the exact production sequence a job's allocation
|
||||
* attempt runs: sched_ctx_init() -> sched_ctx_set_primary() (the real
|
||||
* call that stages ctx->alloc_req.shared via plugin_prepare_allocation()'s
|
||||
* ctx->worker==NULL branch, exactly as sched_make_primary_allocation()
|
||||
* does today) -> my_alloc(). Returns my_alloc()'s return code; ctx is left
|
||||
* does today) -> seqjob's registered entry point, the framework routine
|
||||
* sched_allocator_run(). Returns its return code; ctx is left
|
||||
* initialized (caller must sched_ctx_fini()). */
|
||||
static int drive_my_alloc(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
||||
xce_primary_resreq_t* primary, xce_sched_ctx_t* ctx)
|
||||
static int drive_allocator(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
||||
xce_primary_resreq_t* primary, xce_sched_ctx_t* ctx)
|
||||
{
|
||||
xce_sched_plugin_t plugin;
|
||||
|
||||
|
|
@ -321,10 +323,9 @@ static int drive_my_alloc(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
|||
|
||||
memset(&plugin, 0, sizeof(plugin));
|
||||
plugin.sched = sched;
|
||||
/* scheduler-sim-live-allocation spec, task 4.3: my_alloc() now reads
|
||||
* plugin->core (honestly typed, task 1.2) for every core-safe call,
|
||||
* alongside the still-needed plugin->sched (sched_make_allocs(),
|
||||
* scheduler.c, unchanged). */
|
||||
/* the runner reads plugin->core (honestly typed) for every core-safe
|
||||
* call, plugin->sched (sched_make_allocs(), scheduler.c) and seqjob's
|
||||
* allocator contract. */
|
||||
plugin.core = &(sched->core);
|
||||
plugin.allocator_iface = &seqjob_alloc_iface;
|
||||
|
||||
|
|
@ -394,7 +395,7 @@ test_three_hosts_only_resource_satisfying_host_is_chosen_and_debited(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -458,7 +459,7 @@ test_host_failing_select_filter_is_skipped_despite_plenty_of_resources(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -472,7 +473,7 @@ test_host_failing_select_filter_is_skipped_despite_plenty_of_resources(void)
|
|||
|
||||
/*
|
||||
* Req 9.1, fixture 3 (iteration-order sensitivity): two hosts that are
|
||||
* BOTH select-matching and resource-satisfying -- my_alloc() must pick
|
||||
* BOTH select-matching and resource-satisfying -- the allocator must pick
|
||||
* whichever one sched->core.workers' own iteration mechanism visits
|
||||
* FIRST. That mechanism -- iter_make()/iter_next() over the RTTI `var`
|
||||
* sched->core.workers -- is the exact same primitive the deleted
|
||||
|
|
@ -483,7 +484,7 @@ test_host_failing_select_filter_is_skipped_despite_plenty_of_resources(void)
|
|||
* identical pre- and post-rewrap. This test derives that order directly
|
||||
* (an independent iter_make()/iter_next() scan below) rather than
|
||||
* assuming worker-insertion order happens to match it, then asserts
|
||||
* my_alloc()'s pick against the derived value.
|
||||
* the allocator's pick against the derived value.
|
||||
*/
|
||||
static void
|
||||
test_pick_matches_first_host_in_the_shared_workers_iteration_order(void)
|
||||
|
|
@ -526,7 +527,7 @@ test_pick_matches_first_host_in_the_shared_workers_iteration_order(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
@ -585,7 +586,7 @@ test_select_fail_then_resource_fail_then_success_does_not_short_circuit(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
rc = drive_my_alloc(&sched, &obj, &primary, &ctx);
|
||||
rc = drive_allocator(&sched, &obj, &primary, &ctx);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc);
|
||||
TEST_ASSERT_NOT_NULL(ctx.alloc);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
* allocator()'s own init_fn (seqjob_allocator_init()/parjob_allocator_init(),
|
||||
* plugins/seqjob_allocator.c/parjob_allocator.c) still read plugin->sched,
|
||||
* needing a real xce_scheduler_t*. seqjob_allocator.c's/parjob_allocator.c's
|
||||
* own my_alloc() then resolves its plugin-hook fan-out (plugin_prepare_
|
||||
* then-private my_alloc() resolved its plugin-hook fan-out (plugin_prepare_
|
||||
* allocation()) via THAT SAME plugin instance's own plugin->core field, not
|
||||
* the core parameter threaded down from sched_make_allocation() -- so with
|
||||
* plugin->core pointing at the wrapper's own core, the fan-out iterates the
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
* Same technique test_sched_election_sim_fixture.c/test_sim_live_
|
||||
* allocation.c already establish (see those files' own header comments):
|
||||
* links the REAL, unmodified `scheduler_srcs` object list (minus
|
||||
* src/main.c) so my_alloc()'s real fan-out through the real plugin.c/
|
||||
* src/main.c) so the runner's real fan-out through the real plugin.c/
|
||||
* resource.c/plugins/limit.c chain is genuinely exercised, not stubbed.
|
||||
*
|
||||
* ── Fixture shape ──────────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue