Add Metal execution preferences

This commit is contained in:
Georg Bauer
2026-07-24 15:37:13 +02:00
parent bccce697af
commit ac464317d4
8 changed files with 326 additions and 16 deletions

View File

@@ -6,8 +6,74 @@ pub(crate) const REASONING_MODES: [ReasoningMode; 3] = [
ReasoningMode::Max,
ReasoningMode::Direct,
];
const THINK_MAX_MIN_CONTEXT: i32 = 393_216;
const MAX_CPU_THREADS: u32 = 32;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub(crate) struct ExecutionPreferences {
pub(crate) cpu_threads: Option<u32>,
pub(crate) power_percent: Option<u8>,
pub(crate) prefill_chunk: Option<u32>,
pub(crate) quality: bool,
pub(crate) warm_weights: bool,
}
impl ExecutionPreferences {
pub(crate) fn validate(&self, model: ModelChoice) -> Result<(), String> {
if self.cpu_threads == Some(0) {
return Err("CPU helper threads must be a positive whole number.".into());
}
if self
.cpu_threads
.is_some_and(|threads| threads > i32::MAX as u32)
{
return Err("CPU helper threads is too large.".into());
}
if self
.power_percent
.is_some_and(|power| !(1..=100).contains(&power))
{
return Err("GPU power must be between 1 and 100 percent.".into());
}
if self.prefill_chunk == Some(0) {
return Err("Prefill chunk must be a positive whole number.".into());
}
if self
.prefill_chunk
.is_some_and(|chunk| chunk > i32::MAX as u32)
{
return Err("Prefill chunk is too large.".into());
}
if model == ModelChoice::Glm52 {
if self.power_percent.is_some_and(|power| power != 100) {
return Err("GLM 5.2 currently requires 100% GPU power.".into());
}
if self.prefill_chunk.is_some() {
return Err("GLM 5.2 selects its prefill chunk automatically.".into());
}
}
Ok(())
}
pub(crate) fn engine_settings(&self) -> EngineExecutionSettings {
EngineExecutionSettings {
cpu_threads: self.cpu_threads.unwrap_or(0).min(MAX_CPU_THREADS),
power_percent: self.power_percent.unwrap_or(0),
prefill_chunk: self.prefill_chunk.unwrap_or(0),
quality: self.quality,
warm_weights: self.warm_weights,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct EngineExecutionSettings {
pub(crate) cpu_threads: u32,
pub(crate) power_percent: u8,
pub(crate) prefill_chunk: u32,
pub(crate) quality: bool,
pub(crate) warm_weights: bool,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub(crate) enum ReasoningMode {
@@ -156,4 +222,27 @@ mod tests {
assert_eq!((effective.top_p, effective.min_p), (0.4, 0.2));
assert_eq!(effective.reasoning_mode, ReasoningMode::High);
}
#[test]
fn execution_settings_keep_ds4_automatic_values_and_glm_rules() {
let defaults = ExecutionPreferences::default().engine_settings();
assert_eq!(
(
defaults.cpu_threads,
defaults.power_percent,
defaults.prefill_chunk
),
(0, 0, 0)
);
let tuned = ExecutionPreferences {
cpu_threads: Some(100),
power_percent: Some(50),
prefill_chunk: Some(4096),
..ExecutionPreferences::default()
};
assert!(tuned.validate(ModelChoice::DeepSeekV4Flash).is_ok());
assert!(tuned.validate(ModelChoice::Glm52).is_err());
assert_eq!(tuned.engine_settings().cpu_threads, MAX_CPU_THREADS);
}
}