fix(scheduler): apply a mid-replay CONFIG_PUSH to the sim limit plugin (bug-1964)
Cause: live applies every pushed config through sched_init_config(), whose plugin_config_update() runs each plugin's config_hook (the limit plugin builds its limits there). The simulator seeded the limit plugin only at bootstrap (sim_bootstrap_limit_plugin()); the core's CONFIG_PUSH event loaded groups, resources and queues but never told the plugins, so a limit added during a replay never existed in sim. Fix: one shared fan-out, plugin_config_update_core(core, config), which live's plugin_config_update() now delegates to. The core's CONFIG_PUSH calls a driver-registered xce_core_config_cb_t after loading groups (live order), keeping the core free of plugin.c; the simulator registers the fan-out in sim_bootstrap_limit_plugin(). limit_update_config() reads the honestly-typed plugin->core instead of casting plugin->sched, so the hook is safe on the sim core; the hand-built plugin fixtures in test_limit_plugin.c/test_repl_limit_table.c now set plugin->core as plugin_register() does. test_sim_limit_config_push_parity.c covers it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2cd02cdc8c
commit
3224e90683
13 changed files with 452 additions and 7 deletions
|
|
@ -89,6 +89,21 @@ typedef int (*xce_core_decision_cb_t)(void*, xce_decision_t*);
|
|||
*/
|
||||
typedef void (*xce_core_cache_clear_cb_t)(xce_sched_core_t*);
|
||||
|
||||
/*
|
||||
* xce_core_config_cb_t - driver-registered plugin config hook (bug-1964):
|
||||
* called by the core's CONFIG_PUSH event (core_events.c) with the pushed
|
||||
* config, after the config's named groups are loaded and before its
|
||||
* resources and queues are applied -- the order live's sched_init_config()
|
||||
* (scheduler.c) uses. Both drivers hand a pushed config to every
|
||||
* registered plugin's config_hook through the one plugin.c fan-out,
|
||||
* plugin_config_update_core(): live calls it from sched_init_config(), the
|
||||
* simulator registers it here (sim_bootstrap_limit_plugin(), sim_limit.c),
|
||||
* so a limit added mid-replay reaches the limit plugin as it does live. A
|
||||
* hook rather than a direct call keeps the core free of plugin.c; NULL
|
||||
* (the default) means "no plugin to tell".
|
||||
*/
|
||||
typedef int (*xce_core_config_cb_t)(xce_sched_core_t*, xce_conf4sched_t*);
|
||||
|
||||
/*
|
||||
* xce_unsatisfiable_lookup_cb_t / xce_unsatisfiable_populate_cb_t -
|
||||
* driver-registered, OPTIONAL unsatisfiable-resreq cache consult/populate
|
||||
|
|
@ -197,6 +212,10 @@ struct xce_sched_core_s {
|
|||
* xce_core_cache_clear_cb_t above. NULL until a driver registers one
|
||||
* (xce_core_set_cache_clear_cb()). */
|
||||
xce_core_cache_clear_cb_t cache_clear_cb;
|
||||
/* bug-1964: plugin config hook for the CONFIG_PUSH event -- see
|
||||
* xce_core_config_cb_t above. NULL until a driver registers one
|
||||
* (xce_core_set_config_cb()). */
|
||||
xce_core_config_cb_t config_cb;
|
||||
/* Req 5.2 (scheduler-sim-live-allocation spec, task 1.1): the
|
||||
* unsatisfiable-resreq cache consult/populate seam -- see
|
||||
* xce_unsatisfiable_lookup_cb_t above. NULL until a driver registers
|
||||
|
|
@ -621,6 +640,13 @@ extern int xce_core_set_decision_cb(xce_sched_core_t*, xce_core_decision_cb_t,
|
|||
extern int xce_core_set_cache_clear_cb(xce_sched_core_t*,
|
||||
xce_core_cache_clear_cb_t);
|
||||
|
||||
/*
|
||||
* xce_core_set_config_cb - registers the driver's plugin config hook for
|
||||
* the CONFIG_PUSH event (bug-1964; see xce_core_config_cb_t). Same calling
|
||||
* convention as xce_core_set_cache_clear_cb() above; NULL unregisters.
|
||||
*/
|
||||
extern int xce_core_set_config_cb(xce_sched_core_t*, xce_core_config_cb_t);
|
||||
|
||||
/*
|
||||
* xce_core_begin_session / xce_core_signal_go - Req 5 AC 5 (task 4.4) split
|
||||
* into two exported halves (task 5.2, Req 1 AC 7 / Req 5 AC 9) so a driver
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ typedef struct {
|
|||
extern int plugin_register(void*, void*);
|
||||
extern void plugin_unregister(void*);
|
||||
extern int plugin_config_update(void*, xce_conf4sched_t*);
|
||||
extern int plugin_config_update_core(xce_sched_core_t*, xce_conf4sched_t*);
|
||||
extern int plugin_queue_update(void*, xce_sched_queue_t*);
|
||||
extern int plugin_job_update(void*, xce_sched_job_t*);
|
||||
extern int plugin_worker_update(void*, xce_sched_worker_t*);
|
||||
|
|
|
|||
|
|
@ -851,6 +851,16 @@ int xce_core_push_events(xce_sched_core_t* core, xce_core_event_t* events,
|
|||
rc);
|
||||
}
|
||||
|
||||
/* bug-1964: then the plugins (the limit plugin builds its
|
||||
* limits from config->limits), as sched_init_config() does */
|
||||
if ((config != NULL) && (core->config_cb != NULL)) {
|
||||
rc = core->config_cb(core, config);
|
||||
if (rc < 0) {
|
||||
WARN("%s CONFIG_PUSH: plugin config update failed rc=%d",
|
||||
__func__, rc);
|
||||
}
|
||||
}
|
||||
|
||||
if (config != NULL) {
|
||||
core_apply_config_resources(core, config);
|
||||
core_apply_config_resvals(core, config);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,22 @@ int xce_core_set_cache_clear_cb(xce_sched_core_t* core,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* xce_core_set_config_cb (bug-1964) - registers the driver-supplied plugin
|
||||
* config hook the CONFIG_PUSH event calls. See core.h's
|
||||
* xce_core_config_cb_t doc comment.
|
||||
*/
|
||||
int xce_core_set_config_cb(xce_sched_core_t* core, xce_core_config_cb_t cb)
|
||||
{
|
||||
if (core == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
core->config_cb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* core_reset_workers - mirrors scheduler.c's sched_reset_workers/
|
||||
* sched_reset_worker_ (release each available worker's stale per-session
|
||||
* host_eval_ctx snapshot + reset its in-use resource values), parameterized
|
||||
|
|
|
|||
|
|
@ -247,14 +247,30 @@ void plugin_unregister(void* arg)
|
|||
int plugin_config_update(void* arg, xce_conf4sched_t* config)
|
||||
{
|
||||
xce_scheduler_t* sched = (xce_scheduler_t*)arg;
|
||||
iterator_t it;
|
||||
int rc;
|
||||
|
||||
if (sched == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = iter_make(&it, sched->core.plugins);
|
||||
return plugin_config_update_core(&(sched->core), config);
|
||||
}
|
||||
|
||||
/*
|
||||
* plugin_config_update_core (bug-1964) - hands `config` to the config_hook
|
||||
* of every plugin registered on `core`. The one fan-out of both drivers:
|
||||
* live reaches it through plugin_config_update() (sched_init_config()),
|
||||
* the simulator through the core's CONFIG_PUSH config_cb (sim_limit.c).
|
||||
*/
|
||||
int plugin_config_update_core(xce_sched_core_t* core, xce_conf4sched_t* config)
|
||||
{
|
||||
iterator_t it;
|
||||
int rc;
|
||||
|
||||
if (core == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = iter_make(&it, core->plugins);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,14 +128,16 @@ static int limit_seed_config_impl(xce_sched_plugin_t* plugin,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* bug-1964: reads plugin->core, set by both plugin_register() and
|
||||
* plugin_register_core(), not a plugin->sched cast -- the simulator runs
|
||||
* this hook too now (plugin_config_update_core() from the core's
|
||||
* CONFIG_PUSH), and its plugins have no xce_scheduler_t behind them. */
|
||||
static int limit_update_config(xce_sched_plugin_t* plugin,
|
||||
xce_conf4sched_t* config)
|
||||
{
|
||||
xce_scheduler_t* sched = (xce_scheduler_t*)plugin->sched;
|
||||
|
||||
TRACE("%s ...", __func__);
|
||||
|
||||
return limit_seed_config_impl(plugin, &(sched->core), config);
|
||||
return limit_seed_config_impl(plugin, plugin->core, config);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -140,4 +140,9 @@ void sim_bootstrap_limit_plugin(xce_sched_sim_driver_t* sim)
|
|||
* type-punned alternative was not. */
|
||||
limit_seed_config(plugin, &(sim->core), sim->core.config);
|
||||
}
|
||||
|
||||
/* bug-1964: a later CONFIG_PUSH in the replay reaches the plugins
|
||||
* (this one's config_hook builds the pushed limits) through the same
|
||||
* plugin.c fan-out live's sched_init_config() uses */
|
||||
xce_core_set_config_cb(&(sim->core), plugin_config_update_core);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3135,6 +3135,28 @@ test('scheduler sim group limit parity test',
|
|||
sched_sim_group_limit_parity_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
||||
# bug-1964: a CONFIG_PUSH during a replay reaches the simulator's limit
|
||||
# plugin as the live scheduler's sched_init_config() does. Same
|
||||
# real-scheduler_srcs link technique as above.
|
||||
sched_sim_limit_config_push_parity_test_srcs = [
|
||||
'test_sim_limit_config_push_parity.c']
|
||||
foreach f : scheduler_srcs
|
||||
if f != 'src/main.c'
|
||||
sched_sim_limit_config_push_parity_test_srcs += ['../' + f]
|
||||
endif
|
||||
endforeach
|
||||
|
||||
sched_sim_limit_config_push_parity_test = executable(
|
||||
'sched_sim_limit_config_push_parity_test',
|
||||
sched_sim_limit_config_push_parity_test_srcs,
|
||||
include_directories:[incdir],
|
||||
dependencies: [scheduler_test_deps],
|
||||
install: false)
|
||||
|
||||
test('scheduler sim limit config push parity test',
|
||||
sched_sim_limit_config_push_parity_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
||||
# bug-1944: a job moved to another queue (core JOB_UPDATE event) keeps its
|
||||
# own priority and does not overtake jobs already pending in the target
|
||||
# queue. Same real-scheduler_srcs link technique as above.
|
||||
|
|
|
|||
|
|
@ -129,6 +129,9 @@ static void fixture_init(xce_scheduler_t* sched, xce_sched_plugin_t* plugin)
|
|||
|
||||
memset(plugin, 0, sizeof(*plugin));
|
||||
plugin->sched = sched;
|
||||
/* as plugin_register() sets it; limit_update_config() reads it
|
||||
* (bug-1964) */
|
||||
plugin->core = &(sched->core);
|
||||
|
||||
rc = limit_init(plugin);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
|
|
|||
|
|
@ -522,6 +522,9 @@ static void register_limit_plugin(xce_sched_sim_driver_t* sim,
|
|||
memset(plugin, 0, sizeof(*plugin));
|
||||
plugin->name = "xce_sched_limit";
|
||||
plugin->sched = group_sched;
|
||||
/* as plugin_register() sets it; limit_update_config() reads it
|
||||
* (bug-1964) */
|
||||
plugin->core = &(group_sched->core);
|
||||
|
||||
rc = limit_init(plugin);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,12 @@
|
|||
* from a live CONFIG_PUSH). A configPush replay event would therefore
|
||||
* silently never reach the limit plugin in EITHER mode -- not a
|
||||
* sim-mode-specific gap, just not how limit config ever reaches a plugin
|
||||
* post-startup in this codebase today. The REAL mechanism (confirmed by
|
||||
* post-startup in this codebase today. (Update, bug-1964: no longer true.
|
||||
* Live re-applies every pushed config through sched_apply_pending_config()
|
||||
* -> sched_init_config(), and the core's CONFIG_PUSH now reaches the
|
||||
* plugins through the simulator's config_cb, plugin_config_update_core();
|
||||
* test_sim_limit_config_push_parity.c covers that path. This fixture keeps
|
||||
* the snapshot seed.) The REAL mechanism (confirmed by
|
||||
* reading sim_loop.c's sched_sim_driver_run(), sim.c's snapshot-load path,
|
||||
* and sim_limit.c's own header comment) is: a snapshot's `config` field
|
||||
* (SnapshotData.config, a real Conf4Sched capnp field, schema-verified
|
||||
|
|
|
|||
325
src/scheduler/testsuite/test_sim_limit_config_push_parity.c
Normal file
325
src/scheduler/testsuite/test_sim_limit_config_push_parity.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* test_sim_limit_config_push_parity.c - bug-1964: a CONFIG_PUSH that
|
||||
* arrives during a replay must reach the limit plugin in the simulator
|
||||
* exactly as it does in the live scheduler.
|
||||
*
|
||||
* Live applies every pushed config through sched_init_config()
|
||||
* (scheduler.c), whose plugin_config_update() hands it to each plugin's
|
||||
* config_hook -- the limit plugin builds its limits there. The simulator
|
||||
* seeds the limit plugin once, from the replay snapshot's config
|
||||
* (sim_bootstrap_limit_plugin(), sim_limit.c), and applies a later push
|
||||
* through the core's CONFIG_PUSH event (core_events.c).
|
||||
*
|
||||
* Fixture: both drivers start from a config without limits (live: applied
|
||||
* by sched_init_config(); sim: the replay snapshot's config), then receive
|
||||
* a second config that adds a host-scoped limit (live: sched_init_config()
|
||||
* again; sim: a CONFIG_PUSH event through xce_core_push_events(), as
|
||||
* sim_loop.c replays it). One pending job then runs a round. Both drivers
|
||||
* must have the limit configured and must match the job against it (one
|
||||
* usage instance). Limits do not gate admission in this codebase (see
|
||||
* test_sim_contention_limit_driver_parity.c), so the limit plugin's state
|
||||
* is what a replay decides with and what `info limit` shows.
|
||||
*
|
||||
* Fixture technique and safety conventions as in
|
||||
* test_sim_group_limit_parity.c (real scheduler_srcs, real picker/
|
||||
* allocator threads, `static` fixtures, exactly one RUN_TEST()).
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "controller.capnp.h"
|
||||
#include "decision.h"
|
||||
#include "plugin.h"
|
||||
#include "preason.h"
|
||||
#include "resobj.h"
|
||||
#include "sched/types.h"
|
||||
#include "scheduler.h"
|
||||
#include "sim.h"
|
||||
#include "xcelimit.h"
|
||||
#include "xstring.h"
|
||||
|
||||
extern void sim_bootstrap_picker(xce_sched_sim_driver_t* sim);
|
||||
extern void sim_bootstrap_limit_plugin(xce_sched_sim_driver_t* sim);
|
||||
extern void sim_bootstrap_seqjob_allocator(xce_sched_sim_driver_t* sim);
|
||||
extern void sim_bootstrap_parjob_allocator(xce_sched_sim_driver_t* sim);
|
||||
|
||||
#define WORKER_NAME "cfglim_worker"
|
||||
#define QUEUE_NAME "normal"
|
||||
#define TEST_RESREQ ((char*)"select[type==any] rusage[mem=1]")
|
||||
#define LIMIT_RESNAME "cfglim_host_res"
|
||||
#define LIMIT_NAME "cfglim_pushed_limit"
|
||||
#define JOB_USER "user1"
|
||||
#define JOB_ID ((uint64_t)196401ULL)
|
||||
|
||||
void setUp(void) { return; }
|
||||
void tearDown(void) { return; }
|
||||
|
||||
static void register_resources(var resmgr)
|
||||
{
|
||||
xce_resource_t res;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.name = strdup("slots");
|
||||
res.valtype = XCE_VAL_NUMERIC;
|
||||
res.ordtype = XCE_ORD_DECR;
|
||||
res.flags = XCE_RESF_LIMIT | XCE_RESF_CONSUMABLE | XCE_RESF_RELEASE
|
||||
| XCE_RESF_DEFAULT_HOST;
|
||||
TEST_ASSERT_NOT_NULL(makeResource(resmgr, &res));
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.name = strdup(LIMIT_RESNAME);
|
||||
TEST_ASSERT_NOT_NULL(makeResource(resmgr, &res));
|
||||
}
|
||||
|
||||
static void add_worker_resval(xce_sched_worker_t* w, xce_sched_core_t* core,
|
||||
const char* resname, double value)
|
||||
{
|
||||
xce_resource_t* r = NULL;
|
||||
xce_val_t* val = NULL;
|
||||
int rc;
|
||||
|
||||
rc = key_find(core->resmgr, (void*)resname, (void**)&r);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
TEST_ASSERT_NOT_NULL(r);
|
||||
|
||||
val = (xce_val_t*)calloc(1, sizeof(*val));
|
||||
TEST_ASSERT_NOT_NULL(val);
|
||||
val->which = Value_u_fvalue;
|
||||
val->u.fvalue = value;
|
||||
zarray_put(&(w->resvals), r->idx, val);
|
||||
}
|
||||
|
||||
static void populate(xce_sched_core_t* core, xce_scheduler_t* job_wrapper,
|
||||
xce_sched_plugin_t* picker)
|
||||
{
|
||||
xce_sched_queue_t* q = (xce_sched_queue_t*)calloc(1, sizeof(*q));
|
||||
xce_sched_worker_t* w = (xce_sched_worker_t*)calloc(1, sizeof(*w));
|
||||
job_submit_data_t submit;
|
||||
xce_job_t j;
|
||||
xce_sched_job_t* job;
|
||||
int rc;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(q);
|
||||
q->name = makeString(QUEUE_NAME);
|
||||
rc = sched_add_queue(core, q);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
picker->picker_iface->on_queue_update(picker, q);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(w);
|
||||
w->name = strdup(WORKER_NAME);
|
||||
w->idx = -1;
|
||||
zarray_init(&(w->resvals), 128, (zarray_item_killer_t)kill_sched_resval);
|
||||
zarray_init(&(w->resInUse), 128, (zarray_item_killer_t)kill_sched_resval);
|
||||
add_worker_resval(w, core, "slots", 4.0);
|
||||
add_worker_resval(w, core, LIMIT_RESNAME, 1000.0);
|
||||
rc = sched_add_worker(core, w);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
memset(&submit, 0, sizeof(submit));
|
||||
submit.queue = (char*)QUEUE_NAME;
|
||||
submit.user = (char*)JOB_USER;
|
||||
submit.project_name = (char*)"default";
|
||||
submit.resreq = TEST_RESREQ;
|
||||
submit.mintasks = 1;
|
||||
submit.maxtasks = 1;
|
||||
|
||||
memset(&j, 0, sizeof(j));
|
||||
j.jobid = JOB_ID;
|
||||
j.state = JOB_STAT_PEND;
|
||||
j.sub_time = 1000ULL;
|
||||
j.queue_time = 1000ULL;
|
||||
j.submit = &submit;
|
||||
|
||||
job = make_sched_job(job_wrapper, &j);
|
||||
TEST_ASSERT_NOT_NULL(job);
|
||||
job->schedobj->u.primary->resreq->minTasks = 1;
|
||||
job->schedobj->u.primary->resreq->maxTasks = 1;
|
||||
rc = sched_add_job(core, job);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
picker->picker_iface->on_job_push(picker, job);
|
||||
}
|
||||
|
||||
static void run_round(xce_sched_core_t* core)
|
||||
{
|
||||
pthread_t picker_tid;
|
||||
pthread_t allocator_tid;
|
||||
xce_decision_t* d;
|
||||
int rc;
|
||||
|
||||
rc = pthread_create(&picker_tid, NULL, sched_job_picker, core);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
rc = pthread_create(&allocator_tid, NULL, sched_allocator, core);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
rc = xce_core_go(core);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
do {
|
||||
d = NULL;
|
||||
cbuf_get(&(core->decisions), &d);
|
||||
} while (d != NULL);
|
||||
|
||||
rc = xce_core_end_session(core);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
}
|
||||
|
||||
static int count_entries(var handle)
|
||||
{
|
||||
iterator_t it;
|
||||
void* item = NULL;
|
||||
int count = 0;
|
||||
int rc;
|
||||
|
||||
if (handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = iter_make(&it, handle);
|
||||
if (rc < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
rc = iter_next(&it, &item);
|
||||
if ((rc < 0) || (rc == RTTI_ITER_NO_DATA)) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
iter_destroy(&it);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static xce_scheduler_t g_normal;
|
||||
static xce_sched_sim_driver_t g_sim;
|
||||
static xce_scheduler_t g_sim_job_wrapper;
|
||||
|
||||
/* the pushed config: `static`, since no core here is handed a newer one
|
||||
* after it, so it is never freed. The first config each driver gets is
|
||||
* heap-allocated and empty, because applying the pushed one frees it. */
|
||||
static xce_limit_val_t g_limit_val = { .resname = (char*)LIMIT_RESNAME,
|
||||
.percent = 1,
|
||||
.val = 50.0 };
|
||||
static xce_limit_config_t g_limit_cfg = { .name = (char*)LIMIT_NAME,
|
||||
.val = &g_limit_val };
|
||||
static xce_limit_config_t* g_limits[1] = { &g_limit_cfg };
|
||||
|
||||
static xce_conf4sched_t g_pushed_normal;
|
||||
static xce_conf4sched_t g_pushed_sim;
|
||||
|
||||
static void init_pushed_config(xce_conf4sched_t* config)
|
||||
{
|
||||
memset(config, 0, sizeof(*config));
|
||||
config->nlimits = 1;
|
||||
config->limits = g_limits;
|
||||
}
|
||||
|
||||
static xce_conf4sched_t* new_empty_config(void)
|
||||
{
|
||||
xce_conf4sched_t* config = (xce_conf4sched_t*)calloc(1, sizeof(*config));
|
||||
|
||||
TEST_ASSERT_NOT_NULL(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
static void test_config_push_reaches_limit_plugin_in_sim_as_in_live(void)
|
||||
{
|
||||
xce_sched_plugin_t* fcfs_normal = NULL;
|
||||
xce_sched_plugin_t* fcfs_sim = NULL;
|
||||
sched_snapshot_data_t snap;
|
||||
xce_core_event_t ev;
|
||||
int rc;
|
||||
|
||||
init_pushed_config(&g_pushed_normal);
|
||||
init_pushed_config(&g_pushed_sim);
|
||||
|
||||
/* ---- live: both configs applied by sched_init_config() ---- */
|
||||
memset(&g_normal, 0, sizeof(g_normal));
|
||||
rc = xce_sched_core_init(&(g_normal.core));
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
register_resources(g_normal.core.resmgr);
|
||||
|
||||
fcfs_normal = builtin_fcfs_new_plugin();
|
||||
TEST_ASSERT_NOT_NULL(fcfs_normal);
|
||||
rc = plugin_register(&g_normal, fcfs_normal);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
g_normal.core.job_pick_plugin = (char*)"builtin_fcfs";
|
||||
rc = plugin_register(&g_normal, limit_new_plugin());
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
rc = register_seqjob_allocator(&g_normal);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
rc = register_parjob_allocator(&g_normal);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
rc = sched_init_config(&g_normal, new_empty_config());
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
rc = sched_init_config(&g_normal, &g_pushed_normal);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
populate(&(g_normal.core), &g_normal, fcfs_normal);
|
||||
run_round(&(g_normal.core));
|
||||
|
||||
/* ---- sim: the snapshot's config, the bootstrap order of
|
||||
* sim_driver_run_body() (sim_loop.c), then the replayed push ---- */
|
||||
memset(&g_sim, 0, sizeof(g_sim));
|
||||
rc = xce_sched_core_init(&(g_sim.core));
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
register_resources(g_sim.core.resmgr);
|
||||
|
||||
memset(&snap, 0, sizeof(snap));
|
||||
snap.config = new_empty_config();
|
||||
rc = xce_sched_core_load_snapshot(&(g_sim.core), &snap);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
sim_bootstrap_picker(&g_sim);
|
||||
rc = key_find(g_sim.core.plugins, "builtin_fcfs", (void**)&fcfs_sim);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
TEST_ASSERT_NOT_NULL(fcfs_sim);
|
||||
sim_bootstrap_limit_plugin(&g_sim);
|
||||
sim_bootstrap_seqjob_allocator(&g_sim);
|
||||
sim_bootstrap_parjob_allocator(&g_sim);
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = XCE_CORE_EVENT_CONFIG_PUSH;
|
||||
ev.u.config_push.config = &g_pushed_sim;
|
||||
rc = xce_core_push_events(&(g_sim.core), &ev, 1);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
memset(&g_sim_job_wrapper, 0, sizeof(g_sim_job_wrapper));
|
||||
rc = xce_sched_core_init(&(g_sim_job_wrapper.core));
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
g_sim_job_wrapper.core.resmgr = g_sim.core.resmgr;
|
||||
g_sim_job_wrapper.core.workers = g_sim.core.workers;
|
||||
g_sim_job_wrapper.core.queues = g_sim.core.queues;
|
||||
|
||||
populate(&(g_sim.core), &g_sim_job_wrapper, fcfs_sim);
|
||||
run_round(&(g_sim.core));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
1, count_entries(limit_get_configured_limits(&(g_normal.core))),
|
||||
"live: the pushed config's limit must be configured");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
1, count_entries(limit_get_usage_instances(&(g_normal.core))),
|
||||
"live: the pushed limit must match the job");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
1, count_entries(limit_get_configured_limits(&(g_sim.core))),
|
||||
"sim: a CONFIG_PUSH during replay must configure its limit as live "
|
||||
"does");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
1, count_entries(limit_get_usage_instances(&(g_sim.core))),
|
||||
"sim: the pushed limit must match the job as it does live");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_config_push_reaches_limit_plugin_in_sim_as_in_live);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
@ -234,6 +234,17 @@ int limit_seed_config(xce_sched_plugin_t* plugin, xce_sched_core_t* core,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* plugin_config_update_core() (plugin.c, not part of this TU) -- bug-1964:
|
||||
* sim_bootstrap_limit_plugin() registers it as the core's CONFIG_PUSH
|
||||
* config_cb, after the limit plugin is registered -- unreachable here for
|
||||
* the same reason as limit_seed_config() immediately above. */
|
||||
int plugin_config_update_core(xce_sched_core_t* core, xce_conf4sched_t* config)
|
||||
{
|
||||
(void)core;
|
||||
(void)config;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* core_reset_workers()'s (core_session.c) linker dependency -- never
|
||||
* invoked (no worker is ever added here). */
|
||||
void sched_worker_release_host_ctx(xce_sched_worker_t* w) { (void)w; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue