#![cfg(test)]
use vyre::DispatchConfig;
use vyre::VyreBackend;
use vyre_driver_cuda::{CudaBackend, CudaBackendRegistration};
use vyre_primitives::predicate::edge_kind;
use weir::fixed_point_resident::{
FixedPointBorrowedResidentPlan, FixedPointResidentFrontierScratch, FixedPointResidentGraph,
};
use weir::oracle::graph::slice_closure as slice_closure_cpu;
use weir::slice::{
prepare_slice_plan, slice_closure_borrowed_via,
slice_closure_plan_borrowed_into_with_scratch_via,
};
fn run_dispatch(
backend: &CudaBackend,
) -> impl Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String> + '_ {
move |program, inputs, grid_override| {
let mut config = DispatchConfig::default();
config.grid_override = grid_override;
backend
.dispatch_borrowed(program, inputs, &config)
.map_err(|err| err.to_string())
}
}
fn live_dispatcher() -> CudaBackend {
CudaBackend::acquire()
.expect("CudaBackend::acquire failed on a host that must have an NVIDIA GPU.")
}
#[test]
fn cuda_slice_chain_pulls_back() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 2, 3, 3];
let edge_targets = vec![1u32, 2, 3];
let edge_kind_mask = vec![edge_kind::ASSIGNMENT, edge_kind::CONTROL, edge_kind::ALIAS];
let seed_bits = vec![0b1000u32];
let cpu = slice_closure_cpu(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = slice_closure_borrowed_via(
&dispatch,
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![0b1111u32]);
}
#[test]
fn cuda_slice_diamond_admits_all_kinds() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![
edge_kind::ASSIGNMENT,
edge_kind::CONTROL,
edge_kind::ALIAS,
edge_kind::MEM_LOAD,
];
let seed_bits = vec![0b1000u32];
let cpu = slice_closure_cpu(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = slice_closure_borrowed_via(
&dispatch,
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![0b1111u32]);
}
#[test]
fn cuda_slice_zero_kind_blocks() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 1];
let edge_targets = vec![1u32];
let edge_kind_mask = vec![0u32];
let seed_bits = vec![0b10u32];
let cpu = slice_closure_cpu(2, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = slice_closure_borrowed_via(
&dispatch,
2,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![0b10u32]);
}
#[test]
fn cuda_slice_self_loop_terminates() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 1];
let edge_targets = vec![0u32];
let edge_kind_mask = vec![edge_kind::ALIAS];
let seed_bits = vec![0b01u32];
let cpu = slice_closure_cpu(2, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = slice_closure_borrowed_via(
&dispatch,
2,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
50,
)
.expect("dispatch");
assert_eq!(gpu, cpu);
}
#[test]
fn cuda_slice_disconnected_components() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let edge_offsets = vec![0u32, 1, 1, 2, 2];
let edge_targets = vec![1u32, 3];
let edge_kind_mask = vec![edge_kind::ASSIGNMENT; 2];
let seed_bits = vec![0b1000u32];
let cpu = slice_closure_cpu(4, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let gpu = slice_closure_borrowed_via(
&dispatch,
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
16,
)
.expect("dispatch");
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![0b1100u32]);
}
#[test]
fn cuda_slice_prepared_plan_reuses_scratch_parity() {
let backend = live_dispatcher();
let dispatch = run_dispatch(&backend);
let dispatch_into = |program: &vyre::ir::Program,
inputs: &[&[u8]],
grid_override: Option<[u32; 3]>,
outputs: &mut Vec<Vec<u8>>| {
let result = dispatch(program, inputs, grid_override)?;
outputs.clear();
outputs.extend(result);
Ok(())
};
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![
edge_kind::ASSIGNMENT,
edge_kind::CONTROL,
edge_kind::ALIAS,
edge_kind::MEM_LOAD,
];
let first_seed = vec![0b1000u32];
let second_seed = vec![0b0010u32];
let first_cpu = slice_closure_cpu(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&first_seed,
);
let second_cpu = slice_closure_cpu(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&second_seed,
);
let plan = prepare_slice_plan(4, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("slice plan must prepare once for CUDA parity");
let retained = plan.retained_graph_bytes();
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let first_gpu = slice_closure_plan_borrowed_into_with_scratch_via(
&dispatch_into,
&plan,
&first_seed,
16,
&mut scratch,
)
.expect("first prepared CUDA slice run must converge");
let second_gpu = slice_closure_plan_borrowed_into_with_scratch_via(
&dispatch_into,
&plan,
&second_seed,
16,
&mut scratch,
)
.expect("second prepared CUDA slice run must converge");
assert_eq!(plan.retained_graph_bytes(), retained);
assert_eq!(scratch.output_slot_count(), 1);
assert_eq!(first_gpu, first_cpu);
assert_eq!(second_gpu, second_cpu);
assert_eq!(first_gpu, vec![0b1111u32]);
assert_eq!(second_gpu, vec![0b0011u32]);
}
#[test]
fn cuda_slice_resident_frontier_reuse_parity() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let edge_offsets = vec![0u32, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 3];
let edge_kind_mask = vec![
edge_kind::ASSIGNMENT,
edge_kind::CONTROL,
edge_kind::ALIAS,
edge_kind::MEM_LOAD,
];
let first_seed = vec![0b1000u32];
let second_seed = vec![0b0010u32];
let first_cpu = slice_closure_cpu(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&first_seed,
);
let second_cpu = slice_closure_cpu(
4,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&second_seed,
);
let plan = prepare_slice_plan(4, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("slice plan must prepare for resident CUDA parity");
let config = DispatchConfig::default();
let pipeline = backend
.compile_native(plan.program(), &config)
.expect("CUDA native compile must succeed for resident slice parity")
.expect("CUDA backend registration must return a native compiled pipeline for resident slice parity");
let resident = FixedPointResidentGraph::upload(&backend, plan.graph())
.expect("CUDA backend must upload slice graph as resident resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let mut resident_frontier = FixedPointResidentFrontierScratch::default();
{
let borrowed = FixedPointBorrowedResidentPlan::new(&resident, pipeline);
let first_gpu = borrowed
.slice_reusing_frontier(
&backend,
&first_seed,
16,
&config,
&mut scratch,
&mut resident_frontier,
)
.expect("first resident CUDA slice run must converge");
let second_gpu = borrowed
.slice_reusing_frontier(
&backend,
&second_seed,
16,
&config,
&mut scratch,
&mut resident_frontier,
)
.expect("second resident CUDA slice run must converge");
assert_eq!(first_gpu, first_cpu);
assert_eq!(second_gpu, second_cpu);
assert_eq!(first_gpu, vec![0b1111u32]);
assert_eq!(second_gpu, vec![0b0011u32]);
}
resident_frontier
.clear(&backend)
.expect("resident slice frontier resources must free cleanly");
resident
.free(&backend)
.expect("resident slice graph resources must free cleanly");
}
#[test]
fn cuda_slice_resident_sequence_window_uses_final_convergence_readback_only() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let edge_offsets = vec![0u32, 1, 2, 3, 4, 4];
let edge_targets = vec![1u32, 2, 3, 4];
let edge_kind_mask = vec![edge_kind::ASSIGNMENT; 4];
let seed_bits = vec![0b10000u32];
let cpu = slice_closure_cpu(5, &edge_offsets, &edge_targets, &edge_kind_mask, &seed_bits);
let plan = prepare_slice_plan(5, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("slice plan must prepare for sequence-window resident CUDA parity");
let config = DispatchConfig::default();
let pipeline = backend
.compile_native(plan.program(), &config)
.expect("CUDA native compile must succeed for borrowed resident slice sequence-window parity")
.expect("CUDA backend registration must return a native compiled pipeline for borrowed resident slice sequence-window parity");
let resident = FixedPointResidentGraph::upload(&backend, plan.graph())
.expect("CUDA backend must upload slice sequence-window graph resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let mut resident_frontier = FixedPointResidentFrontierScratch::default();
backend.reset_telemetry();
let borrowed = FixedPointBorrowedResidentPlan::new(&resident, pipeline);
let gpu = borrowed
.slice_reusing_frontier_sequence_window(
&backend,
&plan,
&seed_bits,
16,
&mut scratch,
&mut resident_frontier,
)
.expect("sequence-window resident CUDA slice dispatch must converge");
let telemetry = backend.telemetry_snapshot();
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![0b11111u32]);
assert_eq!(
telemetry.readback_bytes, 8,
"Fix: sequence-window slice resident solve must read only final frontier plus one changed flag, not poll every iteration."
);
assert!(
telemetry.sync_points < 16,
"Fix: sequence-window slice resident solve must not synchronize once per fixed-point iteration; observed {} sync points.",
telemetry.sync_points
);
assert!(
telemetry.param_upload_bytes < telemetry.kernel_launches.saturating_mul(4),
"Fix: sequence-window slice resident solve must hoist repeated fixed-point launch parameter uploads; observed {} parameter bytes across {} launches.",
telemetry.param_upload_bytes,
telemetry.kernel_launches
);
resident_frontier
.clear(&backend)
.expect("sequence-window resident slice frontier resources must free cleanly");
resident
.free(&backend)
.expect("sequence-window resident slice graph resources must free cleanly");
}
#[test]
fn cuda_slice_resident_sequence_window_reads_changed_flag_not_previous_frontier() {
let backend = CudaBackendRegistration::new(live_dispatcher());
let node_count = 65_u32;
let edge_offsets = (0..=node_count)
.map(|node| node.min(node_count - 1))
.collect::<Vec<_>>();
let edge_targets = (1..node_count).collect::<Vec<_>>();
let edge_kind_mask = vec![edge_kind::ASSIGNMENT; edge_targets.len()];
let seed_bits = vec![0, 0, 1];
let cpu = slice_closure_cpu(
node_count,
&edge_offsets,
&edge_targets,
&edge_kind_mask,
&seed_bits,
);
let plan = prepare_slice_plan(node_count, &edge_offsets, &edge_targets, &edge_kind_mask)
.expect("multiword slice plan must prepare for resident CUDA changed-flag parity");
let config = DispatchConfig::default();
let pipeline = backend
.compile_native(plan.program(), &config)
.expect("CUDA native compile must succeed for multiword borrowed resident slice sequence-window parity")
.expect("CUDA backend registration must return a native compiled pipeline for multiword borrowed resident slice sequence-window parity");
let resident = FixedPointResidentGraph::upload(&backend, plan.graph())
.expect("CUDA backend must upload multiword slice sequence-window graph resources");
let mut scratch = weir::fixed_point_scratch::FixedPointScratch::default();
let mut resident_frontier = FixedPointResidentFrontierScratch::default();
backend.reset_telemetry();
let borrowed = FixedPointBorrowedResidentPlan::new(&resident, pipeline);
let gpu = borrowed
.slice_reusing_frontier_sequence_window(
&backend,
&plan,
&seed_bits,
128,
&mut scratch,
&mut resident_frontier,
)
.expect("multiword changed-flag resident CUDA slice dispatch must converge");
let telemetry = backend.telemetry_snapshot();
assert_eq!(gpu, cpu);
assert_eq!(gpu, vec![u32::MAX, u32::MAX, 1]);
assert_eq!(
telemetry.readback_bytes, 16,
"Fix: multiword slice changed-flag sequence window must read one 4-byte changed flag plus the 12-byte final frontier; reading a previous frontier would be 24 bytes."
);
assert!(
telemetry.sync_points <= 2,
"Fix: changed-flag slice sequence window must use one seed-upload fence and one resident-window fence, not per-iteration synchronization; observed {} sync points.",
telemetry.sync_points
);
resident_frontier
.clear(&backend)
.expect("multiword sequence-window resident slice frontier resources must free cleanly");
resident
.free(&backend)
.expect("multiword sequence-window resident slice graph resources must free cleanly");
}