Coverage Report

Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/trueno/src/brick/profiler/tile_stats.rs
Line
Count
Source
1
//! Tile-level profiling statistics.
2
3
use std::time::Instant;
4
5
/// Tile-level profiling statistics.
6
///
7
/// Tracks per-tile performance metrics for hierarchical cache-blocked operations.
8
/// Used in conjunction with `TcbGeometry` and `TilingConfig` from the tiling module.
9
///
10
/// # Example
11
///
12
/// ```ignore
13
/// let mut profiler = BrickProfiler::new();
14
/// profiler.enable();
15
///
16
/// let tile_timer = profiler.start_tile(TileLevel::Macro, 0, 0);
17
/// // ... execute tile ...
18
/// profiler.stop_tile(tile_timer, 1024 * 1024);
19
/// ```
20
#[derive(Debug, Clone, Default)]
21
pub struct TileStats {
22
    /// Tile level (Macro/Midi/Micro)
23
    pub level: TileLevel,
24
    /// Total samples collected
25
    pub count: u64,
26
    /// Total elapsed time (nanoseconds)
27
    pub total_ns: u64,
28
    /// Min elapsed time (nanoseconds)
29
    pub min_ns: u64,
30
    /// Max elapsed time (nanoseconds)
31
    pub max_ns: u64,
32
    /// Total elements processed
33
    pub total_elements: u64,
34
    /// Total cache misses (estimated)
35
    pub cache_misses: u64,
36
    /// Total arithmetic operations
37
    pub total_flops: u64,
38
}
39
40
/// Tile hierarchy level for profiling.
41
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
42
pub enum TileLevel {
43
    /// Macro-tile: L3 cache / GPU global memory
44
    #[default]
45
    Macro,
46
    /// Midi-tile: L2 cache / GPU shared memory
47
    Midi,
48
    /// Micro-tile: Registers / SIMD lanes
49
    Micro,
50
}
51
52
impl TileLevel {
53
    /// Get the name of this tile level.
54
    #[must_use]
55
0
    pub const fn name(&self) -> &'static str {
56
0
        match self {
57
0
            TileLevel::Macro => "macro",
58
0
            TileLevel::Midi => "midi",
59
0
            TileLevel::Micro => "micro",
60
        }
61
0
    }
62
}
63
64
impl TileStats {
65
    /// Create new tile stats for a given level.
66
0
    pub fn new(level: TileLevel) -> Self {
67
0
        Self {
68
0
            level,
69
0
            count: 0,
70
0
            total_ns: 0,
71
0
            min_ns: u64::MAX,
72
0
            max_ns: 0,
73
0
            total_elements: 0,
74
0
            cache_misses: 0,
75
0
            total_flops: 0,
76
0
        }
77
0
    }
78
79
    /// Add a sample to statistics.
80
0
    pub fn add_sample(&mut self, elapsed_ns: u64, elements: u64, flops: u64) {
81
0
        self.count += 1;
82
0
        self.total_ns += elapsed_ns;
83
0
        self.min_ns = self.min_ns.min(elapsed_ns);
84
0
        self.max_ns = self.max_ns.max(elapsed_ns);
85
0
        self.total_elements += elements;
86
0
        self.total_flops += flops;
87
0
    }
88
89
    /// Average time in microseconds.
90
    #[must_use]
91
0
    pub fn avg_us(&self) -> f64 {
92
0
        if self.count == 0 {
93
0
            0.0
94
        } else {
95
0
            self.total_ns as f64 / self.count as f64 / 1000.0
96
        }
97
0
    }
98
99
    /// Throughput in elements/second.
100
    #[must_use]
101
0
    pub fn throughput(&self) -> f64 {
102
0
        if self.total_ns == 0 {
103
0
            0.0
104
        } else {
105
0
            self.total_elements as f64 / (self.total_ns as f64 / 1_000_000_000.0)
106
        }
107
0
    }
108
109
    /// Compute throughput in GFLOP/s.
110
    #[must_use]
111
0
    pub fn gflops(&self) -> f64 {
112
0
        if self.total_ns == 0 {
113
0
            0.0
114
        } else {
115
0
            self.total_flops as f64 / (self.total_ns as f64 / 1_000_000_000.0) / 1e9
116
        }
117
0
    }
118
119
    /// Arithmetic intensity (FLOP/byte) estimate.
120
    ///
121
    /// Assumes 4 bytes per element (f32).
122
    #[must_use]
123
0
    pub fn arithmetic_intensity(&self) -> f64 {
124
0
        if self.total_elements == 0 {
125
0
            0.0
126
        } else {
127
0
            self.total_flops as f64 / (self.total_elements as f64 * 4.0)
128
        }
129
0
    }
130
131
    /// Estimated cache efficiency (0.0-1.0).
132
    ///
133
    /// Based on ratio of actual throughput vs theoretical peak.
134
    #[must_use]
135
0
    pub fn cache_efficiency(&self, peak_gflops: f64) -> f64 {
136
0
        if peak_gflops <= 0.0 {
137
0
            0.0
138
        } else {
139
0
            (self.gflops() / peak_gflops).min(1.0)
140
        }
141
0
    }
142
}
143
144
/// Timer handle for tile-level profiling.
145
#[derive(Debug)]
146
pub struct TileTimer {
147
    /// Tile level
148
    pub(crate) level: TileLevel,
149
    /// Row index within parent tile (reserved for spatial analysis)
150
    pub(crate) _row: u32,
151
    /// Column index within parent tile (reserved for spatial analysis)
152
    pub(crate) _col: u32,
153
    /// Start time
154
    pub(crate) start: Instant,
155
}