use super::super::super::*;
#[test]
fn test_f136_cpa_parallel_heavy_branch() {
let mut graph = ExecutionGraph::new();
let root = graph.push_scope(ExecutionNode::Layer { index: 0 });
graph.pop_scope();
let branch_a = graph.push_scope(ExecutionNode::Brick {
id: BrickId::QkvProjection,
timing_ns: 10_000_000, elements: 4096,
});
graph.pop_scope();
let b1 = graph.push_scope(ExecutionNode::Brick {
id: BrickId::RmsNorm,
timing_ns: 3_000_000, elements: 1024,
});
graph.pop_scope();
let b2 = graph.push_scope(ExecutionNode::Brick {
id: BrickId::AttentionScore,
timing_ns: 3_000_000,
elements: 1024,
});
graph.pop_scope();
let b3 = graph.push_scope(ExecutionNode::Brick {
id: BrickId::GateProjection,
timing_ns: 3_000_000,
elements: 1024,
});
graph.pop_scope();
let b4 = graph.push_scope(ExecutionNode::Brick {
id: BrickId::UpProjection,
timing_ns: 3_000_000,
elements: 1024,
});
graph.pop_scope();
let b5 = graph.push_scope(ExecutionNode::Brick {
id: BrickId::DownProjection,
timing_ns: 3_000_000,
elements: 1024,
});
graph.pop_scope();
graph.add_dependency(root, branch_a);
graph.add_dependency(root, b1);
graph.add_dependency(b1, b2);
graph.add_dependency(b2, b3);
graph.add_dependency(b3, b4);
graph.add_dependency(b4, b5);
let (path, total_ns) = graph.critical_path();
assert!(
total_ns >= 15_000_000,
"F136: Critical path should be >= 15ms, got {}ms",
total_ns / 1_000_000
);
assert!(path.len() >= 5, "F136: Critical path should have >= 5 nodes, got {}", path.len());
}
#[test]
fn test_f137_depends_on_overrides_sequence() {
let mut graph = ExecutionGraph::new();
let a = graph.push_scope(ExecutionNode::Brick {
id: BrickId::RmsNorm,
timing_ns: 100_000, elements: 1024,
});
graph.pop_scope();
let b = graph.push_scope(ExecutionNode::Brick {
id: BrickId::QkvProjection,
timing_ns: 500_000, elements: 4096,
});
graph.pop_scope();
let c = graph.push_scope(ExecutionNode::Brick {
id: BrickId::AttentionScore,
timing_ns: 200_000, elements: 2048,
});
graph.pop_scope();
graph.add_dependency(a, c);
graph.add_dependency(c, b);
let (path, total_ns) = graph.critical_path();
assert!(
total_ns >= 800_000,
"F137: DependsOn path should be >= 800µs, got {}µs",
total_ns / 1000
);
let b_pos = path.iter().position(|&id| id == b);
let c_pos = path.iter().position(|&id| id == c);
if let (Some(bp), Some(cp)) = (b_pos, c_pos) {
assert!(bp > cp, "F137: B must come after C in critical path");
}
}
#[test]
fn test_f138_roofline_anomaly_detection() {
let mut graph = ExecutionGraph::new();
let _kernel = graph.record_kernel_launch_with_metrics(
"impossible_kernel",
0xBAD,
(128, 1, 1),
(256, 1, 1),
8192,
100_000, 50.0, 1000.0, );
let distances = graph.roofline_distance(83.0, 1008.0);
for &dist in distances.values() {
assert!(
dist <= 0.0 || dist >= 0.0, "F138: Should handle anomalous TFLOPS gracefully"
);
}
}
#[test]
fn test_f139_ping_pong_large_scale() {
let mut graph = ExecutionGraph::new();
for i in 0..100 {
let _h2d = graph.record_transfer(
&format!("host_buf_{}", i),
&format!("device_buf_{}", i),
1024 * 1024 * 1024, TransferDirection::H2D,
Some(50_000_000), );
let _d2h = graph.record_transfer(
&format!("device_buf_{}", i),
&format!("host_buf_{}", i),
1024 * 1024 * 1024, TransferDirection::D2H,
Some(50_000_000), );
}
let patterns = graph.detect_ping_pong();
assert!(
patterns.len() >= 50,
"F139: Should detect >= 50 ping-pong patterns, got {}",
patterns.len()
);
}
#[test]
fn test_f140_transfer_metadata_preservation() {
let mut graph = ExecutionGraph::new();
let transfer_id = graph.record_transfer(
"src_buffer",
"dst_buffer",
4 * 1024 * 1024, TransferDirection::H2D,
Some(25_000), );
let node = &graph.nodes()[transfer_id.0 as usize];
if let ExecutionNode::Transfer { src, dst, bytes, direction, timing_ns } = node {
assert_eq!(src, "src_buffer", "F140: Source buffer mismatch");
assert_eq!(dst, "dst_buffer", "F140: Dest buffer mismatch");
assert_eq!(*bytes, 4 * 1024 * 1024, "F140: Bytes mismatch");
assert_eq!(*direction, TransferDirection::H2D, "F140: Direction mismatch");
assert_eq!(*timing_ns, Some(25_000), "F140: Timing mismatch");
} else {
panic!("F140: Expected Transfer node");
}
}