/home/noah/src/trueno/src/tiling/geometry.rs
Line | Count | Source |
1 | | //! TCB geometry types and level definitions. |
2 | | |
3 | | use serde::{Deserialize, Serialize}; |
4 | | use std::fmt; |
5 | | |
6 | | // ============================================================================ |
7 | | // TILE-001: TcbGeometry Struct |
8 | | // ============================================================================ |
9 | | |
10 | | /// Dimensions for a Tiling Compute Block |
11 | | /// |
12 | | /// Represents the (M, N, K) dimensions of a tile in matrix operations: |
13 | | /// - M: Output rows |
14 | | /// - N: Output columns |
15 | | /// - K: Reduction dimension (inner product) |
16 | | /// |
17 | | /// # Alignment Constraints |
18 | | /// |
19 | | /// Per the TCB-03 pattern (Tile Quantization Alignment), K must align with |
20 | | /// the quantization superblock size: |
21 | | /// - Q4_0: K % 32 == 0 |
22 | | /// - Q4_K: K % 256 == 0 |
23 | | /// - Q8_0: K % 32 == 0 |
24 | | #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] |
25 | | pub struct TcbGeometry { |
26 | | /// Items processed in M dimension (rows) |
27 | | pub m: u32, |
28 | | /// Items processed in N dimension (columns) |
29 | | pub n: u32, |
30 | | /// Reduction dimension (inner product) |
31 | | pub k: u32, |
32 | | /// Alignment requirement in bytes (typically 16 for SIMD, 32 for AVX2, 64 for AVX-512) |
33 | | pub alignment: u32, |
34 | | } |
35 | | |
36 | | impl TcbGeometry { |
37 | | /// Create a new TCB geometry |
38 | | /// |
39 | | /// # Panics |
40 | | /// Panics if any dimension is zero. |
41 | | #[must_use] |
42 | 0 | pub fn new(m: u32, n: u32, k: u32) -> Self { |
43 | 0 | assert!(m > 0 && n > 0 && k > 0, "TCB dimensions must be non-zero"); |
44 | 0 | Self { |
45 | 0 | m, |
46 | 0 | n, |
47 | 0 | k, |
48 | 0 | alignment: 16, // Default to SSE/NEON alignment |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | /// Create geometry with explicit alignment |
53 | | #[must_use] |
54 | 0 | pub fn with_alignment(m: u32, n: u32, k: u32, alignment: u32) -> Self { |
55 | 0 | assert!(m > 0 && n > 0 && k > 0, "TCB dimensions must be non-zero"); |
56 | 0 | assert!( |
57 | 0 | alignment.is_power_of_two(), |
58 | 0 | "Alignment must be power of 2" |
59 | | ); |
60 | 0 | Self { m, n, k, alignment } |
61 | 0 | } |
62 | | |
63 | | /// Calculate arithmetic intensity (FLOPS per byte loaded) |
64 | | /// |
65 | | /// For GEMM: AI = (2 * M * N * K) / (M*K + K*N) * sizeof(f32) |
66 | | /// |
67 | | /// Higher AI means compute-bound; lower means memory-bound. |
68 | | #[must_use] |
69 | 0 | pub fn arithmetic_intensity(&self) -> f32 { |
70 | 0 | let flops = 2.0 * self.m as f64 * self.n as f64 * self.k as f64; |
71 | 0 | let bytes = (self.m as f64 * self.k as f64 + self.k as f64 * self.n as f64) * 4.0; |
72 | 0 | (flops / bytes) as f32 |
73 | 0 | } |
74 | | |
75 | | /// Calculate total elements in the tile |
76 | | #[must_use] |
77 | 0 | pub fn total_elements(&self) -> u64 { |
78 | 0 | self.m as u64 * self.n as u64 |
79 | 0 | } |
80 | | |
81 | | /// Calculate total FLOPs for this tile |
82 | | #[must_use] |
83 | 0 | pub fn total_flops(&self) -> u64 { |
84 | 0 | 2 * self.m as u64 * self.n as u64 * self.k as u64 |
85 | 0 | } |
86 | | |
87 | | /// Check if K dimension aligns with Q4_K superblock (256) |
88 | | #[must_use] |
89 | 0 | pub fn is_q4k_aligned(&self) -> bool { |
90 | 0 | self.k % 256 == 0 |
91 | 0 | } |
92 | | |
93 | | /// Check if K dimension aligns with Q4_0/Q8_0 block (32) |
94 | | #[must_use] |
95 | 0 | pub fn is_q4_0_aligned(&self) -> bool { |
96 | 0 | self.k % 32 == 0 |
97 | 0 | } |
98 | | |
99 | | /// Calculate bytes needed for A tile (M × K × sizeof(f32)) |
100 | | #[must_use] |
101 | 0 | pub fn a_tile_bytes(&self) -> usize { |
102 | 0 | self.m as usize * self.k as usize * 4 |
103 | 0 | } |
104 | | |
105 | | /// Calculate bytes needed for B tile (K × N × sizeof(f32)) |
106 | | #[must_use] |
107 | 0 | pub fn b_tile_bytes(&self) -> usize { |
108 | 0 | self.k as usize * self.n as usize * 4 |
109 | 0 | } |
110 | | |
111 | | /// Calculate bytes needed for C tile (M × N × sizeof(f32)) |
112 | | #[must_use] |
113 | 0 | pub fn c_tile_bytes(&self) -> usize { |
114 | 0 | self.m as usize * self.n as usize * 4 |
115 | 0 | } |
116 | | |
117 | | /// Check if tile fits in given cache size (bytes) |
118 | | #[must_use] |
119 | 0 | pub fn fits_in_cache(&self, cache_bytes: usize) -> bool { |
120 | 0 | self.a_tile_bytes() + self.b_tile_bytes() <= cache_bytes |
121 | 0 | } |
122 | | } |
123 | | |
124 | | impl Default for TcbGeometry { |
125 | 0 | fn default() -> Self { |
126 | | // Sensible default: 4×4 micro-tile for SIMD |
127 | 0 | Self { |
128 | 0 | m: 4, |
129 | 0 | n: 4, |
130 | 0 | k: 4, |
131 | 0 | alignment: 16, |
132 | 0 | } |
133 | 0 | } |
134 | | } |
135 | | |
136 | | impl fmt::Display for TcbGeometry { |
137 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
138 | 0 | write!( |
139 | 0 | f, |
140 | 0 | "TCB({}×{}×{}, align={}, AI={:.2})", |
141 | | self.m, |
142 | | self.n, |
143 | | self.k, |
144 | | self.alignment, |
145 | 0 | self.arithmetic_intensity() |
146 | | ) |
147 | 0 | } |
148 | | } |
149 | | // ============================================================================ |
150 | | // TILE-001: Tiling Levels |
151 | | // ============================================================================ |
152 | | |
153 | | /// Tiling hierarchy level |
154 | | #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] |
155 | | pub enum TcbLevel { |
156 | | /// Macro-tile: L3 cache / GPU global memory partitioning |
157 | | Macro, |
158 | | /// Midi-tile: L2 cache / GPU shared memory |
159 | | Midi, |
160 | | /// Micro-tile: Registers / SIMD lanes |
161 | | Micro, |
162 | | } |
163 | | |
164 | | impl TcbLevel { |
165 | | /// Get typical cache size for this level (x86_64) |
166 | | #[must_use] |
167 | 0 | pub fn typical_cache_bytes(&self) -> usize { |
168 | 0 | match self { |
169 | 0 | TcbLevel::Macro => 32 * 1024 * 1024, // 32 MB L3 |
170 | 0 | TcbLevel::Midi => 256 * 1024, // 256 KB L2 |
171 | 0 | TcbLevel::Micro => 32 * 1024, // 32 KB L1 |
172 | | } |
173 | 0 | } |
174 | | } |