1use std::sync::OnceLock;
21
22#[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
28const PLATFORM_CACHE_LINE: usize = 128; #[cfg(all(target_arch = "aarch64", not(target_vendor = "apple")))]
31const PLATFORM_CACHE_LINE: usize = 64; #[cfg(not(target_arch = "aarch64"))]
34const PLATFORM_CACHE_LINE: usize = 64; #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
41const PLATFORM_PAR_THRESHOLD: usize = 16_384; #[cfg(not(all(target_arch = "aarch64", target_vendor = "apple")))]
44const PLATFORM_PAR_THRESHOLD: usize = 30_000;
45
46struct HwInfo {
50 total_cpus: usize,
51 perf_cores: usize, l1d_cache: usize, l2_cache: usize, cache_line: usize, }
56
57impl HwInfo {
58 fn detect() -> Self {
59 let total = std::thread::available_parallelism()
60 .map(|n| n.get())
61 .unwrap_or(2);
62
63 #[allow(unused_mut)]
66 let mut info = HwInfo {
67 total_cpus: total,
68 perf_cores: 0,
69 l1d_cache: 0,
70 l2_cache: 0,
71 cache_line: 0,
72 };
73
74 #[cfg(target_vendor = "apple")]
75 {
76 info.perf_cores = sysctl_usize("hw.perflevel0.physicalcpu").unwrap_or(0);
77 info.l1d_cache = sysctl_usize("hw.l1dcachesize").unwrap_or(0);
78 info.l2_cache = sysctl_usize("hw.l2cachesize").unwrap_or(0);
79 info.cache_line = sysctl_usize("hw.cachelinesize").unwrap_or(0);
80 }
81
82 #[cfg(target_os = "linux")]
83 {
84 if let Ok(v) = std::fs::read_to_string(
86 "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size",
87 ) {
88 info.cache_line = v.trim().parse().unwrap_or(0);
89 }
90 if let Ok(v) = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cache/index0/size")
91 {
92 let s = v.trim().to_uppercase();
94 if s.ends_with('K') {
95 info.l1d_cache = s[..s.len() - 1].parse::<usize>().unwrap_or(0) * 1024;
96 } else {
97 info.l1d_cache = s.parse().unwrap_or(0);
98 }
99 }
100 }
101
102 info
103 }
104
105 fn optimal_workers(&self) -> usize {
111 let base = if self.perf_cores > 0 {
112 self.perf_cores / 2
113 } else if cfg!(all(target_arch = "aarch64", target_vendor = "apple")) {
114 self.total_cpus / 2
115 } else {
116 self.total_cpus.saturating_mul(3) / 4
117 };
118 base.clamp(1, 32)
119 }
120
121 fn cache_line(&self) -> usize {
123 if self.cache_line > 0 {
124 self.cache_line
125 } else {
126 PLATFORM_CACHE_LINE
127 }
128 }
129
130 #[allow(dead_code)]
132 fn fuse_attn_threshold(&self) -> usize {
133 if self.l1d_cache > 0 {
134 64
140 } else {
141 64
142 }
143 }
144}
145
146#[cfg(target_vendor = "apple")]
147fn sysctl_usize(name: &str) -> Option<usize> {
148 use std::ffi::CString;
149 let cname = CString::new(name).ok()?;
150 let mut val: u64 = 0;
151 let mut len = std::mem::size_of::<u64>();
152 unsafe {
153 unsafe extern "C" {
154 fn sysctlbyname(
155 name: *const i8,
156 oldp: *mut u8,
157 oldlenp: *mut usize,
158 newp: *const u8,
159 newlen: usize,
160 ) -> i32;
161 }
162 let ret = sysctlbyname(
163 cname.as_ptr(),
164 &mut val as *mut u64 as *mut u8,
165 &mut len,
166 std::ptr::null(),
167 0,
168 );
169 if ret == 0 { Some(val as usize) } else { None }
170 }
171}
172
173#[derive(Debug, Clone)]
175pub struct RuntimeConfig {
176 pub pool_workers: usize,
178
179 pub par_threshold: usize,
181 pub min_rows_per_thread: usize,
182
183 pub sdpa_seq_threshold: usize,
185
186 pub arena_alignment: usize,
188
189 pub ln_eps_default: f32,
191 pub attn_mask_neg_inf: f32,
192 pub score_skip_threshold: f32,
193 pub mask_binary_threshold: f32,
194
195 pub verbose: u8,
197}
198
199impl Default for RuntimeConfig {
200 fn default() -> Self {
201 Self::auto_detect()
202 }
203}
204
205impl RuntimeConfig {
206 pub fn auto_detect() -> Self {
208 let hw = HwInfo::detect();
209
210 Self {
211 pool_workers: hw.optimal_workers(),
212 par_threshold: PLATFORM_PAR_THRESHOLD,
213 min_rows_per_thread: 4,
214 sdpa_seq_threshold: 32,
215 arena_alignment: hw.cache_line(),
216 ln_eps_default: 1e-12,
217 attn_mask_neg_inf: -1e9,
218 score_skip_threshold: 1e-8,
219 mask_binary_threshold: 0.5,
220 verbose: 0,
221 }
222 }
223
224 pub fn from_env() -> Self {
226 let mut cfg = Self::auto_detect();
227
228 if let Some(v) = rlx_ir::env::var("RLX_WORKERS")
229 && let Ok(n) = v.parse::<usize>()
230 {
231 cfg.pool_workers = if n == 0 { cfg.pool_workers } else { n.min(32) };
232 }
233 if let Some(v) = rlx_ir::env::var("RLX_PAR_THRESHOLD")
234 && let Ok(n) = v.parse()
235 {
236 cfg.par_threshold = n;
237 }
238 if let Some(v) = rlx_ir::env::var("RLX_SDPA_THRESHOLD")
239 && let Ok(n) = v.parse()
240 {
241 cfg.sdpa_seq_threshold = n;
242 }
243 if let Some(v) = rlx_ir::env::var("RLX_ARENA_ALIGN")
244 && let Ok(n) = v.parse()
245 {
246 cfg.arena_alignment = n;
247 }
248 if let Some(v) = rlx_ir::env::var("RLX_VERBOSE")
249 && let Ok(n) = v.parse()
250 {
251 cfg.verbose = n;
252 }
253
254 if cfg.verbose >= 1 {
255 let hw = HwInfo::detect();
256 eprintln!(
257 "[rlx] hw: {} CPUs ({} P-cores), L1={}KB, L2={}KB, cacheline={}B",
258 hw.total_cpus,
259 hw.perf_cores,
260 hw.l1d_cache / 1024,
261 hw.l2_cache / 1024,
262 hw.cache_line()
263 );
264 eprintln!(
265 "[rlx] config: workers={}, par_thr={}, sdpa_thr={}, align={}",
266 cfg.pool_workers, cfg.par_threshold, cfg.sdpa_seq_threshold, cfg.arena_alignment
267 );
268 }
269
270 cfg
271 }
272
273 pub fn install(&self) {
276 rlx_ir::env::set("RLX_WORKERS", self.pool_workers.to_string());
277 rlx_ir::env::set("RLX_PAR_THRESHOLD", self.par_threshold.to_string());
278 rlx_ir::env::set("RLX_SDPA_THRESHOLD", self.sdpa_seq_threshold.to_string());
279 rlx_ir::env::set("RLX_ARENA_ALIGN", self.arena_alignment.to_string());
280 rlx_ir::env::set("RLX_VERBOSE", self.verbose.to_string());
281 }
282
283 pub fn global() -> &'static RuntimeConfig {
285 static CONFIG: OnceLock<RuntimeConfig> = OnceLock::new();
286 CONFIG.get_or_init(RuntimeConfig::from_env)
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 #[test]
295 fn auto_detect_sane_defaults() {
296 let cfg = RuntimeConfig::auto_detect();
297 assert!(cfg.pool_workers >= 1);
298 assert!(cfg.pool_workers <= 32);
299 assert!(cfg.arena_alignment >= 64);
301 assert!(cfg.verbose == 0);
302 }
303
304 #[test]
305 fn global_is_consistent() {
306 let a = RuntimeConfig::global();
307 let b = RuntimeConfig::global();
308 assert_eq!(a.pool_workers, b.pool_workers);
309 }
310
311 #[test]
312 fn hw_detection() {
313 let hw = HwInfo::detect();
314 assert!(hw.total_cpus >= 1);
315 #[cfg(target_vendor = "apple")]
317 assert!(
318 hw.cache_line > 0,
319 "expected sysctl to return cache line size"
320 );
321 }
322}