use super::ir_util::{atomic_load_relaxed, atomic_store_relaxed};
use super::protocol::*;
use vyre_foundation::ir::{Expr, Node};
mod offsets;
pub use offsets::{
default_priority_offsets, default_priority_offsets_array, try_default_priority_offsets,
write_default_priority_offsets,
};
pub const PRIORITY_LEVELS: u32 = 5;
pub mod priority {
pub const CRITICAL: u32 = 0;
pub const HIGH: u32 = 1;
pub const NORMAL: u32 = 2;
pub const LOW: u32 = 3;
pub const IDLE: u32 = 4;
}
pub const STARVATION_THRESHOLD: u32 = 16;
pub const TENANT_FAIRNESS_THRESHOLD: u32 = 64;
pub const PRIORITY_OFFSETS_BASE: u32 = control::PRIORITY_OFFSETS_BASE;
pub const PRIORITY_STARVATION_COUNTER: u32 = control::PRIORITY_STARVATION_COUNTER;
#[must_use]
pub fn policy_offset_start(partition_start: Expr, partition_end: Expr, lane_id: Expr) -> Expr {
let range = Expr::sub(partition_end.clone(), partition_start.clone());
let nonzero_range = Expr::max(range, Expr::u32(1));
Expr::add(partition_start, Expr::rem(lane_id, nonzero_range))
}
#[must_use]
pub fn priority_partition_probe_count(partition_slots: u32, worker_width: u32) -> u32 {
if partition_slots == 0 {
return 0;
}
let width = worker_width.max(1);
partition_slots.div_ceil(width)
}
#[must_use]
pub fn priority_partition_active_lane_count(partition_slots: u32, worker_width: u32) -> u32 {
partition_slots.min(worker_width.max(1))
}
#[must_use]
pub fn priority_partition_probe_budget(partition_slots: u32, worker_width: u32) -> u32 {
priority_partition_active_lane_count(partition_slots, worker_width)
.checked_mul(priority_partition_probe_count(partition_slots, worker_width))
.unwrap_or_else(|| {
panic!(
"megakernel priority partition probe budget overflowed u32. Fix: shard partition slots or reduce worker width."
)
})
}
#[must_use]
pub fn check_tenant_fairness(tenant_id: Expr) -> Expr {
let tenant_counter = Expr::rem(tenant_id, Expr::u32(control::TENANT_FAIRNESS_SLOTS));
let count = atomic_load_relaxed(
"control",
Expr::add(Expr::u32(control::TENANT_FAIRNESS_BASE), tenant_counter),
);
Expr::lt(count, Expr::u32(TENANT_FAIRNESS_THRESHOLD))
}
#[must_use]
pub fn check_priority_fairness(priority: Expr) -> Expr {
let count = atomic_load_relaxed(
"control",
Expr::add(Expr::u32(control::PRIORITY_FAIRNESS_BASE), priority),
);
Expr::lt(count, Expr::u32(STARVATION_THRESHOLD))
}
#[must_use]
pub fn priority_scan_body(total_slots: u32) -> Vec<Node> {
priority_scan_body_with_stride(total_slots, total_slots.max(1))
}
#[must_use]
pub fn priority_scan_body_with_stride(total_slots: u32, worker_stride: u32) -> Vec<Node> {
let worker_stride = worker_stride.max(1);
vec![
Node::let_bind("claimed_slot_base", Expr::u32(u32::MAX)),
Node::let_bind("claimed_priority", Expr::u32(u32::MAX)),
Node::let_bind("claimed_tenant", Expr::u32(u32::MAX)),
Node::let_bind(
"priority_starvation_count",
atomic_load_relaxed("control", Expr::u32(PRIORITY_STARVATION_COUNTER)),
),
Node::let_bind(
"priority_force_lower",
Expr::ge(
Expr::var("priority_starvation_count"),
Expr::u32(STARVATION_THRESHOLD),
),
),
Node::loop_for(
"scan_pri",
Expr::u32(0),
Expr::u32(PRIORITY_LEVELS),
vec![
Node::if_then(
Expr::and(
Expr::eq(Expr::var("claimed_slot_base"), Expr::u32(u32::MAX)),
Expr::or(
Expr::not(Expr::var("priority_force_lower")),
Expr::gt(Expr::var("scan_pri"), Expr::u32(priority::HIGH)),
),
),
vec![
Node::let_bind(
"part_start",
atomic_load_relaxed(
"control",
Expr::add(Expr::u32(PRIORITY_OFFSETS_BASE), Expr::var("scan_pri")),
),
),
Node::let_bind(
"part_end",
atomic_load_relaxed(
"control",
Expr::add(
Expr::u32(PRIORITY_OFFSETS_BASE),
Expr::add(Expr::var("scan_pri"), Expr::u32(1)),
),
),
),
Node::let_bind(
"part_len",
Expr::sub(Expr::var("part_end"), Expr::var("part_start")),
),
Node::let_bind(
"probe_count",
Expr::div(
Expr::add(
Expr::var("part_len"),
Expr::u32(worker_stride.saturating_sub(1)),
),
Expr::u32(worker_stride),
),
),
Node::if_then(
Expr::gt(Expr::var("part_len"), Expr::u32(0)),
vec![
Node::let_bind(
"partition_lane",
Expr::rem(Expr::var("lane_id"), Expr::u32(worker_stride)),
),
Node::if_then(
Expr::lt(Expr::var("partition_lane"), Expr::var("part_len")),
vec![Node::loop_for(
"scan_idx",
Expr::u32(0),
Expr::var("probe_count"),
vec![
Node::let_bind(
"scan_slot",
Expr::add(
Expr::var("part_start"),
Expr::rem(
Expr::add(
Expr::var("partition_lane"),
Expr::mul(
Expr::var("scan_idx"),
Expr::u32(worker_stride),
),
),
Expr::var("part_len"),
),
),
),
Node::if_then(
Expr::and(
Expr::eq(
Expr::var("claimed_slot_base"),
Expr::u32(u32::MAX),
),
Expr::lt(
Expr::var("scan_slot"),
Expr::u32(total_slots),
),
),
vec![
Node::let_bind(
"probe_base",
Expr::mul(
Expr::var("scan_slot"),
Expr::u32(SLOT_WORDS),
),
),
Node::let_bind(
"probe_status",
atomic_load_relaxed(
"ring_buffer",
Expr::var("probe_base"),
),
),
Node::let_bind(
"probe_schedulable",
Expr::or(
Expr::eq(
Expr::var("probe_status"),
Expr::u32(slot::PUBLISHED),
),
Expr::or(
Expr::eq(
Expr::var("probe_status"),
Expr::u32(slot::YIELD),
),
Expr::eq(
Expr::var("probe_status"),
Expr::u32(slot::REQUEUE),
),
),
),
),
Node::if_then(
Expr::var("probe_schedulable"),
vec![
Node::let_bind(
"probe_tenant",
Expr::load(
"ring_buffer",
Expr::add(
Expr::var("probe_base"),
Expr::u32(TENANT_WORD),
),
),
),
Node::let_bind(
"probe_tenant_base",
atomic_load_relaxed(
"control",
Expr::u32(
control::TENANT_BASE,
),
),
),
Node::let_bind(
"probe_tenant_mask",
atomic_load_relaxed(
"control",
Expr::add(
Expr::var(
"probe_tenant_base",
),
Expr::var("probe_tenant"),
),
),
),
Node::if_then(
Expr::ne(
Expr::var(
"probe_tenant_mask",
),
Expr::u32(0),
),
vec![
Node::let_bind(
"probe_expected",
Expr::var("probe_status"),
),
Node::let_bind(
"probe_prev",
Expr::atomic_compare_exchange(
"ring_buffer",
Expr::var("probe_base"),
Expr::var("probe_expected"),
Expr::u32(slot::CLAIMED),
),
),
Node::if_then(
Expr::eq(
Expr::var("probe_prev"),
Expr::var("probe_expected"),
),
vec![
Node::assign(
"claimed_slot_base",
Expr::var("probe_base"),
),
Node::assign(
"claimed_priority",
Expr::var("scan_pri"),
),
Node::assign(
"claimed_tenant",
Expr::var("probe_tenant"),
),
],
),
],
),
],
),
],
),
],
)],
),
],
),
],
),
],
),
Node::if_then(
Expr::ne(Expr::var("claimed_priority"), Expr::u32(u32::MAX)),
vec![
Node::if_then_else(
Expr::le(Expr::var("claimed_priority"), Expr::u32(priority::HIGH)),
vec![Node::let_bind(
"priority_starvation_prev",
Expr::atomic_add(
"control",
Expr::u32(PRIORITY_STARVATION_COUNTER),
Expr::u32(1),
),
)],
vec![atomic_store_relaxed(
"priority_starvation_prev",
"control",
Expr::u32(PRIORITY_STARVATION_COUNTER),
Expr::u32(0),
)],
),
Node::let_bind(
"tenant_fairness_prev",
Expr::atomic_add(
"control",
Expr::add(
Expr::u32(control::TENANT_FAIRNESS_BASE),
Expr::rem(
Expr::var("claimed_tenant"),
Expr::u32(control::TENANT_FAIRNESS_SLOTS),
),
),
Expr::u32(1),
),
),
Node::let_bind(
"priority_fairness_prev",
Expr::atomic_add(
"control",
Expr::add(
Expr::u32(control::PRIORITY_FAIRNESS_BASE),
Expr::var("claimed_priority"),
),
Expr::u32(1),
),
),
],
),
]
}
#[cfg(test)]
mod tests;