feat(scheduler-sim-decision-trace): capture selection facts, cluster-wide limits and attempt reasons

Task 2.1: policy, queue and priority/queue-time ordering keys, each
matched cluster-wide limit as (name, scope), and per-code attempt
failure reasons with the hosts and resources they name, all copied into
the record arena.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-08 09:08:23 +00:00
parent a801aff46f
commit 54f9139e77
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
5 changed files with 873 additions and 4 deletions

View file

@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include "resreq.h"
#include "sched/types.h"
@ -212,6 +213,15 @@ typedef struct {
int count;
} sched_trace_limit_tally_t;
/* One cluster-wide limit matched to the job (2.3), from the schedobj's
* glimits. `scope` is the scope instance the limit applies to, as
* comma-separated `u=..,q=..,p=..` pairs; "" when the limit has no
* per-consumer scope. */
typedef struct {
const char* limit; /* arena copy */
const char* scope; /* arena copy */
} sched_trace_limit_ref_t;
/* One requested resource of a single requirement or member (3.2). */
typedef struct {
const char* name; /* arena copy */
@ -357,8 +367,21 @@ struct xce_sched_trace_rec_s {
int line_bound;
bool incomplete; /* arena growth failed: appending stopped */
/* selection block */
const char* policy_name; /* arena copy of ctl->policy_name, or NULL */
/* selection block (2.2, 2.3), filled by TraceCapture */
const char* policy_name; /* the job's ordering policy: arena copy of
* the queue's picker override, else of
* ctl->policy_name, else of the core's
* picker; NULL if none is known */
bool selection_set; /* capture_selection ran: the ordering keys
* below are known (not NOT_FOUND) */
const char* queue_name; /* arena copy; NULL: the job has no queue */
int32_t queue_priority;
int32_t job_priority;
time_t queue_time;
bool glimits_set; /* capture_glimits ran: the limits are known
* (false: no schedobj, limits unavailable) */
int nglimits;
sched_trace_limit_ref_t* glimits; /* in the schedobj's glimits order */
/* current requirement path (pushed and popped by the allocation chain) */
sched_trace_path_t path;
@ -560,4 +583,31 @@ extern void sched_trace_finalize_failed(xce_sched_trace_rec_t* rec, int err);
*/
extern void sched_trace_search_end(xce_sched_trace_rec_t* rec, int rc);
/*
* TraceCapture (src/sched_trace_capture.c, design.md "TraceCapture"). Each
* reads scheduler state on the thread that owns it, read-only, and copies
* what it reports into `rec` (never NULL: the SCHED_TRACE gate).
*/
/* The job's ordering policy and keys at selection (2.2): policy name, queue
* name and priority, job priority, queue time. A NULL job (not found by
* the allocator, 2.4) captures nothing. */
extern void sched_trace_capture_selection(xce_sched_trace_rec_t* rec,
const xce_sched_core_t* core,
const xce_sched_job_t* job);
/* The job's matched cluster-wide limits (2.3): each xce_vres_t in
* obj->glimits as (limit name, scope instance). A NULL obj (no schedobj,
* 2.4) leaves the limits unavailable. */
extern void sched_trace_capture_glimits(xce_sched_trace_rec_t* rec,
const xce_sched_obj_t* obj);
/* A failed compound attempt's reasons (3.5), from its pend-reason set before
* the scheduler replaces obj->reason: one ATTEMPT_REASONS entry with a
* count per pend-reason code (main reason, host and resource reasons, in
* the order first seen) and the distinct hosts and resources they name.
* A NULL or empty set stores the entry with no reasons. */
extern void sched_trace_capture_attempt_reasons(xce_sched_trace_rec_t* rec,
const xce_pendreason_t* reason);
#endif