use std::collections::{HashMap, HashSet};
use fuel_graph::opt::insert_cross_device_copies;
use fuel_graph::{Graph, NodeId, Op, extract_runs_multi, topo_order_multi};
use fuel_ir::probe::BackendId;
use fuel_ir::{DType, DeviceLocation, Result};
use crate::driver::{OptimizationContext, PassRegistry};
use crate::kernel::KernelBindingTable;
use crate::plan::{ExecutionPlan, PlanOptions, compile_plan};
use crate::topology::SystemTopology;
#[derive(Debug, Clone)]
pub struct OptimizedGraph {
pub roots: Vec<NodeId>,
pub generation: u64,
pub(crate) placements: Option<HashMap<NodeId, DeviceLocation>>,
}
impl OptimizedGraph {
pub fn runs(&self, graph: &Graph) -> Vec<fuel_graph::Run> {
extract_runs_multi(graph, &self.roots)
}
pub fn placement_of(&self, node: NodeId) -> Option<DeviceLocation> {
self.placements.as_ref()?.get(&node).copied()
}
pub fn has_placements(&self) -> bool {
self.placements.is_some()
}
pub fn placements(&self) -> impl Iterator<Item = (NodeId, DeviceLocation)> + '_ {
self.placements
.iter()
.flat_map(|m| m.iter().map(|(&id, &loc)| (id, loc)))
}
pub fn dispatch_order(&self, graph: &Graph) -> Vec<NodeId> {
fuel_graph::lower_runs_arm0(graph, &self.roots)
}
pub fn branch_count(&self, graph: &Graph) -> usize {
(0..graph.len())
.map(NodeId)
.filter(|&id| matches!(graph.node(id).op, Op::Branch { .. }))
.count()
}
}
pub fn optimize_graph(
graph: &mut Graph,
roots: &[NodeId],
bindings_table: &KernelBindingTable,
opts: &PlanOptions<'_>,
) -> Result<OptimizedGraph> {
optimize_graph_with_passes(
graph,
roots,
bindings_table,
opts,
PassRegistry::default_passes(),
)
}
pub fn optimize_graph_with_runtime_fusion(
graph: &mut Graph,
roots: &[NodeId],
bindings_table: &KernelBindingTable,
opts: &PlanOptions<'_>,
) -> Result<OptimizedGraph> {
optimize_graph_with_passes(
graph,
roots,
bindings_table,
opts,
PassRegistry::default_passes_with_runtime_fusion(),
)
}
fn optimize_graph_with_passes(
graph: &mut Graph,
roots: &[NodeId],
bindings_table: &KernelBindingTable,
opts: &PlanOptions<'_>,
passes: PassRegistry,
) -> Result<OptimizedGraph> {
let order = fuel_graph::opt::execution_plan(graph, roots);
let order = if insert_dtype_fixups(graph, roots, bindings_table, opts) {
fuel_graph::opt::execution_plan(graph, roots)
} else {
order
};
let plan = compile_plan(graph, &order, bindings_table, opts)?;
let generation = plan.generation;
let cycle_guard: HashSet<NodeId> = HashSet::new();
let ctx = OptimizationContext {
order: &order,
plan: &plan,
cycle_guard: &cycle_guard,
bindings: bindings_table,
};
passes.run_lockstep(graph, &ctx)?;
let mut resolved_placements: Option<HashMap<NodeId, DeviceLocation>> = None;
if let Some(pinned) = opts.pinned_device {
stamp_plan_backends(graph, roots, &plan, pinned);
let judge = opts.judge;
crate::variant_bake::bake_variant_branches(graph, roots, &|g, branch, arm, interior| {
let backend = g.target_backend(g.node(branch).inputs.first().copied()?)?;
crate::variant_bake::decode_arm_composite_ns_judged(
g, branch, arm, interior, backend, judge,
)
});
resolved_placements = Some(insert_residency_copies(
graph,
roots,
&plan,
pinned,
opts.input_residency,
));
fuel_graph::opt::insert_layout_fixups(graph, roots, |id| {
plan.alternatives(id)
.and_then(|set| set.winner())
.map(|cand| cand.caps.strided_input)
.unwrap_or(true)
});
}
Ok(OptimizedGraph {
roots: roots.to_vec(),
generation,
placements: resolved_placements,
})
}
fn insert_dtype_fixups(
graph: &mut Graph,
roots: &[NodeId],
bindings: &KernelBindingTable,
options: &PlanOptions<'_>,
) -> bool {
let order = topo_order_multi(graph, roots);
let mut casts: Vec<(NodeId, NodeId, DType)> = Vec::new();
for &id in &order {
let (op, inputs, out_dtype) = {
let node = graph.node(id);
(node.op.clone(), node.inputs.clone(), node.dtype)
};
let op_kind = match crate::pipelined::op_to_op_kind(&op) {
Some(k) => k,
None => continue, };
let native_key = crate::pipelined::build_lookup_dtypes(graph, graph.node(id));
if native_key.len() != inputs.len() + 1 {
continue;
}
let candidates = crate::plan::candidate_backends_for(graph, options, id, graph.node(id));
let servable = |key: &[DType]| {
candidates
.iter()
.any(|&backend| bindings.backend_supports(op_kind, key, backend))
};
if servable(&native_key) {
continue; }
let target = out_dtype;
if !inputs
.iter()
.all(|&i| lossless_upcast(graph.node(i).dtype, target))
{
continue;
}
let promoted_key: Vec<DType> = inputs
.iter()
.map(|_| target)
.chain(std::iter::once(out_dtype))
.collect();
if promoted_key == native_key {
continue; }
if !servable(&promoted_key) {
continue; }
for &input_id in &inputs {
if graph.node(input_id).dtype != target {
casts.push((id, input_id, target));
}
}
}
if casts.is_empty() {
return false;
}
tracing::warn!(
promoting_casts = casts.len(),
"dtype-reconciliation inserted {} promoting Cast(s): a node's per-operand \
dtype key had no native kernel on any backend, so input(s) were upcast to \
the output dtype. This CHANGES numerics vs a native mixed-precision kernel \
and increases resident bytes for the promoted operand(s).",
casts.len(),
);
fuel_graph::opt::insert_cast_fixups(graph, &casts);
true
}
fn lossless_upcast(from: DType, to: DType) -> bool {
use DType::*;
if from == to {
return true;
}
matches!(
(from, to),
(BF16, F32) | (BF16, F64) | (F16, F32) | (F16, F64) | (F32, F64)
)
}
fn stamp_plan_backends(
graph: &mut Graph,
roots: &[NodeId],
plan: &ExecutionPlan,
pinned_loc: DeviceLocation,
) {
let pinned_backend = location_to_backend_id(pinned_loc);
let order = topo_order_multi(graph, roots);
for &id in &order {
let node = graph.node(id);
if matches!(node.op, Op::Const | Op::Release | Op::Contiguize)
|| node.op.is_view_op()
|| matches!(node.op, Op::Reshape(_))
{
continue;
}
let stamp = plan
.alternatives(id)
.and_then(|set| set.winner())
.map(|c| c.backend)
.unwrap_or(pinned_backend);
graph.set_target_backend(id, stamp);
}
}
fn insert_residency_copies(
graph: &mut Graph,
roots: &[NodeId],
plan: &ExecutionPlan,
pinned_loc: DeviceLocation,
input_residency: Option<&dyn Fn(NodeId) -> Option<DeviceLocation>>,
) -> HashMap<NodeId, DeviceLocation> {
let eff_roots = fuel_graph::effective_roots(graph, roots);
let placements = effective_placements(graph, &eff_roots, plan, pinned_loc, input_residency);
let topology = SystemTopology::current();
let shares = |a: DeviceLocation, b: DeviceLocation| -> bool {
if a == b {
return true;
}
topology.shares_storage(
(location_to_backend_id(a), a),
(location_to_backend_id(b), b),
)
};
let needs_host_staging = |a: DeviceLocation, b: DeviceLocation| -> bool {
if a == DeviceLocation::Cpu || b == DeviceLocation::Cpu {
return false;
}
matches!(
topology.transfer_path(a, b),
fuel_ir::backend::TransferPath::HostStaging
)
};
let inserted = insert_cross_device_copies(
graph,
&eff_roots,
|id| placements.get(&id).copied(),
shares,
needs_host_staging,
);
let src_location = |graph: &Graph, src: NodeId| -> Option<DeviceLocation> {
placements
.get(&src)
.copied()
.or_else(|| graph.placement(src))
};
for ©_id in &inserted {
if let Some(&src) = graph.node(copy_id).inputs.first()
&& let Some(src_loc) = src_location(graph, src)
{
graph.set_target_backend(copy_id, location_to_backend_id(src_loc));
}
}
let order = topo_order_multi(graph, &eff_roots);
for &id in &order {
if !matches!(graph.node(id).op, Op::Copy { .. } | Op::Move { .. }) {
continue;
}
let Some(&src) = graph.node(id).inputs.first() else {
continue;
};
let Some(src_loc) = src_location(graph, src) else {
continue;
};
graph.set_target_backend(id, location_to_backend_id(src_loc));
}
placements
}
fn effective_placements(
g: &Graph,
roots: &[NodeId],
plan: &ExecutionPlan,
pinned_loc: DeviceLocation,
input_residency: Option<&dyn Fn(NodeId) -> Option<DeviceLocation>>,
) -> HashMap<NodeId, DeviceLocation> {
let order = topo_order_multi(g, roots);
let mut map: HashMap<NodeId, DeviceLocation> = HashMap::with_capacity(order.len());
for &id in &order {
let node = g.node(id);
match node.op {
Op::Copy { target } | Op::Move { target } | Op::Alloc { target } => {
map.insert(id, target);
continue;
}
_ => {}
}
if let Some(loc) = g.placement(id) {
map.insert(id, loc);
continue;
}
if let Some(loc) = input_residency.and_then(|f| f(id)) {
map.insert(id, loc);
continue;
}
if let Some(winner) = plan.alternatives(id).and_then(|set| set.winner()) {
map.insert(id, winner.device);
continue;
}
if g.target_backend(id).is_some() {
map.insert(id, pinned_loc);
continue;
}
if (node.op.is_view_op() || matches!(node.op, Op::Reshape(_) | Op::Contiguize))
&& let Some(&loc) = node.inputs.first().and_then(|i| map.get(i))
{
map.insert(id, loc);
}
}
map
}
fn location_to_backend_id(loc: DeviceLocation) -> BackendId {
match loc {
DeviceLocation::Cpu => BackendId::Cpu,
DeviceLocation::Cuda { .. } => BackendId::Cuda,
DeviceLocation::Vulkan { .. } => BackendId::Vulkan,
DeviceLocation::Metal { .. } => BackendId::Metal,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fused::PrecisionGuarantee;
use crate::kernel::{KernelCaps, OpParams, unknown_cost};
use fuel_graph::opt::execution_plan;
use fuel_graph::{Node, Op};
use fuel_ir::dispatch::OpKind;
use fuel_ir::probe::BackendId;
use fuel_ir::{DType, DeviceLocation, Layout, Result as FuelResult, Shape};
use fuel_memory::Storage;
use std::sync::{Arc, RwLock};
fn noop_kernel(
_i: &[Arc<RwLock<Storage>>],
_o: &mut [Arc<RwLock<Storage>>],
_l: &[Layout],
_p: &OpParams,
) -> FuelResult<()> {
Ok(())
}
fn register_elementwise(table: &mut KernelBindingTable, op: OpKind, n_in: usize) {
let mut dtypes = vec![DType::F32; n_in];
dtypes.push(DType::F32); table.register_full(
op,
&dtypes,
BackendId::Cpu,
noop_kernel,
KernelCaps::empty(),
PrecisionGuarantee::PRIMITIVE_DETERMINISTIC_CPU,
unknown_cost,
);
}
fn f32_node(g: &mut Graph, op: Op, inputs: Vec<NodeId>) -> NodeId {
g.push(Node {
op,
inputs,
shape: Shape::from_dims(&[4]),
dtype: DType::F32,
})
}
fn build_branchless_graph(table: &mut KernelBindingTable) -> (Graph, NodeId) {
register_elementwise(table, OpKind::ReluElementwise, 1);
register_elementwise(table, OpKind::SiluElementwise, 1);
register_elementwise(table, OpKind::AddElementwise, 2);
register_elementwise(table, OpKind::TanhElementwise, 1);
let mut g = Graph::new();
let a = f32_node(&mut g, Op::Const, vec![]);
let a1 = f32_node(&mut g, Op::Relu, vec![a]);
let b = f32_node(&mut g, Op::Const, vec![]);
let b1 = f32_node(&mut g, Op::Silu, vec![b]);
let sum = f32_node(&mut g, Op::Add, vec![a1, b1]);
let out = f32_node(&mut g, Op::Tanh, vec![sum]);
(g, out)
}
fn build_straight_line_graph(table: &mut KernelBindingTable) -> (Graph, NodeId) {
register_elementwise(table, OpKind::ReluElementwise, 1);
register_elementwise(table, OpKind::SiluElementwise, 1);
register_elementwise(table, OpKind::TanhElementwise, 1);
let mut g = Graph::new();
let a = f32_node(&mut g, Op::Const, vec![]);
let b = f32_node(&mut g, Op::Relu, vec![a]);
let c = f32_node(&mut g, Op::Silu, vec![b]);
let d = f32_node(&mut g, Op::Tanh, vec![c]);
(g, d)
}
fn cpu_opts() -> PlanOptions<'static> {
PlanOptions::new()
.without_cost_population()
.with_pinned_device(DeviceLocation::Cpu)
}
#[test]
fn optimize_graph_stamps_backends_onto_the_graph() {
let mut table = KernelBindingTable::new();
let (mut g, root) = build_straight_line_graph(&mut table);
let (a, b, c, d) = (NodeId(0), NodeId(1), NodeId(2), NodeId(3));
assert!(g.target_backend(b).is_none(), "unstamped before optimize");
let _optimized = optimize_graph(&mut g, &[root], &table, &cpu_opts())
.expect("optimize_graph on a straight-line CPU graph");
assert_eq!(
g.target_backend(b),
Some(BackendId::Cpu),
"Relu stamped Cpu"
);
assert_eq!(
g.target_backend(c),
Some(BackendId::Cpu),
"Silu stamped Cpu"
);
assert_eq!(
g.target_backend(d),
Some(BackendId::Cpu),
"Tanh stamped Cpu"
);
assert!(
g.target_backend(a).is_none(),
"Op::Const leaf is not stamped"
);
}
#[test]
fn placement_of_observes_the_decision_and_marks_not_computed() {
let mut table = KernelBindingTable::new();
let (mut g, root) = build_straight_line_graph(&mut table);
let (_a, b, c, d) = (NodeId(0), NodeId(1), NodeId(2), NodeId(3));
let optimized = optimize_graph(&mut g, &[root], &table, &cpu_opts())
.expect("optimize_graph on a straight-line CPU graph");
assert!(
optimized.has_placements(),
"a pinned device runs the residency pass, so placements must be computed",
);
assert_eq!(
optimized.placement_of(b),
Some(DeviceLocation::Cpu),
"Relu placed Cpu"
);
assert_eq!(
optimized.placement_of(c),
Some(DeviceLocation::Cpu),
"Silu placed Cpu"
);
assert_eq!(
optimized.placement_of(d),
Some(DeviceLocation::Cpu),
"Tanh placed Cpu"
);
assert!(
optimized.placements().count() >= 3,
"the map must actually be populated, got {} entries",
optimized.placements().count(),
);
let mut table2 = KernelBindingTable::new();
let (mut g2, root2) = build_straight_line_graph(&mut table2);
for n in [NodeId(0), NodeId(1), NodeId(2), NodeId(3)] {
g2.set_placement(n, DeviceLocation::Cpu);
}
let bare = PlanOptions::new().without_cost_population();
let unpinned = optimize_graph(&mut g2, &[root2], &table2, &bare)
.expect("optimize_graph with graph placements but no pinned device");
assert!(
!unpinned.has_placements(),
"no pinned device => residency pass skipped => placements NOT computed",
);
assert_eq!(
unpinned.placement_of(b),
None,
"and every lookup is None — which `has_placements()` explains as \
'not computed', never 'placed nowhere'",
);
}
#[test]
fn optimize_graph_reconciles_mixed_precision_matmul_via_cast() {
let bindings = crate::dispatch::global_bindings(); let mut g = Graph::new();
let lhs = g.push(Node {
op: Op::Const,
inputs: vec![],
shape: Shape::from_dims(&[2, 3]),
dtype: DType::F32,
});
let rhs = g.push(Node {
op: Op::Const,
inputs: vec![],
shape: Shape::from_dims(&[3, 2]),
dtype: DType::BF16,
});
let mm = g.push(Node {
op: Op::MatMul,
inputs: vec![lhs, rhs],
shape: Shape::from_dims(&[2, 2]),
dtype: DType::F32,
});
optimize_graph(&mut g, &[mm], &bindings, &cpu_opts())
.expect("mixed-precision matmul reconciled + optimized on CPU");
let mm_inputs = g.node(mm).inputs.clone();
assert_eq!(mm_inputs[0], lhs, "lhs (already F32) untouched");
let cast_id = mm_inputs[1];
assert_ne!(cast_id, rhs, "rhs was rewired to a Cast");
assert!(
matches!(g.node(cast_id).op, Op::Cast(DType::F32)),
"rhs cast to F32"
);
assert_eq!(g.node(cast_id).dtype, DType::F32);
assert_eq!(
g.node(cast_id).inputs,
vec![rhs],
"cast reads the original BF16 weight"
);
}
fn register_matmul(table: &mut KernelBindingTable, dtypes: &[DType], backend: BackendId) {
table.register_full(
OpKind::MatMul,
dtypes,
backend,
noop_kernel,
KernelCaps::empty(),
PrecisionGuarantee::PRIMITIVE_DETERMINISTIC_CPU,
unknown_cost,
);
}
fn register_cast(table: &mut KernelBindingTable, from: DType, to: DType, backend: BackendId) {
table.register_full(
OpKind::Cast,
&[from, to],
backend,
noop_kernel,
KernelCaps::empty(),
PrecisionGuarantee::PRIMITIVE_DETERMINISTIC_CPU,
unknown_cost,
);
}
fn mixed_matmul_graph() -> (Graph, NodeId, NodeId, NodeId) {
let mut g = Graph::new();
let lhs = g.push(Node {
op: Op::Const,
inputs: vec![],
shape: Shape::from_dims(&[2, 3]),
dtype: DType::F32,
});
let rhs = g.push(Node {
op: Op::Const,
inputs: vec![],
shape: Shape::from_dims(&[3, 2]),
dtype: DType::BF16,
});
let mm = g.push(Node {
op: Op::MatMul,
inputs: vec![lhs, rhs],
shape: Shape::from_dims(&[2, 2]),
dtype: DType::F32,
});
(g, lhs, rhs, mm)
}
#[test]
fn dtype_reconciliation_ignores_kernels_on_non_candidate_backends() {
let mut table = KernelBindingTable::new();
register_matmul(
&mut table,
&[DType::F32, DType::F32, DType::F32],
BackendId::Cpu,
);
register_matmul(
&mut table,
&[DType::F32, DType::BF16, DType::F32],
BackendId::Vulkan,
);
register_cast(&mut table, DType::BF16, DType::F32, BackendId::Cpu);
let (mut g, lhs, rhs, mm) = mixed_matmul_graph();
optimize_graph(&mut g, &[mm], &table, &cpu_opts()).expect(
"CPU-pinned mixed-precision matmul must reconcile via Cast even though \
a NON-candidate backend owns the native mixed kernel",
);
let mm_inputs = g.node(mm).inputs.clone();
assert_eq!(mm_inputs[0], lhs, "lhs (already F32) untouched");
let cast_id = mm_inputs[1];
assert_ne!(cast_id, rhs, "rhs was rewired to a Cast");
assert!(
matches!(g.node(cast_id).op, Op::Cast(DType::F32)),
"rhs cast to F32"
);
assert_eq!(
g.node(cast_id).inputs,
vec![rhs],
"cast reads the original BF16 weight"
);
}
#[test]
fn dtype_reconciliation_declines_when_the_candidate_backend_serves_it_natively() {
let mut table = KernelBindingTable::new();
register_matmul(
&mut table,
&[DType::F32, DType::BF16, DType::F32],
BackendId::Cpu,
);
let (mut g, lhs, rhs, mm) = mixed_matmul_graph();
optimize_graph(&mut g, &[mm], &table, &cpu_opts()).expect("native mixed kernel plans");
assert_eq!(
g.node(mm).inputs,
vec![lhs, rhs],
"no Cast: the candidate backend has the native mixed kernel",
);
}
#[test]
fn dtype_reconciliation_counts_admitted_off_device_fallback_as_a_candidate() {
let mut table = KernelBindingTable::new();
register_matmul(
&mut table,
&[DType::F32, DType::F32, DType::F32],
BackendId::Cpu,
);
register_matmul(
&mut table,
&[DType::F32, DType::BF16, DType::F32],
BackendId::Vulkan,
);
let fallback = |_from: DeviceLocation| -> Vec<(BackendId, DeviceLocation)> {
vec![(BackendId::Vulkan, DeviceLocation::Vulkan { gpu_id: 0 })]
};
let opts = PlanOptions::new()
.without_cost_population()
.with_pinned_device(DeviceLocation::Cpu)
.with_fallback_placements_for(&fallback);
let (mut g, lhs, rhs, mm) = mixed_matmul_graph();
optimize_graph(&mut g, &[mm], &table, &opts).expect("off-device native mixed kernel plans");
assert_eq!(
g.node(mm).inputs,
vec![lhs, rhs],
"no Cast: the admitted off-device fallback backend serves the mixed key natively",
);
}
#[test]
fn optimize_graph_without_pinned_device_does_not_stamp() {
let mut table = KernelBindingTable::new();
let (mut g, root) = build_straight_line_graph(&mut table);
for id in [NodeId(0), NodeId(1), NodeId(2), NodeId(3)] {
g.set_placement(id, DeviceLocation::Cpu);
}
let opts = PlanOptions::new().without_cost_population(); let _ = optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph");
assert!(
g.target_backend(NodeId(1)).is_none(),
"no pinned device ⇒ no target_backend stamping",
);
}
#[test]
fn optimize_graph_inserts_layout_fixup_for_strided_input() {
let mut table = KernelBindingTable::new();
register_elementwise(&mut table, OpKind::ReluElementwise, 1); let mut g = Graph::new();
let a = f32_node(&mut g, Op::Const, vec![]);
let r = f32_node(&mut g, Op::Relu, vec![a]);
g.set_layout(a, Layout::contiguous_with_offset(Shape::from_dims(&[4]), 1));
let _optimized = optimize_graph(&mut g, &[r], &table, &cpu_opts())
.expect("optimize_graph with a strided input");
let relu_input = g.node(r).inputs[0];
assert!(
matches!(g.node(relu_input).op, Op::Contiguize),
"strided input to a strided-rejecting kernel must be fixed up via \
Op::Contiguize, got {:?}",
g.node(relu_input).op,
);
assert_eq!(
g.node(relu_input).inputs,
vec![a],
"the inserted Op::Contiguize wraps the original strided input",
);
}
#[test]
fn residency_noop_when_colocated() {
let mut g = Graph::new();
let c1 = f32_node(&mut g, Op::Const, vec![]);
let c2 = f32_node(&mut g, Op::Const, vec![]);
let add = f32_node(&mut g, Op::Add, vec![c1, c2]);
g.set_target_backend(add, BackendId::Cpu);
let residency = |id: NodeId| (id == c1 || id == c2).then_some(DeviceLocation::Cpu);
let pre = g.len();
insert_residency_copies(
&mut g,
&[add],
&ExecutionPlan::empty(),
DeviceLocation::Cpu,
Some(&residency),
);
assert_eq!(g.len(), pre, "co-located graph must be a no-op");
assert_eq!(g.node(add).inputs, vec![c1, c2], "edges untouched");
}
#[test]
fn residency_one_copy_per_crossing_deduped() {
let cuda0 = DeviceLocation::Cuda { gpu_id: 0 };
let mut g = Graph::new();
let c1 = f32_node(&mut g, Op::Const, vec![]);
let neg = f32_node(&mut g, Op::Neg, vec![c1]);
let sqr = f32_node(&mut g, Op::Sqr, vec![c1]);
g.set_target_backend(neg, BackendId::Cuda);
g.set_target_backend(sqr, BackendId::Cuda);
let residency = |id: NodeId| (id == c1).then_some(DeviceLocation::Cpu);
let pre = g.len();
insert_residency_copies(
&mut g,
&[neg, sqr],
&ExecutionPlan::empty(),
cuda0,
Some(&residency),
);
assert_eq!(g.len(), pre + 1, "one crossing → one copy, CSE-deduped");
let neg_in = g.node(neg).inputs[0];
let sqr_in = g.node(sqr).inputs[0];
assert_eq!(neg_in, sqr_in, "both consumers share the one copy");
assert_ne!(neg_in, c1, "consumers rewired off the raw input");
let copy = g.node(neg_in);
assert!(
matches!(copy.op, Op::Copy { target } if target == cuda0),
"copy targets the consumer device; got {:?}",
copy.op,
);
assert_eq!(copy.inputs, vec![c1], "copy reads the resident slot");
assert_eq!(
g.target_backend(neg_in),
Some(BackendId::Cpu),
"stamped with the SOURCE backend (H2D runs on the CPU wrapper)",
);
assert_eq!(
g.placement(neg_in),
Some(cuda0),
"copy output placed on the consumer device",
);
}
#[test]
fn residency_idempotent_and_restamped_on_second_call() {
let cuda0 = DeviceLocation::Cuda { gpu_id: 0 };
let mut g = Graph::new();
let c1 = f32_node(&mut g, Op::Const, vec![]);
let neg = f32_node(&mut g, Op::Neg, vec![c1]);
g.set_target_backend(neg, BackendId::Cuda);
let residency = |id: NodeId| (id == c1).then_some(DeviceLocation::Cpu);
insert_residency_copies(
&mut g,
&[neg],
&ExecutionPlan::empty(),
cuda0,
Some(&residency),
);
let copy_id = g.node(neg).inputs[0];
g.set_target_backend(copy_id, BackendId::Cuda);
let pre = g.len();
insert_residency_copies(
&mut g,
&[neg],
&ExecutionPlan::empty(),
cuda0,
Some(&residency),
);
assert_eq!(g.len(), pre, "re-run inserts nothing");
assert_eq!(
g.target_backend(copy_id),
Some(BackendId::Cpu),
"re-stamp sweep restores the source-backend stamp",
);
}
fn residency_diamond(
arm1_loc: DeviceLocation,
) -> (Graph, NodeId, NodeId, NodeId, NodeId, NodeId) {
let mut g = Graph::new();
let pre = f32_node(&mut g, Op::Const, vec![]);
let diverge = f32_node(&mut g, Op::Relu, vec![pre]);
let arm0 = f32_node(&mut g, Op::Silu, vec![diverge]);
let arm1 = f32_node(&mut g, Op::GeluTanh, vec![diverge]);
let reconverge = f32_node(&mut g, Op::Relu, vec![arm0]);
let mut b = g.open_branch(diverge);
b.add_arm(arm0);
b.add_arm(arm1);
let branch = b
.finalize_branches(&mut g, reconverge)
.expect("well-formed 2-arm branch")
.expect("2 arms survive");
let post = f32_node(&mut g, Op::Tanh, vec![reconverge]);
g.set_placement(pre, DeviceLocation::Cpu);
g.set_placement(diverge, DeviceLocation::Cpu);
g.set_placement(arm0, DeviceLocation::Cpu);
g.set_placement(reconverge, DeviceLocation::Cpu);
g.set_placement(post, DeviceLocation::Cpu);
g.set_placement(arm1, arm1_loc);
(g, branch, diverge, arm0, arm1, post)
}
#[test]
fn residency_stitches_every_branch_arm_not_just_arm0() {
let cuda0 = DeviceLocation::Cuda { gpu_id: 0 };
let (mut g, _branch, diverge, arm0, arm1, post) = residency_diamond(cuda0);
insert_residency_copies(
&mut g,
&[post],
&ExecutionPlan::empty(),
DeviceLocation::Cpu,
None,
);
assert_eq!(
g.node(arm0).inputs,
vec![diverge],
"arm-0 is co-located with its producer ⇒ no copy, edge untouched",
);
let arm1_in = g.node(arm1).inputs[0];
assert_ne!(
arm1_in, diverge,
"arm-1 (CUDA) reads the CPU producer directly — its inbound \
cross-device Op::Copy was NEVER inserted. Re-picking arm-1 at \
runtime (C2) would dispatch a CUDA kernel over un-copied CPU \
bytes. The residency pass stitched only arm-0's route.",
);
let copy = g.node(arm1_in);
assert!(
matches!(copy.op, Op::Copy { target } if target == cuda0),
"arm-1's inbound copy must target CUDA; got {:?}",
copy.op,
);
assert_eq!(
copy.inputs,
vec![diverge],
"arm-1's copy reads the shared CPU producer",
);
}
fn noop_kernel_b(
_i: &[Arc<RwLock<Storage>>],
_o: &mut [Arc<RwLock<Storage>>],
_l: &[Layout],
_p: &OpParams,
) -> FuelResult<()> {
Ok(())
}
fn register_two_backend(table: &mut KernelBindingTable, op: OpKind, n_in: usize) {
let mut dtypes = vec![DType::F32; n_in];
dtypes.push(DType::F32);
table.register_full(
op,
&dtypes,
BackendId::Cpu,
noop_kernel,
KernelCaps::empty(),
PrecisionGuarantee::PRIMITIVE_DETERMINISTIC_CPU,
unknown_cost,
);
table.register_full(
op,
&dtypes,
BackendId::Cuda,
noop_kernel_b,
KernelCaps::empty(),
PrecisionGuarantee::PRIMITIVE_DETERMINISTIC_CPU,
unknown_cost,
);
}
fn two_backend_placements(dev: DeviceLocation) -> Vec<BackendId> {
if dev == DeviceLocation::Cpu {
vec![BackendId::Cpu, BackendId::Cuda]
} else {
vec![]
}
}
fn two_backend_opts() -> PlanOptions<'static> {
PlanOptions::new()
.without_cost_population()
.with_pinned_device(DeviceLocation::Cpu)
.with_placements_for_device(&two_backend_placements)
}
fn build_single_fork_graph(
table: &mut KernelBindingTable,
) -> (Graph, NodeId, NodeId, NodeId, NodeId) {
register_elementwise(table, OpKind::ReluElementwise, 1);
register_two_backend(table, OpKind::SiluElementwise, 1); register_elementwise(table, OpKind::TanhElementwise, 1);
let mut g = Graph::new();
let mut prev = f32_node(&mut g, Op::Const, vec![]);
for _ in 0..20 {
prev = f32_node(&mut g, Op::Relu, vec![prev]);
}
let prod = prev; let fork = f32_node(&mut g, Op::Silu, vec![prod]);
let tail = f32_node(&mut g, Op::Tanh, vec![fork]); let mut prev = tail;
for _ in 0..20 {
prev = f32_node(&mut g, Op::Relu, vec![prev]);
}
let root = prev;
(g, prod, fork, tail, root)
}
#[test]
fn deliberate_fork_emits_one_two_arm_branch() {
use fuel_graph::{branch_density, passes_fewness_gate};
let mut table = KernelBindingTable::new();
let (mut g, _prod, fork, _tail, root) = build_single_fork_graph(&mut table);
let opts = two_backend_opts();
let nodes_before = g.len();
let optimized = optimize_graph(&mut g, &[root], &table, &opts)
.expect("optimize_graph succeeds on a 2-placement graph");
assert_eq!(
optimized.branch_count(&g),
1,
"a single genuine placement fork emits exactly one Op::Branch",
);
let branch_id = (nodes_before..g.len())
.map(NodeId)
.find(|&id| matches!(g.node(id).op, Op::Branch { .. }))
.expect("a Branch node was appended");
let branch = g.node(branch_id);
assert_eq!(branch.inputs.len(), 2, "the branch has exactly two arms");
assert_eq!(
branch.inputs[0], fork,
"arm-0 is the DP winner node (the route realize uses today)",
);
assert_ne!(
branch.inputs[1], fork,
"arm-1 is a distinct (runner-up placement) node",
);
assert!(
passes_fewness_gate(&g, root),
"a single deliberate fork passes the fewness gate; density={}",
branch_density(&g, root),
);
}
#[test]
fn plain_fan_out_is_not_a_branch() {
let mut table = KernelBindingTable::new();
register_two_backend(&mut table, OpKind::ReluElementwise, 1);
register_elementwise(&mut table, OpKind::SiluElementwise, 1);
register_elementwise(&mut table, OpKind::TanhElementwise, 1);
register_elementwise(&mut table, OpKind::AddElementwise, 2);
let mut g = Graph::new();
let c = f32_node(&mut g, Op::Const, vec![]);
let shared = f32_node(&mut g, Op::Relu, vec![c]);
let c0 = f32_node(&mut g, Op::Silu, vec![shared]);
let c1 = f32_node(&mut g, Op::Tanh, vec![shared]);
let out = f32_node(&mut g, Op::Add, vec![c0, c1]);
let opts = two_backend_opts();
let optimized =
optimize_graph(&mut g, &[out], &table, &opts).expect("optimize_graph succeeds");
assert_eq!(
optimized.branch_count(&g),
0,
"plain fan-out (multiple consumers) is not a deliberate fork",
);
let _ = shared;
}
#[test]
fn branched_graph_realizes_via_arm0() {
let mut table = KernelBindingTable::new();
let (mut g, prod, fork, tail, root) = build_single_fork_graph(&mut table);
let opts = two_backend_opts();
let pre_order = execution_plan(&g, &[root]);
let optimized =
optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph succeeds");
assert_eq!(optimized.branch_count(&g), 1, "exactly one branch");
let branch_id = (0..g.len())
.map(NodeId)
.find(|&id| matches!(g.node(id).op, Op::Branch { .. }))
.expect("a Branch node exists");
let arm1 = g.node(branch_id).inputs[1];
let order = optimized.dispatch_order(&g);
assert!(
!order.contains(&arm1),
"arm-0 lowering must skip arm-1's run; order={order:?} arm1={arm1:?}",
);
assert!(order.contains(&prod), "pre-run (diverge producer) executes");
assert!(order.contains(&fork), "arm-0 (the winner) executes");
assert!(order.contains(&tail), "post-run (reconverge) executes");
assert!(order.contains(&root), "the realize root executes");
assert_eq!(
order, pre_order,
"arm-0 dispatch order equals the pre-branch single-route order",
);
}
type CachedEnvTestFixture = (
Arc<RwLock<Graph>>,
crate::pipelined::StorageCache,
OptimizedGraph,
std::sync::OnceLock<Vec<NodeId>>,
Arc<dyn crate::ranker::RuntimeSelector>,
NodeId,
);
fn cached_env_test_fixture() -> CachedEnvTestFixture {
use crate::pipelined::StorageCache;
use crate::ranker::runtime_selector::WinnerSelector;
let mut table = KernelBindingTable::new();
let (mut g, _prod, _fork, _tail, root) = build_single_fork_graph(&mut table);
let opts = two_backend_opts();
let optimized =
optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph succeeds");
assert_eq!(optimized.branch_count(&g), 1, "exactly one branch");
let graph = Arc::new(RwLock::new(g));
let mut cache = StorageCache::new();
cache.insert(
NodeId(0), Arc::new(RwLock::new(fuel_memory::from_slice_cpu(&[
1.0_f32, 2.0, 3.0, 4.0,
]))),
);
let order_cache: std::sync::OnceLock<Vec<NodeId>> = std::sync::OnceLock::new();
let selector: Arc<dyn crate::ranker::RuntimeSelector> = Arc::new(WinnerSelector);
(graph, cache, optimized, order_cache, selector, root)
}
#[test]
fn cached_env_never_caches_a_branched_graph_with_a_real_selector() {
use crate::PipelinedExecutor;
use fuel_ir::{Error, SymEnv};
let (graph, cache, optimized, order_cache, selector, root) = cached_env_test_fixture();
let result = PipelinedExecutor::realize_with_optimized_picking_cached_env(
graph.clone(),
root,
cache.clone(),
&optimized,
&order_cache,
Some(selector.clone()),
None,
SymEnv::default(),
);
assert!(
result.is_ok() || matches!(result, Err(Error::TopologyChanged { .. })),
"a picked realize over a branched graph must either succeed or hit the \
(unrelated, expected-under-concurrency) TopologyChanged race: {:?}",
result.err()
);
assert!(
order_cache.get().is_none(),
"a branched graph with a real selector pick must NEVER populate order_cache — \
it must route through OrderSource::Streaming, not OrderSource::Cached",
);
let result2 = PipelinedExecutor::realize_with_optimized_picking_cached_env(
graph,
root,
cache,
&optimized,
&order_cache,
Some(selector),
None,
SymEnv::default(),
);
assert!(
result2.is_ok() || matches!(result2, Err(Error::TopologyChanged { .. })),
"second picked realize must either succeed or hit the same expected-under- \
concurrency TopologyChanged race: {:?}",
result2.err()
);
assert!(
order_cache.get().is_none(),
"order_cache must still be empty after a second picked realize",
);
}
#[test]
fn cached_env_tolerates_a_concurrent_topology_generation_bump() {
use crate::PipelinedExecutor;
use fuel_ir::{Error, SymEnv};
let (graph, cache, mut optimized, order_cache, selector, root) = cached_env_test_fixture();
optimized.generation = optimized.generation.wrapping_add(1);
let result = PipelinedExecutor::realize_with_optimized_picking_cached_env(
graph,
root,
cache,
&optimized,
&order_cache,
Some(selector),
None,
SymEnv::default(),
);
assert!(
matches!(result, Err(Error::TopologyChanged { .. })),
"a forced generation bump before realize must surface as TopologyChanged, \
not silently succeed or fail some other way: {:?}",
result
);
assert!(
order_cache.get().is_none(),
"order_cache must stay empty even when the realize that would have \
populated it (if it were ever going to) failed with TopologyChanged",
);
}
#[test]
fn no_default_max_n_truncation() {
let mut table = KernelBindingTable::new();
let (mut g, _prod, fork, _tail, root) = build_single_fork_graph(&mut table);
let opts = two_backend_opts();
let optimized =
optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph succeeds");
assert_eq!(optimized.branch_count(&g), 1);
let branch_id = (0..g.len())
.map(NodeId)
.find(|&id| matches!(g.node(id).op, Op::Branch { .. }))
.expect("a Branch node exists");
assert_eq!(g.node(branch_id).inputs.len(), 2);
assert_eq!(g.node(branch_id).inputs[0], fork);
}
#[test]
fn equivalence_gate_branchless_order_matches_compile_plan() {
for build in [
build_straight_line_graph as fn(&mut KernelBindingTable) -> (Graph, NodeId),
build_branchless_graph as fn(&mut KernelBindingTable) -> (Graph, NodeId),
] {
let mut table = KernelBindingTable::new();
let (mut g, root) = build(&mut table);
let opts = cpu_opts();
let order = execution_plan(&g, &[root]);
let plan = compile_plan(&g, &order, &table, &opts)
.expect("today's compile_plan succeeds on a placeable graph");
let optimized = optimize_graph(&mut g, &[root], &table, &opts)
.expect("optimize_graph succeeds on the same graph");
assert_eq!(
optimized.branch_count(&g),
0,
"a no-competing-route graph optimizes to zero Op::Branch nodes",
);
let lowered = optimized.dispatch_order(&g);
assert_eq!(
lowered, plan.order,
"the extract_runs/lower_run dispatch order must equal \
compile_plan(...).order exactly (same NodeIds, same order)",
);
assert_eq!(
lowered.len(),
order.len(),
"the lowered order covers every node compile_plan ordered",
);
}
}
#[test]
fn optimize_graph_branchless_is_idempotent_and_adds_no_nodes() {
let mut table = KernelBindingTable::new();
let (mut g, root) = build_branchless_graph(&mut table);
let opts = cpu_opts();
let nodes_before = g.len();
let first =
optimize_graph(&mut g, &[root], &table, &opts).expect("first optimize succeeds");
let order_first = first.dispatch_order(&g);
let nodes_after_first = g.len();
let second =
optimize_graph(&mut g, &[root], &table, &opts).expect("second optimize succeeds");
let order_second = second.dispatch_order(&g);
let nodes_after_second = g.len();
assert_eq!(
nodes_before, nodes_after_first,
"optimize_graph adds no nodes (A3a is single-route-only)",
);
assert_eq!(
nodes_after_first, nodes_after_second,
"a second optimize_graph adds no further nodes — idempotent",
);
assert_eq!(first.branch_count(&g), 0, "no branches after first");
assert_eq!(second.branch_count(&g), 0, "no branches after second");
assert_eq!(
order_first, order_second,
"the lowered dispatch order is stable across repeated optimize",
);
}
#[test]
fn dispatch_order_is_stable_across_repeated_calls_with_no_mutation() {
for build in [
build_branchless_graph as fn(&mut KernelBindingTable) -> (Graph, NodeId),
build_straight_line_graph,
] {
let mut table = KernelBindingTable::new();
let (mut g, root) = build(&mut table);
let opts = cpu_opts();
let optimized = optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph");
let orders: Vec<Vec<NodeId>> = (0..5).map(|_| optimized.dispatch_order(&g)).collect();
for (i, order) in orders.iter().enumerate().skip(1) {
assert_eq!(
&orders[0], order,
"dispatch_order call {i} diverged from call 0 with no intervening \
mutation — the order_for memoization fix would be UNSAFE if this failed",
);
}
}
}
#[test]
fn optimize_graph_fails_fast_on_missing_binding() {
let table = KernelBindingTable::new(); let mut g = Graph::new();
let a = f32_node(&mut g, Op::Const, vec![]);
let relu = f32_node(&mut g, Op::Relu, vec![a]);
let opts = cpu_opts();
let err = optimize_graph(&mut g, &[relu], &table, &opts)
.map(|_| ())
.unwrap_err();
match err {
fuel_ir::Error::NoBackendForOp { op, .. } => {
assert_eq!(op, OpKind::ReluElementwise);
}
other => panic!("expected NoBackendForOp, got {other:?}"),
}
}
use crate::driver::{
FrontierConvergenceOptimizer, OptimizationContext, Optimizer, PassRegistry, Pathfinder,
PlacementForkPathfinder,
};
use std::collections::HashSet;
fn branch_snapshot(g: &Graph) -> Vec<(NodeId, NodeId, Vec<NodeId>)> {
(0..g.len())
.map(NodeId)
.filter_map(|id| match g.node(id).op {
Op::Branch { reconverge_at } => {
Some((id, reconverge_at, g.node(id).inputs.clone()))
}
_ => None,
})
.collect()
}
#[test]
fn driver_matches_legacy_sequence() {
let mut ref_table = KernelBindingTable::new();
let (mut ref_g, _prod, ref_fork, _tail, ref_root) = build_single_fork_graph(&mut ref_table);
let opts = two_backend_opts();
let ref_order = execution_plan(&ref_g, &[ref_root]);
let ref_plan = compile_plan(&ref_g, &ref_order, &ref_table, &opts)
.expect("reference compile_plan succeeds");
{
let guard: HashSet<NodeId> = HashSet::new();
let ctx = OptimizationContext {
order: &ref_order,
plan: &ref_plan,
cycle_guard: &guard,
bindings: &ref_table,
};
PlacementForkPathfinder
.propose(&mut ref_g, &ctx)
.expect("pathfinder proposes");
FrontierConvergenceOptimizer
.prune(&mut ref_g, &ctx)
.expect("optimizer prunes");
}
let ref_snapshot = branch_snapshot(&ref_g);
let ref_dispatch = fuel_graph::lower_runs_arm0(&ref_g, &[ref_root]);
let mut table = KernelBindingTable::new();
let (mut g, _p, fork, _t, root) = build_single_fork_graph(&mut table);
let optimized =
optimize_graph(&mut g, &[root], &table, &opts).expect("optimize_graph succeeds");
let got_snapshot = branch_snapshot(&g);
let got_dispatch = optimized.dispatch_order(&g);
assert_eq!(
got_snapshot, ref_snapshot,
"driver produces the identical Op::Branch structure as the legacy \
pathfinder→optimizer sequence",
);
assert_eq!(
got_snapshot.len(),
1,
"the representative multi-placement graph produces exactly one branch",
);
assert_eq!(
got_snapshot[0].2[0], fork,
"arm-0 is the DP winner (the route realize uses)",
);
assert_eq!(
got_dispatch, ref_dispatch,
"driver yields the identical arm-0 dispatch order as the legacy sequence",
);
let _ = ref_fork;
}
#[test]
fn noop_registry_leaves_branchless_graph_unchanged() {
let mut table = KernelBindingTable::new();
let (mut g, root) = build_branchless_graph(&mut table);
let opts = cpu_opts();
let order = execution_plan(&g, &[root]);
let plan = compile_plan(&g, &order, &table, &opts).expect("compile_plan succeeds");
let dispatch_before = fuel_graph::lower_runs_arm0(&g, &[root]);
let nodes_before = g.len();
let registry = PassRegistry::new(); assert_eq!(registry.pathfinder_count(), 0);
assert_eq!(registry.optimizer_count(), 0);
let guard: HashSet<NodeId> = HashSet::new();
let ctx = OptimizationContext {
order: &order,
plan: &plan,
cycle_guard: &guard,
bindings: &table,
};
registry
.run_lockstep(&mut g, &ctx)
.expect("empty registry runs cleanly");
assert_eq!(g.len(), nodes_before, "no-op registry adds no nodes");
let branches = (0..g.len())
.map(NodeId)
.filter(|&id| matches!(g.node(id).op, Op::Branch { .. }))
.count();
assert_eq!(branches, 0, "no-op registry adds no branches");
let dispatch_after = fuel_graph::lower_runs_arm0(&g, &[root]);
assert_eq!(
dispatch_before, dispatch_after,
"no-op registry leaves the dispatch order unchanged",
);
}
#[test]
fn lockstep_runs_pathfinder_before_dependent_optimizer() {
use std::sync::{Arc, Mutex};
#[derive(Clone)]
struct RecordPathfinder(Arc<Mutex<Vec<&'static str>>>);
impl Pathfinder for RecordPathfinder {
fn name(&self) -> &'static str {
"RecordPathfinder"
}
fn propose(
&self,
_g: &mut Graph,
_ctx: &OptimizationContext<'_>,
) -> fuel_ir::Result<()> {
self.0.lock().unwrap().push("propose");
Ok(())
}
}
#[derive(Clone)]
struct RecordOptimizer(Arc<Mutex<Vec<&'static str>>>);
impl Optimizer for RecordOptimizer {
fn name(&self) -> &'static str {
"RecordOptimizer"
}
fn prune(&self, _g: &mut Graph, _ctx: &OptimizationContext<'_>) -> fuel_ir::Result<()> {
self.0.lock().unwrap().push("prune");
Ok(())
}
}
let log = Arc::new(Mutex::new(Vec::new()));
let registry = PassRegistry::new()
.with_pathfinder(Box::new(RecordPathfinder(log.clone())))
.with_optimizer(Box::new(RecordOptimizer(log.clone())));
let mut g = Graph::new();
let _a = f32_node(&mut g, Op::Const, vec![]);
let plan = ExecutionPlan::empty();
let order: Vec<NodeId> = Vec::new();
let guard: HashSet<NodeId> = HashSet::new();
let table = KernelBindingTable::new();
let ctx = OptimizationContext {
order: &order,
plan: &plan,
cycle_guard: &guard,
bindings: &table,
};
registry.run_lockstep(&mut g, &ctx).expect("drive runs");
let seq = log.lock().unwrap().clone();
assert_eq!(
seq,
vec!["propose", "prune"],
"lock-step drive runs the pathfinder ADD strictly before its \
dependent optimizer PRUNE (prune-as-you-go)",
);
}
#[test]
#[ignore = "live GPU (CUDA); run via scripts/gpu-run.ps1"]
#[cfg(feature = "cuda")]
fn paged_attn_decomposed_arm_placement_report_cuda() {
use fuel_graph::registry::{FusedOpParams, FusedOps};
use std::collections::BTreeMap;
const B: usize = 1;
const HQ: usize = 4;
const HKV: usize = 4;
const SQ: usize = 1;
const D: usize = 4;
const NUM_BLOCKS: usize = 32;
const BLOCK_SIZE: usize = 4;
const MAX_BLK: usize = 8;
let mut g = Graph::new();
let leaf = |g: &mut Graph, dims: &[usize], dtype: DType| {
g.push(Node {
op: Op::Const,
inputs: vec![],
shape: Shape::from_dims(dims),
dtype,
})
};
let q = leaf(&mut g, &[B, HQ, SQ, D], DType::F32);
let kc = leaf(&mut g, &[NUM_BLOCKS, BLOCK_SIZE, HKV, D], DType::F32);
let vc = leaf(&mut g, &[NUM_BLOCKS, BLOCK_SIZE, HKV, D], DType::F32);
let bt = leaf(&mut g, &[B, MAX_BLK], DType::U32);
let cl = leaf(&mut g, &[B], DType::U32);
let params = FusedOpParams::PagedAttn {
softmax_scale: 1.0 / (D as f32).sqrt(),
block_size: BLOCK_SIZE,
softcap: None,
};
let fused = g.push(Node {
op: Op::Fused(FusedOps::PAGED_ATTN, params.clone()),
inputs: vec![q, kc, vc, bt, cl],
shape: Shape::from_dims(&[B, HQ, SQ, D]),
dtype: DType::F32,
});
let root = fuel_graph::registry::paged_attn::decompose(&mut g, fused, ¶ms);
assert_ne!(
root, fused,
"PRECONDITION: decompose must actually lower. A self-return is the \
G2 fixpoint signal (malformed node / declined recipe), and every \
placement below would then describe the FUSED node, silently \
answering a different question than the one asked.",
);
let table = crate::dispatch::global_bindings();
assert!(
table
.lookup(
OpKind::MatMul,
&[DType::F32, DType::F32, DType::F32],
BackendId::Cuda
)
.is_ok(),
"INSTRUMENT BROKEN: the binding table has no CUDA MatMul, so every \
'no CUDA support' conclusion below would be an artifact of the \
harness. Fix the table before reading any verdict from this test.",
);
let mut missing_cuda: Vec<String> = Vec::new();
let mut present_cuda: Vec<String> = Vec::new();
for i in 0..g.len() {
let id = NodeId(i);
let node = g.node(id);
let Some(kind) = crate::pipelined::op_to_op_kind(&node.op) else {
continue; };
let mut dtypes: Vec<DType> = node.inputs.iter().map(|&i| g.node(i).dtype).collect();
dtypes.push(node.dtype); let sig = format!(
"{kind:?}{:?}",
dtypes.iter().map(|d| format!("{d:?}")).collect::<Vec<_>>()
);
if table.lookup(kind, &dtypes, BackendId::Cuda).is_ok() {
present_cuda.push(sig);
} else {
missing_cuda.push(sig);
}
}
missing_cuda.sort();
missing_cuda.dedup();
present_cuda.sort();
present_cuda.dedup();
println!("\n=== PagedAttn recipe: CUDA binding coverage (asked per node) ===");
println!("PRESENT on CUDA ({}):", present_cuda.len());
for s in &present_cuda {
println!(" {s}");
}
println!("MISSING on CUDA ({}):", missing_cuda.len());
for s in &missing_cuda {
println!(" {s}");
}
assert!(
!present_cuda.is_empty(),
"INSTRUMENT BROKEN: not one recipe node resolved on CUDA, so the \
MISSING list is a property of the lookup, not of the backend",
);
println!(
"\n>>> THE ASK: the {} signature(s) above are what CUDA lacks for the \
§1 dense recipe. Each is a small, named primitive — not \"paged \
attention\".\n",
missing_cuda.len()
);
let opts = PlanOptions::new().with_pinned_device(DeviceLocation::Cuda { gpu_id: 0 });
let optimized = match optimize_graph(&mut g, &[root], &table, &opts) {
Ok(o) => o,
Err(e) => {
println!("\n=== DECOMPOSED ARM DOES NOT PLAN ON CUDA ===");
println!("optimize_graph error: {e:?}");
println!("That is itself the answer: some recipe primitive has no CUDA");
println!("binding, and the error names it. THAT is the Baracuda ask.");
return;
}
};
assert!(
optimized.has_placements(),
"placement NOT COMPUTED — every placement_of would be None and the \
report below would describe the missing instrument, not the graph",
);
let mut by_op: BTreeMap<String, BTreeMap<String, usize>> = BTreeMap::new();
let mut host_ops: Vec<String> = Vec::new();
for i in 0..g.len() {
let id = NodeId(i);
let op_name = match &g.node(id).op {
Op::Fused(fid, _) => format!("Fused({fid:?})"),
other => format!("{other:?}")
.split(' ')
.next()
.unwrap_or("?")
.to_string(),
};
let place = match optimized.placement_of(id) {
Some(d) => format!("{d:?}"),
None => "None".to_string(),
};
if place.starts_with("Cpu") {
host_ops.push(op_name.clone());
}
*by_op.entry(op_name).or_default().entry(place).or_insert(0) += 1;
}
println!("\n=== PagedAttn DECOMPOSED arm: node placement (CUDA-pinned) ===");
println!(
"total nodes: {} (fused node #{} lowered to root #{})",
g.len(),
fused.0,
root.0
);
for (op, places) in &by_op {
let rendered: Vec<String> = places.iter().map(|(d, n)| format!("{d}×{n}")).collect();
println!(" {op:<40} {}", rendered.join(" "));
}
println!("\n--- VERDICT ---");
if host_ops.is_empty() {
println!(
"EVERY recipe node is off-host. The decomposed paged attention runs \
ON DEVICE, so the 186x round-trip is removable by OFFERING THIS ARM \
— no Baracuda kernel required to eliminate it. A kernel would then \
be a throughput question (the recipe materialises padded capacity, \
not live context_len), not a round-trip one."
);
} else {
host_ops.sort();
host_ops.dedup();
println!(
"HOST-PLACED recipe primitives: {host_ops:?}\n\
These are the ask — each is a far smaller and better-specified \
request than \"paged attention\", and until they exist on device \
the decomposed arm cannot win."
);
}
println!("--- END VERDICT ---\n");
}
}