Coordinate foreground search and background inference CPU budgets

This commit is contained in:
karl committed 2026-10-13 01:56:03 +02:00
1 parent 6b78c8bb7f
commit d85746db5b
12 files changed
+858 -60

No files matched your search

+34 -4
View File
@@ -7,7 +7,7 @@ use std::{
path::{Path, PathBuf},
};
const SETTINGS_VERSION: u32 = 1;
const SETTINGS_VERSION: u32 = 2;
const MAX_SETTINGS_BYTES: u64 = 128 * 1024;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
@@ -27,7 +27,7 @@ impl Default for Settings {
Self {
version: SETTINGS_VERSION,
roots: Vec::new(),
cpu_threads: 1,
cpu_threads: 2,
model_directory: None,
}
}
@@ -71,7 +71,7 @@ pub struct SettingsStore {
impl SettingsStore {
pub fn load(path: PathBuf) -> Result<Self, String> {
let value = match fs::metadata(&path) {
let mut value = match fs::metadata(&path) {
Ok(metadata) => {
if metadata.len() > MAX_SETTINGS_BYTES {
return Err("Settings file exceeds the size limit.".into());
@@ -82,6 +82,15 @@ impl SettingsStore {
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Settings::default(),
Err(error) => return Err(error.to_string()),
};
// Version 1 applied the value independently to both workers. Reserve
// one background thread while retaining the old query allocation.
if value.version == 1 {
if !(1..=8).contains(&value.cpu_threads) {
return Err("CPU threads must be between 1 and 8.".into());
}
value.version = SETTINGS_VERSION;
value.cpu_threads = (value.cpu_threads + 1).min(8);
}
let store = Self { path, value };
store.value.validate()?;
Ok(store)
@@ -126,7 +135,7 @@ mod tests {
let directory = tempfile::tempdir().unwrap();
let path = directory.path().join("settings.json");
let mut store = SettingsStore::load(path.clone()).unwrap();
assert_eq!(store.value.cpu_threads, 1);
assert_eq!(store.value.cpu_threads, 2);
store.add_root(directory.path()).unwrap();
store.add_root(directory.path()).unwrap();
let mut next = store.value.clone();
@@ -175,6 +184,8 @@ mod tests {
fs::write(&path, r#"{"version":1,"roots":[],"cpu_threads":1}"#).unwrap();
let store = SettingsStore::load(path).unwrap();
assert!(store.value.model_directory.is_none());
assert_eq!(store.value.version, 2);
assert_eq!(store.value.cpu_threads, 2);
let invalid = Settings {
model_directory: Some(PathBuf::from("relative")),
..Settings::default()
@@ -199,3 +210,22 @@ mod tests {
);
}
}
#[cfg(test)]
mod budget_migration_tests {
use super::*;
#[test]
fn version_two_single_thread_is_explicit_and_invalid_legacy_budget_is_rejected() {
let directory = tempfile::tempdir().unwrap();
let path = directory.path().join("settings.json");
fs::write(&path, r#"{"version":2,"roots":[],"cpu_threads":1}"#).unwrap();
assert_eq!(
SettingsStore::load(path.clone()).unwrap().value.cpu_threads,
1
);
fs::write(&path, r#"{"version":1,"roots":[],"cpu_threads":9}"#).unwrap();
assert!(SettingsStore::load(path.clone()).is_err());
fs::write(&path, r#"{"version":1,"roots":[],"cpu_threads":8}"#).unwrap();
assert_eq!(SettingsStore::load(path).unwrap().value.cpu_threads, 8);
}
}