myxce/src/include/resreq.h

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