fix(scheduler-sim-decision-trace): render an unset pend main reason as none

The pend outcome printed 'main reason: code 0' for every pend the
allocator builds, because 0 (libxce's 'no main reason set') fell through
to the unknown-code fallback. Found by the 6.1 end-to-end review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-08 16:07:53 +00:00
parent 625663af59
commit 4d1a245fd9
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
3 changed files with 43 additions and 2 deletions

View file

@ -248,9 +248,12 @@ static void put_pend(FILE* f, const sched_trace_pend_out_t* p)
return;
}
/* 0 is libxce's "no main reason set" (preason.c), not a code */
rtr_indent(f, 2);
fprintf(f, "main reason: %s\n",
rtr_reason_name(r->main_reason, buf, sizeof(buf)));
(r->main_reason == 0)
? "none"
: rtr_reason_name(r->main_reason, buf, sizeof(buf)));
/* entries tied to no host (a shared resource carries host "") */
for (k = 0; (r->host_based_reasons != NULL) && (k < r->nhost_reasons);

View file

@ -338,6 +338,7 @@ static void test_step_mode_full_all_jobs_and_file_copy(void)
"\n cluster-wide check failed; no placement plans tried\n",
"\n single requirement not satisfied\n",
"\n outcome: PEND\n",
"\n main reason: none\n",
"\n resource license: NO_RESOURCE\n",
"\n resource limit=cluster_slots: NO_RESOURCE\n");
TEST_ASSERT_NULL(strstr(b, "plan 1"));
@ -362,7 +363,7 @@ static void test_step_mode_full_all_jobs_and_file_copy(void)
"\n alternative 2/2 not satisfied\n",
"\n no alternative chosen: none of the 2 alternatives was "
"satisfied\n",
"\n outcome: PEND\n");
"\n outcome: PEND\n", "\n main reason: none\n");
free(b);
/* 105, session 5: per-host shortfall rows next to limit rows, the

View file

@ -865,6 +865,42 @@ static void test_pend_outcome_null_entries(void)
sched_trace_rec_free(rec);
}
/* A pend whose set carries no main reason (0, preason.c's "none set"), as
* every pend the allocator builds from per-host and per-resource reasons
* does: the line says none instead of a bare code. */
static void test_pend_outcome_without_main_reason(void)
{
xce_sched_trace_rec_t* rec;
xce_res_reason_t rr = { "license", "", PREASON_NO_RESOURCE };
xce_res_reason_t* rrp[1] = { &rr };
xce_job_preason_t jr;
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);
memset(&jr, 0, sizeof(jr));
jr.nres_reasons = 1;
jr.res_based_reasons = rrp;
rec->outcome = SCHED_TRACE_OUTCOME_PEND;
rec->pend.reasons = &jr; /* read only by the renderer */
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
" outcome: PEND\n"
" main reason: none\n"
" resource license: NO_RESOURCE\n",
out);
free(out);
rec->pend.reasons = NULL;
sched_trace_rec_free(rec);
}
/* ---- no-decision and reconstructed records (2.4, 2.5) ------------------- */
static void test_no_decision_not_found(void)
@ -1277,6 +1313,7 @@ int main(void)
RUN_TEST(test_dispatch_outcome_cap);
RUN_TEST(test_pend_outcome);
RUN_TEST(test_pend_outcome_null_entries);
RUN_TEST(test_pend_outcome_without_main_reason);
RUN_TEST(test_no_decision_not_found);
RUN_TEST(test_no_decision_no_schedobj);
RUN_TEST(test_no_decision_internal_error_keeps_hierarchy);