feat(scheduler-sim-live-allocation): thread core state through allocation context and host search (task 2.1)
Retypes xce_sched_ctx_t.sched (sched/types.h) from void* to xce_sched_core_t* outright, and sched_try_alloc_on_host_() (resource.c) to take xce_sched_core_t* directly -- completing what tasks 1.2/1.3 left as temporary &(sched->core) call-site wraps. Removes the two resulting struct-prefix casts entirely (schedobj.c's sched_ctx_set_primary(), host_iter.c's sched_host_iter_next()): both now pass core state through honestly, with no cast. Updates every sched_ctx_init()/sched_try_alloc_on_host_() call site tree-wide (scheduler.c, parjob_allocator.c, seqjob_allocator.c) with zero change to host_iter/parjob/seqjob's own host-iteration/ bucket-construction algorithm. Adds a driver-parity test for sched_try_alloc_on_host_() proving identical grant/deny results from normal-mode-shaped and simulation-mode-shaped core state. Flags (for task 2.3) a confirmed-dead, type-confused write at plugins/limit.c:319 (ctx.sched = plugin->sched) -- never read today, left untouched since limit.c is task 2.3's boundary, not this one's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
This commit is contained in:
parent
55173fca27
commit
d52c78e4be
14 changed files with 229 additions and 54 deletions
|
|
@ -49,6 +49,14 @@
|
|||
#include "sched/alloc_iter.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: sim.h only depends on
|
||||
* core.h (+ stdbool/stdint/stdio, per its own header comment), so it is
|
||||
* safe to pull in here just for xce_sched_sim_driver_t -- needed to build
|
||||
* a simulation-mode-shaped container for the driver-parity test added by
|
||||
* this task (mirrors test.c's own test_core_safe_allocation_chain_driver_
|
||||
* parity(), task 1.3). */
|
||||
#include "sim.h"
|
||||
|
||||
/* Pull in the real xce_sched_core_init()/sched_add_worker() (core.c),
|
||||
* sched_meet_host_selection()/sched_check_host_satisfy()/put_resvals()
|
||||
* (resource.c, the evaluator + availability check under test), the real
|
||||
|
|
@ -178,7 +186,9 @@ static void make_rack_eq_select(xce_select_node_t* resname,
|
|||
static void init_ctx(xce_sched_ctx_t* ctx, xce_scheduler_t* sched,
|
||||
xce_sched_obj_t* obj, xce_primary_resreq_t* primary)
|
||||
{
|
||||
int rc = sched_ctx_init(ctx, sched, obj);
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched->core), not sched. */
|
||||
int rc = sched_ctx_init(ctx, &(sched->core), obj);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
ctx->primary = primary;
|
||||
}
|
||||
|
|
@ -610,6 +620,112 @@ static void test_init_rejects_missing_ctx(void)
|
|||
TEST_ASSERT_EQUAL_INT(-EINVAL, host_iter->init(host_iter, NULL, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* simulation-mode-shaped (xce_sched_sim_driver_t) core container, proving
|
||||
* identical grant/deny results regardless of which driver's core state is
|
||||
* passed in -- mirrors test.c's own
|
||||
* test_core_safe_allocation_chain_driver_parity() (task 1.3) for the one
|
||||
* function that test doesn't itself cover.
|
||||
*
|
||||
* RED (before task 2.1): fails to compile -- sched_try_alloc_on_host_()
|
||||
* still takes xce_scheduler_t*, so passing xce_sched_core_t* directly is
|
||||
* an incompatible-pointer-type error (this toolchain treats
|
||||
* -Wincompatible-pointer-types as fatal, not a warning).
|
||||
*/
|
||||
static int try_alloc_once(xce_sched_core_t* core, xce_sched_worker_t* w,
|
||||
float host_wanted)
|
||||
{
|
||||
xce_sched_ctx_t ctx;
|
||||
xce_sched_obj_t obj;
|
||||
xce_primary_resreq_t primary;
|
||||
int rc;
|
||||
|
||||
memset(&primary, 0, sizeof(primary));
|
||||
primary.minTasks = 1;
|
||||
primary.maxTasks = 1;
|
||||
primary.select = NULL;
|
||||
|
||||
init_primary_obj(&obj);
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, core, &obj));
|
||||
ctx.primary = &primary;
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
* already established for the identical reason. */
|
||||
ctx.reason = make_pendreason(0);
|
||||
TEST_ASSERT_NOT_NULL(ctx.reason);
|
||||
|
||||
set_wanted_slots(&ctx, host_wanted);
|
||||
|
||||
rc = sched_try_alloc_on_host_(w, core, &ctx);
|
||||
|
||||
sched_ctx_fini(&ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
test_try_alloc_on_host_grants_and_denies_identically_for_both_driver_shapes(
|
||||
void)
|
||||
{
|
||||
xce_scheduler_t sched_normal;
|
||||
xce_sched_sim_driver_t sim_shape;
|
||||
xce_sched_core_t* core_normal = &(sched_normal.core);
|
||||
xce_sched_core_t* core_sim = &(sim_shape.core);
|
||||
xce_sched_worker_t* w_normal;
|
||||
xce_sched_worker_t* w_sim;
|
||||
int rc_normal, rc_sim;
|
||||
|
||||
memset(&sched_normal, 0, sizeof(sched_normal));
|
||||
memset(&sim_shape, 0, sizeof(sim_shape));
|
||||
TEST_ASSERT_EQUAL_INT(0, xce_sched_core_init(core_normal));
|
||||
TEST_ASSERT_EQUAL_INT(0, xce_sched_core_init(core_sim));
|
||||
|
||||
add_worker(core_normal, "only", 4.0f, 0.0f, 0.0);
|
||||
add_worker(core_sim, "only", 4.0f, 0.0f, 0.0);
|
||||
|
||||
w_normal = sched_get_worker(core_normal, "only");
|
||||
w_sim = sched_get_worker(core_sim, "only");
|
||||
TEST_ASSERT_NOT_NULL(w_normal);
|
||||
TEST_ASSERT_NOT_NULL(w_sim);
|
||||
|
||||
/* Grant: wants 3 of 4 free slots. */
|
||||
rc_normal = try_alloc_once(core_normal, w_normal, 3.0f);
|
||||
rc_sim = try_alloc_once(core_sim, w_sim, 3.0f);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, rc_normal);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
rc_normal, rc_sim,
|
||||
"sched_try_alloc_on_host_() must grant identically for a "
|
||||
"normal-mode-shaped and a simulation-mode-shaped core");
|
||||
|
||||
/* Deny: wants 8, only 4 free -- the per-ctx uncommitted debit tracked
|
||||
* by the grant above never touches the worker's own resInUse, so this
|
||||
* second, fresh-ctx attempt against the SAME worker still sees all 4
|
||||
* free, exactly like test.c's own driver-parity test reuses one
|
||||
* worker across a grant then a deny sub-case. */
|
||||
rc_normal = try_alloc_once(core_normal, w_normal, 8.0f);
|
||||
rc_sim = try_alloc_once(core_sim, w_sim, 8.0f);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, rc_normal);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
rc_normal, rc_sim,
|
||||
"sched_try_alloc_on_host_() must deny identically for a "
|
||||
"normal-mode-shaped and a simulation-mode-shaped core");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
|
@ -620,5 +736,7 @@ int main(void)
|
|||
test_host_too_small_for_larger_search_remains_candidate_for_smaller_search);
|
||||
RUN_TEST(test_next_has_a_real_cancellation_point);
|
||||
RUN_TEST(test_init_rejects_missing_ctx);
|
||||
RUN_TEST(
|
||||
test_try_alloc_on_host_grants_and_denies_identically_for_both_driver_shapes);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,7 +394,9 @@ test_ctx_init_defaults_alloc_mode_to_normal(void)
|
|||
obj.tag = XCE_RESREQ_PRIMARY;
|
||||
|
||||
xce_sched_ctx_t ctx;
|
||||
int rc = sched_ctx_init(&ctx, &sched, &obj);
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched.core), not &sched. */
|
||||
int rc = sched_ctx_init(&ctx, &(sched.core), &obj);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_ALLOC_NORMAL, ctx.alloc_mode);
|
||||
|
|
|
|||
|
|
@ -304,7 +304,9 @@ static int drive_my_alloc(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
|||
{
|
||||
xce_sched_plugin_t plugin;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(ctx, sched, obj));
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched->core), not sched. */
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(ctx, &(sched->core), obj));
|
||||
sched_ctx_set_primary(ctx, primary);
|
||||
|
||||
memset(&plugin, 0, sizeof(plugin));
|
||||
|
|
@ -790,7 +792,9 @@ static void test_descending_bucket_order_succeeds_where_ascending_fails(void)
|
|||
primary.select = NULL;
|
||||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &sched, &obj));
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched.core), not &sched. */
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &(sched.core), &obj));
|
||||
sched_ctx_set_primary(&ctx, &primary);
|
||||
|
||||
/* my_alloc() always lazily creates ctx->reason before ever reaching
|
||||
|
|
|
|||
|
|
@ -270,7 +270,9 @@ test_my_alloc_allocates_single_matching_host_through_shared_iterators(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &sched, &obj));
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched.core), not &sched. */
|
||||
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. */
|
||||
|
|
@ -325,7 +327,9 @@ test_seqjob_prepare_allocation_guards_against_maxtasks_gt_1_fanout(void)
|
|||
|
||||
init_primary_obj(&obj, &primary_obj, &primary);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &sched, &obj));
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched.core), not &sched. */
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(&ctx, &(sched.core), &obj));
|
||||
ctx.primary = &primary;
|
||||
|
||||
/* Simulate parjob_prepare_allocation() having already staged this
|
||||
|
|
|
|||
|
|
@ -307,7 +307,9 @@ static int drive_my_alloc(xce_scheduler_t* sched, xce_sched_obj_t* obj,
|
|||
{
|
||||
xce_sched_plugin_t plugin;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(ctx, sched, obj));
|
||||
/* scheduler-sim-live-allocation spec, task 2.1: ctx->sched is now
|
||||
* honestly typed xce_sched_core_t* -- pass &(sched->core), not sched. */
|
||||
TEST_ASSERT_EQUAL_INT(0, sched_ctx_init(ctx, &(sched->core), obj));
|
||||
sched_ctx_set_primary(ctx, primary);
|
||||
|
||||
memset(&plugin, 0, sizeof(plugin));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue