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:
Rongsong Shen 2026-09-30 10:02:46 +00:00
parent 65679285ba
commit d006de3853
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
12 changed files with 104 additions and 103 deletions

View file

@ -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

View file

@ -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. */

View file

@ -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()

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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>

View file

@ -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;

View file

@ -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();
}

View file

@ -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);

View file

@ -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 ──────────────────────────────────────────────────────