fix(scheduler): place a task-range job with the largest count that fits (bug-1931)
The parjob plan generator split only maxTasks, so a job submitted with a task range (minTasks < maxTasks) pended until all maxTasks tasks fit, even when minTasks did (a tasks 2..5 job pended on a host with 2 free slots). The runner now handles a task range in sched_alloc_range_(): it probes minTasks first and pends after that one search when it does not fit; otherwise it places maxTasks when that fits, or binary-searches for the largest count that fits and places it. Fitting is monotone in the count for balanced plans, so the search is exact for today's plan shapes. ctx->ntasks carries the count; parjob's job-level pass scales per-task shared wants and global limits to it, and the generator gets the request with its task count fixed to it. Fixed counts keep the old path. The decision trace shows each count tried (task count N (minimum) / (maximum), placing N tasks) and releases a fitting probe's hosts. Test fixtures that used minTasks = 1 as filler for an N-task job are now fixed-count. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7cdf25e001
commit
e3b87d28f3
19 changed files with 726 additions and 32 deletions
|
|
@ -1066,6 +1066,49 @@ static void test_known_unsatisfiable_names_source_job(void)
|
|||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* bug-1931: a task range names each count it tries -- the minimum, the
|
||||
* maximum, a count between them, and the count it places. */
|
||||
static void test_task_range_counts(void)
|
||||
{
|
||||
static const char* const rn[] = { "slots" };
|
||||
static const float rv[] = { 1.0f };
|
||||
xce_sched_trace_rec_t* rec;
|
||||
fx_primary_t p;
|
||||
char* out;
|
||||
|
||||
rec = new_rec(XCE_TRACE_LEVEL_FULL, XCE_TRACE_LINE_BOUND_DEFAULT,
|
||||
XCE_TRACE_REC_DECISION);
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
set_selection(rec);
|
||||
set_glimits(rec, 0, NULL, NULL);
|
||||
make_primary(&p, 2, 9, 1, rn, rv, NULL);
|
||||
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
sched_trace_resreq_begin(rec, &p.p, 0);
|
||||
sched_trace_task_count(rec, 2, 1);
|
||||
sched_trace_task_count(rec, 9, 2);
|
||||
sched_trace_task_count(rec, 5, 0);
|
||||
sched_trace_task_count(rec, 5, 3);
|
||||
sched_trace_resreq_end(rec, 0, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_rec_finish(rec, XCE_TRACE_REC_PEND_NO_REASON, 0);
|
||||
|
||||
out = render(rec, XCE_REPL_UNITS_RAW);
|
||||
assert_golden(
|
||||
"[trace] job 1-2-1000-42 session 7 position 3 level full\n"
|
||||
SEL_LINE NO_LIMITS_LINE
|
||||
" requirement single tasks 2..9 requests slots=1\n"
|
||||
" task count 2 (minimum)\n"
|
||||
" task count 9 (maximum)\n"
|
||||
" task count 5\n"
|
||||
" placing 5 tasks\n"
|
||||
" single requirement not satisfied\n"
|
||||
" no decision: job pended without any pend reason\n",
|
||||
out);
|
||||
free(out);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_reconstructed_record(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec;
|
||||
|
|
@ -1364,6 +1407,7 @@ int main(void)
|
|||
RUN_TEST(test_no_decision_internal_error_keeps_hierarchy);
|
||||
RUN_TEST(test_no_decision_pend_without_reason_keeps_hierarchy);
|
||||
RUN_TEST(test_known_unsatisfiable_names_source_job);
|
||||
RUN_TEST(test_task_range_counts);
|
||||
RUN_TEST(test_reconstructed_record);
|
||||
RUN_TEST(test_selection_and_limits_unavailable);
|
||||
RUN_TEST(test_entry_kinds_and_edge_cases);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue