trueno_gpu/testing/
mod.rs1#[cfg(feature = "viz")]
27mod gpu_renderer;
28pub mod stress;
29pub mod tui;
30
31#[cfg(feature = "viz")]
32pub use gpu_renderer::{compare_png_bytes, ColorPalette, GpuPixelRenderer, PixelDiffResult, Rgb};
33
34pub use stress::{
35 verify_performance, Anomaly, AnomalyKind, FrameProfile, PerformanceResult,
36 PerformanceThresholds, StressConfig, StressReport, StressRng, StressTestRunner,
37};
38
39pub use tui::{progress_bar, render_to_string, TuiConfig, TuiState};
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum BugClass {
44 RaceCondition,
46 FloatingPointDrift,
48 AccumulatorInit,
50 LoopCounter,
52 MemoryAddressing,
54 ThreadSync,
56 Unknown,
58}
59
60impl BugClass {
61 #[must_use]
63 pub const fn description(&self) -> &'static str {
64 match self {
65 Self::RaceCondition => "Race condition: non-deterministic output",
66 Self::FloatingPointDrift => "FP precision drift in accumulation",
67 Self::AccumulatorInit => "Accumulator not initialized to zero",
68 Self::LoopCounter => "Loop counter SSA bug (wrong iteration count)",
69 Self::MemoryAddressing => "Memory addressing error (offset/alignment)",
70 Self::ThreadSync => "Thread synchronization issue (barrier)",
71 Self::Unknown => "Unknown bug pattern",
72 }
73 }
74
75 #[must_use]
77 pub const fn suggested_fix(&self) -> &'static str {
78 match self {
79 Self::RaceCondition => "Add __syncthreads() / bar.sync; use atomics",
80 Self::FloatingPointDrift => "Use Kahan summation or pairwise reduction",
81 Self::AccumulatorInit => "Initialize accumulator to 0.0 before loop",
82 Self::LoopCounter => "Fix loop bound; use in-place += instead of reassignment",
83 Self::MemoryAddressing => "Check index calculations and stride",
84 Self::ThreadSync => "Add barrier synchronization at workgroup boundaries",
85 Self::Unknown => "Manual inspection required",
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_bug_class_descriptions() {
96 let variants = [
98 BugClass::RaceCondition,
99 BugClass::FloatingPointDrift,
100 BugClass::AccumulatorInit,
101 BugClass::LoopCounter,
102 BugClass::MemoryAddressing,
103 BugClass::ThreadSync,
104 BugClass::Unknown,
105 ];
106
107 for variant in variants {
108 assert!(
109 !variant.description().is_empty(),
110 "{variant:?} has empty description"
111 );
112 assert!(
113 !variant.suggested_fix().is_empty(),
114 "{variant:?} has empty fix"
115 );
116 }
117 }
118
119 #[test]
120 fn test_bug_class_equality() {
121 assert_eq!(BugClass::RaceCondition, BugClass::RaceCondition);
122 assert_ne!(BugClass::RaceCondition, BugClass::Unknown);
123 }
124
125 #[test]
126 fn test_bug_class_clone() {
127 let original = BugClass::FloatingPointDrift;
128 let cloned = original;
129 assert_eq!(original, cloned);
130 }
131}
132
133#[cfg(all(test, feature = "viz"))]
135mod integration_tests;