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

@@ -5,7 +5,7 @@ use std::fs;
use std::path::Path;
use crate::schema::{preferences, projects, sessions};
use crate::settings::{GenerationPreferences, ReasoningMode};
use crate::settings::{ExecutionPreferences, GenerationPreferences, ReasoningMode};
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
@@ -25,6 +25,11 @@ pub struct AppPreferences {
pub min_p: Option<f32>,
pub seed: Option<String>,
pub reasoning_mode: String,
pub cpu_threads: Option<i32>,
pub power_percent: Option<i32>,
pub prefill_chunk: Option<i32>,
pub quality: bool,
pub warm_weights: bool,
}
impl Default for AppPreferences {
@@ -42,6 +47,11 @@ impl Default for AppPreferences {
min_p: None,
seed: None,
reasoning_mode: "high".into(),
cpu_threads: None,
power_percent: None,
prefill_chunk: None,
quality: false,
warm_weights: false,
}
}
}
@@ -67,6 +77,28 @@ impl AppPreferences {
preferences.validate()?;
Ok(preferences)
}
pub(crate) fn execution(&self) -> Result<ExecutionPreferences, String> {
Ok(ExecutionPreferences {
cpu_threads: self
.cpu_threads
.map(u32::try_from)
.transpose()
.map_err(|_| "Saved CPU helper threads is invalid.".to_owned())?,
power_percent: self
.power_percent
.map(u8::try_from)
.transpose()
.map_err(|_| "Saved GPU power is invalid.".to_owned())?,
prefill_chunk: self
.prefill_chunk
.map(u32::try_from)
.transpose()
.map_err(|_| "Saved prefill chunk is invalid.".to_owned())?,
quality: self.quality,
warm_weights: self.warm_weights,
})
}
}
#[derive(AsChangeset)]
@@ -83,6 +115,11 @@ struct PreferenceChanges<'a> {
min_p: Option<f32>,
seed: Option<&'a str>,
reasoning_mode: &'a str,
cpu_threads: Option<i32>,
power_percent: Option<i32>,
prefill_chunk: Option<i32>,
quality: bool,
warm_weights: bool,
}
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
@@ -186,8 +223,12 @@ impl Database {
dspark_enabled: bool,
idle_timeout_minutes: i32,
generation: &GenerationPreferences,
execution: &ExecutionPreferences,
) -> Result<AppPreferences, String> {
generation.validate()?;
let model = crate::model::ModelChoice::from_id(selected_model)
.ok_or_else(|| format!("Unsupported model: {selected_model}"))?;
execution.validate(model)?;
let seed = generation.seed.map(|seed| seed.to_string());
diesel::update(preferences::table.find(1))
.set(PreferenceChanges {
@@ -202,6 +243,11 @@ impl Database {
min_p: generation.min_p,
seed: seed.as_deref(),
reasoning_mode: generation.reasoning_mode.id(),
cpu_threads: execution.cpu_threads.map(|value| value as i32),
power_percent: execution.power_percent.map(i32::from),
prefill_chunk: execution.prefill_chunk.map(|value| value as i32),
quality: execution.quality,
warm_weights: execution.warm_weights,
})
.returning(AppPreferences::as_returning())
.get_result(&mut self.connection)
@@ -262,14 +308,15 @@ mod tests {
assert!(!preferences.dspark_enabled);
assert_eq!(preferences.idle_timeout_minutes, 10);
let generation = GenerationPreferences::default();
let execution = ExecutionPreferences::default();
assert!(
database
.update_preferences("glm-5.2", true, 30, &generation)
.update_preferences("glm-5.2", true, 30, &generation, &execution)
.is_err()
);
assert!(
database
.update_preferences("deepseek-v4-flash", false, 0, &generation)
.update_preferences("deepseek-v4-flash", false, 0, &generation, &execution)
.is_err()
);
let generation = GenerationPreferences {
@@ -278,8 +325,13 @@ mod tests {
reasoning_mode: ReasoningMode::Max,
..generation
};
let execution = ExecutionPreferences {
cpu_threads: Some(8),
quality: true,
..execution
};
database
.update_preferences("glm-5.2", false, 30, &generation)
.update_preferences("glm-5.2", false, 30, &generation, &execution)
.unwrap();
let project = database.create_project("DS4", "/tmp/ds4").unwrap();
@@ -302,6 +354,7 @@ mod tests {
assert_eq!(preferences.selected_model, "glm-5.2");
assert_eq!(preferences.idle_timeout_minutes, 30);
assert_eq!(preferences.generation().unwrap(), generation);
assert_eq!(preferences.execution().unwrap(), execution);
drop(reopened);
fs::remove_file(path).unwrap();
}