312 lines
11 KiB
C
312 lines
11 KiB
C
#if !defined(_RESREQ_H_)
|
|
|
|
#define _RESREQ_H_ 1
|
|
|
|
#include <stdatomic.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "kvmgr.h"
|
|
#include "xlist.h"
|
|
#include "xvec.h"
|
|
|
|
/* ──────────────────────────────────────────────────────────────────────────
|
|
* Select-expression AST (Phase 3-4 implementation)
|
|
* ────────────────────────────────────────────────────────────────────────── */
|
|
|
|
typedef enum {
|
|
SEL_AND, /* && — commutative binary */
|
|
SEL_OR, /* || — commutative binary */
|
|
SEL_NOT, /* ! — unary */
|
|
SEL_GT, /* > — numeric only */
|
|
SEL_LT, /* < — numeric only */
|
|
SEL_GE, /* >= — numeric only */
|
|
SEL_LE, /* <= — numeric only */
|
|
SEL_EQ, /* == — commutative, all types */
|
|
SEL_NE, /* != — commutative, all types */
|
|
SEL_RESNAME, /* leaf: resource variable */
|
|
SEL_NUM, /* leaf: numeric literal */
|
|
SEL_STR, /* leaf: string literal (xstring-interned) */
|
|
SEL_ANY, /* leaf: 'any' keyword — eliminated by const-fold */
|
|
SEL_TRUE, /* leaf: const true — produced by const-fold only */
|
|
SEL_FALSE, /* leaf: const false — produced by const-fold only */
|
|
} sel_node_type_t;
|
|
|
|
typedef enum {
|
|
RES_TYPE_NUMERIC = 0, /* float — supports all comparison operators */
|
|
RES_TYPE_STRING, /* char* — supports == != only */
|
|
RES_TYPE_BOOL, /* int — standalone boolean use */
|
|
} res_type_t;
|
|
|
|
typedef struct xce_select_node_ xce_select_node_t;
|
|
struct xce_select_node_ {
|
|
sel_node_type_t type;
|
|
uint32_t hashcode;
|
|
uint32_t node_id;
|
|
unsigned gc_mark;
|
|
union {
|
|
struct {
|
|
xce_select_node_t *left, *right;
|
|
} binop; /* AND / OR / GT / LT / GE / LE / EQ / NE */
|
|
xce_select_node_t* operand; /* NOT */
|
|
struct {
|
|
int res_idx;
|
|
res_type_t res_type;
|
|
} resname;
|
|
double numval; /* SEL_NUM */
|
|
char* strval; /* SEL_STR — xstring-interned */
|
|
} u;
|
|
};
|
|
|
|
/* Evaluation context forward declarations */
|
|
typedef struct select_eval_ctx_ select_eval_ctx_t;
|
|
typedef struct host_eval_ctx_ host_eval_ctx_t;
|
|
|
|
/* Host snapshot: per-resource numeric (incl. bool as 0.0/1.0) and string values */
|
|
struct host_eval_ctx_ {
|
|
int num_res;
|
|
const double* numvals; /* indexed by res_idx */
|
|
const char** strvals; /* indexed by res_idx */
|
|
};
|
|
|
|
/* Per-evaluation-session memoization context */
|
|
struct select_eval_ctx_ {
|
|
const host_eval_ctx_t* host;
|
|
uint8_t* bool_bits; /* 2 bits per node_id: NONE/TRUE/FALSE/ERROR */
|
|
uint32_t bool_bits_cap; /* capacity in nodes (each uses 2 bits) */
|
|
uint32_t node_count; /* snapshot of sel_node_next_id at init */
|
|
double* num_vals; /* numeric/bool leaf cache, indexed by node_id */
|
|
uint32_t num_vals_cap;
|
|
const char** str_vals; /* string leaf cache, indexed by node_id */
|
|
uint32_t str_vals_cap;
|
|
};
|
|
|
|
/* Scheduler job forward declaration for GC API */
|
|
typedef struct xce_sched_job_ xce_sched_job_t;
|
|
|
|
/* makeSelectNode — intern or allocate a select AST node.
|
|
* Returns NULL on OOM or intern-table cap exceeded. */
|
|
extern xce_select_node_t* makeSelectNode(sel_node_type_t type,
|
|
uintptr_t op1, uintptr_t op2);
|
|
|
|
/* Resreq subsystem lifecycle — call once at process startup/shutdown.
|
|
* resreq_init sets the optimization level and initializes the intern table.
|
|
* resreq_fini tears down the intern table.
|
|
* optimize_level: 0 = disabled (API server); >0 = CSE+memoization (scheduler). */
|
|
extern void resreq_init(int optimize_level);
|
|
extern void resreq_fini(void);
|
|
|
|
/* Optimization level — set once at process startup.
|
|
* 0 = disabled (API server); >0 = CSE+memoization (scheduler). */
|
|
extern void sel_optimize_set(int level);
|
|
extern int sel_get_optimize_level(void);
|
|
|
|
/* Register the calling thread as the sole allocator/eval/GC thread.
|
|
* Must be called once at scheduler startup (before eval_select or
|
|
* gc_sweep_select_nodes). When unregistered (id==0) the checks are skipped. */
|
|
extern void sel_register_alloc_thread(void);
|
|
|
|
/* Intern table lifecycle */
|
|
extern void sel_node_table_init(void);
|
|
extern void sel_node_table_fini(void);
|
|
|
|
/* Test-only reset (requires #define UNIT_TEST before this header) */
|
|
#ifdef UNIT_TEST
|
|
extern void sel_optimize_test_reset(void);
|
|
#endif
|
|
|
|
/* Evaluation APIs */
|
|
extern int eval_select(const xce_select_node_t* node, select_eval_ctx_t* ctx);
|
|
extern int eval_select_simple(const xce_select_node_t* root,
|
|
const host_eval_ctx_t* host);
|
|
|
|
/* Eval context lifecycle */
|
|
extern select_eval_ctx_t* select_eval_ctx_init(uint32_t max_node_id);
|
|
extern void select_eval_ctx_reset(select_eval_ctx_t* ctx,
|
|
const host_eval_ctx_t* host);
|
|
extern void select_eval_ctx_fini(select_eval_ctx_t* ctx);
|
|
|
|
/* Mark-and-sweep GC between scheduling sessions */
|
|
extern void gc_sweep_select_nodes(const xce_sched_job_t** live_jobs,
|
|
size_t njobs);
|
|
extern void recompact_node_ids(void);
|
|
|
|
/* GC mark primitives — called by scheduler to implement the mark phase.
|
|
* Protocol: gc_clear_marks() → gc_mark_select_tree(root) per live node
|
|
* → gc_sweep_select_nodes(NULL, 0) → recompact_node_ids() */
|
|
extern void gc_clear_marks(void);
|
|
extern void gc_mark_select_tree(xce_select_node_t* node);
|
|
|
|
/* Flatten AND/OR right-associative chains to left-associative form.
|
|
* Returns the new root (may differ from the input root).
|
|
* Sets *changed to 1 if any re-association took place, leaves it unchanged
|
|
* otherwise (callers must initialise *changed to 0 before the first call).
|
|
* In level==0 mode: frees orphaned intermediate nodes (NOT their re-parented
|
|
* children). In CSE mode (level > 0): no explicit freeing — GC owns nodes. */
|
|
extern xce_select_node_t* sel_flatten_pass(xce_select_node_t* root,
|
|
int* changed);
|
|
|
|
/* Single-pass const-fold transform (Phase 4d).
|
|
* In level==0: may return a new allocation; frees consumed subtrees.
|
|
* In CSE mode (level > 0): returns an interned singleton; GC owns nodes. */
|
|
extern xce_select_node_t* sel_const_fold_pass(xce_select_node_t* node);
|
|
|
|
typedef struct xce_resreq_select_ xce_select_t;
|
|
typedef struct xce_resreq_rusages_ xce_rusages_t;
|
|
typedef struct xce_resreq_span_ xce_span_t;
|
|
typedef struct xce_resreq_same_ xce_same_t;
|
|
typedef struct xce_resreq_affinity_ xce_affinity_t;
|
|
typedef struct xce_resreq_data_ xce_resreq_data_t;
|
|
|
|
struct xce_resreq_data_ {
|
|
char* selectString;
|
|
char* rusageString;
|
|
char* spanString;
|
|
char* sameString;
|
|
char* affinityString;
|
|
};
|
|
|
|
typedef struct {
|
|
const char* input;
|
|
int pos;
|
|
char* errmsg;
|
|
int err_pos;
|
|
int has_error;
|
|
xce_resreq_data_t data;
|
|
} section_context_t;
|
|
|
|
/* Maximum allowed select expression length and nesting depth */
|
|
#define SELECT_MAX_INPUT_LEN 8192
|
|
#define SELECT_MAX_DEPTH 64
|
|
|
|
/* Parse context for xce_select.peg — auxil struct for packcc-generated parser */
|
|
typedef struct select_context_t_ select_context_t;
|
|
struct select_context_t_ {
|
|
var resmgr; /* resource manager for name resolution */
|
|
const char* input;
|
|
int pos;
|
|
int err_pos;
|
|
int has_error;
|
|
char errmsg[256]; /* fixed-size — no alloc/free in grammar actions */
|
|
int depth; /* current nesting depth — guard vs SELECT_MAX_DEPTH */
|
|
xce_select_node_t* root; /* result root set by grammar top-level action */
|
|
};
|
|
|
|
typedef enum {
|
|
PER_TASK = 0,
|
|
PER_JOB,
|
|
PER_HOST,
|
|
PER_DEFAULT
|
|
} rusage_per_type_t;
|
|
|
|
typedef struct {
|
|
const char* input;
|
|
int pos;
|
|
int err_pos;
|
|
int has_error;
|
|
xlist_t* rusages;
|
|
char* resname;
|
|
rusage_per_type_t per_flag;
|
|
float resvalue;
|
|
float duration_value;
|
|
int decay_flag;
|
|
float tmp_value;
|
|
float duration_multiply;
|
|
} rusage_context_t;
|
|
|
|
typedef struct {
|
|
char* res;
|
|
float value;
|
|
rusage_per_type_t per_flag;
|
|
float duration;
|
|
int decay_flag;
|
|
} rusage_value_t;
|
|
|
|
struct xce_resreq_select_ {
|
|
xce_select_node_t* root;
|
|
};
|
|
|
|
struct xce_resreq_span_ { };
|
|
|
|
struct xce_resreq_same_ { };
|
|
|
|
struct xce_resreq_affinity_ { };
|
|
|
|
typedef struct {
|
|
int minTasks;
|
|
int maxTasks;
|
|
xce_select_t* select;
|
|
xlist_t rusages;
|
|
xce_span_t* span;
|
|
xce_same_t* same;
|
|
xce_affinity_t* affinity;
|
|
} xce_primary_resreq_t;
|
|
|
|
typedef struct {
|
|
xlist_t primaries;
|
|
} xce_compound_resreq_t;
|
|
|
|
typedef struct {
|
|
xlist_t compounds;
|
|
} xce_alter_resreq_t;
|
|
|
|
typedef enum {
|
|
XCE_RESREQ_PRIMARY = 0,
|
|
XCE_RESREQ_COMPOUND,
|
|
XCE_RESREQ_ALTER
|
|
} xce_resreq_tag_t;
|
|
|
|
typedef struct {
|
|
xce_resreq_tag_t tag;
|
|
union {
|
|
xce_primary_resreq_t* primary;
|
|
xce_compound_resreq_t* compound;
|
|
xce_alter_resreq_t* alter;
|
|
} u;
|
|
} xce_resreq_t;
|
|
|
|
typedef struct {
|
|
var resmgr;
|
|
const char* input;
|
|
int pos;
|
|
int err_pos;
|
|
int has_error;
|
|
char* errmsg;
|
|
xce_resreq_t* resreq;
|
|
xce_alter_resreq_t* alter;
|
|
xce_compound_resreq_t* compound;
|
|
xce_primary_resreq_t* primary;
|
|
int resreq_fact_count;
|
|
} resreq_context_t;
|
|
|
|
extern res_type_t valtype_to_res_type(int v);
|
|
|
|
/* Single comparison point for string-valued resources.
|
|
* Returns 1 if a == b, 0 otherwise. Named for future wildcard extension. */
|
|
static inline int xce_str_match(const char* a, const char* b)
|
|
{
|
|
/* NULL means the resource has no value — treat as no-match */
|
|
if (a == NULL || b == NULL) return 0;
|
|
return strcmp(a, b) == 0;
|
|
}
|
|
|
|
extern void kill_select(xce_select_t*);
|
|
extern void sel_free_tree(xce_select_node_t*);
|
|
extern void kill_section_ctx(section_context_t*);
|
|
extern void kill_resreq_data(xce_resreq_data_t*);
|
|
extern int parse_section(xce_resreq_data_t*, char*, char**);
|
|
extern int parse_rusage(xlist_t*, char*, char**);
|
|
extern void kill_rusage_value(rusage_value_t*);
|
|
extern int parse_resreq_primary(xce_primary_resreq_t*, char*, var, char**);
|
|
extern void kill_primary_resreq(xce_primary_resreq_t*);
|
|
extern int parse_resreq(xce_resreq_t*, char*, var, char**);
|
|
extern void kill_resreq(xce_resreq_t*);
|
|
extern int format_resreq(char**, xce_resreq_t*);
|
|
extern int calc_wanted_global_resvals(xvec_idval_t*, var, xlist_t*,
|
|
rusage_per_type_t, int, int);
|
|
extern int calc_wanted_host_resvals(xvec_idval_t*, var, xlist_t*,
|
|
rusage_per_type_t, int, int);
|
|
|
|
#endif
|