Expand description
CART regression tree for next-CPU-burst prediction.
The tree predicts the next burst in nsecs from per-task features and
the prediction maps to a queue band (pred < T_INT -> Q1, pred <
T_BOUND -> Q2, else Q3). It is trained offline in the daemon on
samples emitted by the BPF side and published into a double-buffered
two-entry array map in src/bpf/intf.h, which the classification
path walks.
The node format, the BFS level-order serialization and the prediction
walk are shared with the BPF side: TreeNode is the byte-for-byte
mirror of struct mlfq_tree_node (24 bytes under #[repr(C)]), and
predict implements the same masked, depth-capped descent as
mlfq_tree_walk() in src/bpf/intf.h. serialize_validate()
checks a tree against the invariants the walk relies on; the daemon
must not commit a tree that fails it.
Growth is classic CART variance reduction: each split minimizes the
sum of squared errors of the two child groups, thresholds are exact
u64 nsec midpoints between distinct feature values, and growth stops
at max_depth, min_samples_leaf, max_nodes or a minimum relative
variance reduction.
Structs§
- FitScratch
- Scratch buffers for the CART fit, sized to the maximum window and node budget. The buffers are allocated once with the capacities below and reused across fits by clearing in place, so the training path does not allocate after the first fit. The queue holds owned sample vectors per node; those vectors are still allocated per node, but the major buffers (weights, sorted, left/right) are reused. This keeps the 60s training free of steady-state allocations while preserving the exact CART logic.
- Node
Spec 🔒 - One node in the BFS queue during fit. The samples are the weighted samples that reached this node. This is an internal detail of the fit and is not part of the published tree.
- Serialized
Tree - A fitted tree in the shared serialized form: BFS level order, index 0
= root, parents before children. The daemon writes these nodes at the
front of a map entry’s node buffer (the entry and its tail are
zeroed, which is the untrained shape);
serialize_validate()must pass before the daemon commits the tree. - Tree
Feats - Per-task feature vector, the mirror of
struct mlfq_tree_feats. - Tree
Node - One tree node, the byte-for-byte mirror of
struct mlfq_tree_node. - Tree
Sample - One training sample, the mirror of
struct mlfq_tree_sample.
Constants§
- DEFAULT_
MIN_ REL_ VAR_ REDUCTION - Default minimum relative variance reduction for a split.
- MLFQ_
TREE_ 🔒MAX_ DEPTH - Walk depth bound of the shared store entry, from
src/bpf/intf.h. - MLFQ_
TREE_ 🔒MAX_ NODES - Node budget of the shared store entry, from
src/bpf/intf.h. A power of two, so the walk’s index mask isMAX_NODES - 1. - MLFQ_
TREE_ 🔒META_ ACTIVE_ SHIFT - Bit position of the active-buffer flag in the committed-tree meta
(bit 1, the value of
MLFQ_TREE_META_ACTIVE). - MLFQ_
TREE_ 🔒NR_ FEATURES - Number of populated features; ids 0..8 index the walk’s
feat[9]slots, sleep_var_ratio at id 9 is carry-along for the next ABI, gpu_submit at 8 quantised 0..4. - MLFQ_
TREE_ SAMPLE_ VERSION - Record-layout version tag of the emitted training samples, from
enum mlfq_constsinsrc/bpf/intf.h.
Functions§
- best_
split 🔒 - Search the best binary split for a node’s samples.
- best_
split_ 🔒with_ scratch - Variant of best_split that reuses a caller-provided buffer for sorting. The buffer is cleared and filled from samples for each feature, so the per-feature allocation is avoided after the first call.
- feat_
value 🔒 - Feature value for a feature id, matching the BPF walk’s
feat[9]slot layout insrc/bpf/intf.h(mlfq_tree_walk). Ids 0..8 are the split features (prev_burst, sleep, ema, io_wait, wake_cnt, wake_lat, queue_wait, sq_ema, gpu_submit), id 9 the cadence ratio (carry-along, split when NR_FEATURES promotes it), and the rest zero. - fit
- Grow a CART regression tree over
samples. - fit_
with_ scratch - Fit a tree reusing the caller-provided scratch arena. After the first
call the arena retains its capacity, so subsequent fits do not allocate.
The logic is identical to
fit(), only the temporary buffers are reused. - label_
totals 🔒 - Sum of weights, weighted sum and weighted sum-of-squares of a node’s labels, in f64 for the variance math. Each sample carries its recency weight alongside it.
- leaf_
prediction 🔒 - Clamp a leaf mean to the u32 prediction field of the shared node.
- mae
- Mean absolute error between predictions and actuals.
- midpoint 🔒
- Overflow-safe midpoint between two distinct u64 values.
- partition 🔒
- Partition a node’s samples by a split, mirroring the walk’s
<=routing.feat_value <= thresholdgoes left. The recency weights ride along with their samples. - pearson
- Pearson product-moment correlation of two equally long vectors.
- predict
- Walk a serialized tree and predict the next burst, the Rust mirror of
mlfq_tree_walk()insrc/bpf/intf.h(the BPF wrapper adds only the meta gate and the map lookup around this walk). - sample_
version_ matches - True when a parsed sample carries the current record-layout version.
- sample_
weights - Recency weight of each training sample, by its age in the window.
- sample_
weights_ into - Fill the provided buffer with recency weights without allocating. The buffer is cleared and filled to length n; capacity is retained so the second call with the same n does not allocate.
- serialize_
validate - Validate a tree against the walk’s invariants before publishing.
- should_
publish - The publish quality gate. The tree replaces the previous model only when its holdout MAE beats the exact per-sample EMA baseline on the same holdout slice and the Pearson correlation clears the quality floor and strictly improves on the currently committed model. The holdout MAE is weighted by the recency weights of the window, so recent samples dominate the gate. Correlation is monotonic: once a model at 0.30 is committed, a later fit at 0.30 or below is held out; 0.52 then 0.72 ratchet toward 1.0 on general workloads. A higher correlation must also beat the baseline, so a high but narrow fit on one game cannot regress the tail.
- tree_
meta - Serialize the committed-tree meta value from its parts.
- weighted_
holdout_ mae - Weighted MAE for the holdout slice. Each holdout sample carries its recency weight w_i = 2^(-age_i / (n/2)) where n is the full window length, so the gate emphasizes the recent regime without dropping the older tail entirely.
Type Aliases§
- Weighted
Sample 🔒 - A training sample paired with its recency weight, the unit the fit carries through the node partitions.