sokuto_runtime/engine/
config.rs1use std::path::PathBuf;
7
8use ort::session::builder::GraphOptimizationLevel;
9
10pub fn auto_intra_threads(pool_size: usize, max_cap: usize) -> usize {
22 let physical = num_cpus::get_physical().max(1);
23 let pool = pool_size.max(1);
24 let per_session = physical / pool;
25 per_session.clamp(1, max_cap)
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum ExecutionProvider {
31 #[default]
33 Auto,
34 CoreML,
36 CUDA,
38 TensorRT,
40 CPU,
42}
43
44impl ExecutionProvider {
45 pub fn name(&self) -> &'static str {
47 match self {
48 Self::Auto => "Auto",
49 Self::CoreML => "CoreML",
50 Self::CUDA => "CUDA",
51 Self::TensorRT => "TensorRT",
52 Self::CPU => "CPU",
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
59pub enum OptimizationLevel {
60 Disable,
62 Basic,
64 Extended,
66 #[default]
68 All,
69}
70
71impl OptimizationLevel {
72 pub fn to_ort_level(self) -> GraphOptimizationLevel {
74 match self {
75 Self::Disable => GraphOptimizationLevel::Disable,
76 Self::Basic => GraphOptimizationLevel::Level1,
77 Self::Extended => GraphOptimizationLevel::Level2,
78 Self::All => GraphOptimizationLevel::Level3,
79 }
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct SessionConfig {
86 pub preferred_providers: Vec<ExecutionProvider>,
88 pub intra_threads: Option<usize>,
90 pub inter_threads: Option<usize>,
92 pub parallel_execution: bool,
94 pub optimization_level: OptimizationLevel,
96 pub enable_mem_arena: bool,
98 pub pool_size: usize,
100 pub optimized_model_path: Option<PathBuf>,
102}
103
104impl Default for SessionConfig {
105 fn default() -> Self {
106 #[cfg(target_os = "macos")]
107 let default_providers = vec![ExecutionProvider::CoreML, ExecutionProvider::CPU];
108
109 #[cfg(not(target_os = "macos"))]
110 let default_providers = vec![
111 ExecutionProvider::TensorRT,
112 ExecutionProvider::CUDA,
113 ExecutionProvider::CPU,
114 ];
115
116 Self {
117 preferred_providers: default_providers,
118 intra_threads: None,
119 inter_threads: Some(1),
120 parallel_execution: false,
121 optimization_level: OptimizationLevel::All,
122 enable_mem_arena: true,
123 pool_size: 1,
124 optimized_model_path: None,
125 }
126 }
127}
128
129impl SessionConfig {
130 pub fn auto() -> Self {
132 let mut config = Self::default();
133 config.intra_threads = Some(auto_intra_threads(config.pool_size, 8));
134 config
135 }
136
137 pub fn cpu_only() -> Self {
139 Self {
140 preferred_providers: vec![ExecutionProvider::CPU],
141 intra_threads: None,
142 inter_threads: Some(1),
143 parallel_execution: false,
144 optimization_level: OptimizationLevel::All,
145 enable_mem_arena: true,
146 pool_size: 1,
147 optimized_model_path: None,
148 }
149 }
150
151 pub fn for_tier1() -> Self {
156 let mut config = Self::cpu_only();
157 config.intra_threads = Some(auto_intra_threads(config.pool_size, 4));
158 config
159 }
160
161 pub fn for_tier2() -> Self {
165 let mut config = Self::cpu_only();
166 config.intra_threads = Some(auto_intra_threads(config.pool_size, 8));
167 config
168 }
169
170 pub fn with_auto_threads(mut self) -> Self {
172 self.intra_threads = Some(auto_intra_threads(self.pool_size, 8));
173 self
174 }
175
176 pub fn with_threads(mut self, intra: Option<usize>, inter: Option<usize>) -> Self {
178 self.intra_threads = intra;
179 self.inter_threads = inter;
180 self
181 }
182
183 pub fn with_parallel_execution(mut self, parallel: bool) -> Self {
185 self.parallel_execution = parallel;
186 self
187 }
188
189 pub fn with_optimization_level(mut self, level: OptimizationLevel) -> Self {
191 self.optimization_level = level;
192 self
193 }
194
195 pub fn with_memory_arena(mut self, enable: bool) -> Self {
197 self.enable_mem_arena = enable;
198 self
199 }
200
201 pub fn with_pool_size(mut self, size: usize) -> Self {
203 self.pool_size = size.max(1);
204 self
205 }
206
207 pub fn with_optimized_model_path(mut self, path: impl Into<PathBuf>) -> Self {
209 self.optimized_model_path = Some(path.into());
210 self
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_auto_intra_threads() {
220 let physical = num_cpus::get_physical();
221 assert!(physical >= 1);
222
223 let t1 = auto_intra_threads(1, 4);
224 assert!((1..=4).contains(&t1));
225
226 let t2 = auto_intra_threads(1, 8);
227 assert!((1..=8).contains(&t2));
228
229 let t_pool = auto_intra_threads(4, 8);
230 assert!(t_pool >= 1);
231 }
232
233 #[test]
234 fn test_tier_presets() {
235 let cfg1 = SessionConfig::for_tier1();
236 assert_eq!(cfg1.preferred_providers, vec![ExecutionProvider::CPU]);
237 assert_eq!(cfg1.inter_threads, Some(1));
238 assert!(!cfg1.parallel_execution);
239 assert!(cfg1.intra_threads.is_some());
240 assert!(cfg1.intra_threads.unwrap() <= 4);
241
242 let cfg2 = SessionConfig::for_tier2();
243 assert_eq!(cfg2.preferred_providers, vec![ExecutionProvider::CPU]);
244 assert_eq!(cfg2.inter_threads, Some(1));
245 assert!(!cfg2.parallel_execution);
246 assert!(cfg2.intra_threads.is_some());
247 assert!(cfg2.intra_threads.unwrap() <= 8);
248 }
249}