mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 14:08:11 +02:00
Strata : seconde carte en partage des couches au choix, l'aide aux experts reste le défaut
Repris d'AJEAN 38919238 (#121 amont) et de la partie moteur de 6db3f3d0 : STRATA_SPLIT=layers dans le preset fait lister les deux cartes dans la clé « gpu » de la config (principale d'abord, numéros nvidia-smi) ; le serveur de Strata en déduit --layer-split. Rien du mode d'aide ne subsiste alors : ni --expert-cache-device1 / --remote-expert-opt, ni source d'aide à la lecture des prompts, ni encodeur d'images déplacé ; la réserve de VRAM de l'installeur reste. Sans la clé, ou la seconde carte coupée, rien ne change. Propre à Loki : le placement des experts selon la RAM disponible ne choisit jamais le mode hors RAM en partage des couches (la seconde carte n'y garde pas d'experts, la marge calculée pour elle serait fausse). Réglages : « split » (helper ou layers ; absent = inchangé pour un ancien client), détail split_layers. Fenêtre Strata : la case « Carte d'appoint » devient un choix « Seconde carte » (non utilisée, aide aux experts, partage des couches) ; la carte de configuration du moteur actif l'affiche. Façade Rust alignée (strata/mod.rs, strata/api.rs, tests portés) ; journal de parité régénéré sous Linux avec les réglages et l'affichage du partage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9792953d62
commit
615e58dd2f
13 files changed
+823
-120
No files matched your search
@@ -345,7 +345,7 @@ impl Strata {
|
||||
"mmap": mode == "disk" || mode == "arena", "drop": mode == "drop",
|
||||
"experts": experts, "mode_label": experts_label(&mode), "mode": mode,
|
||||
"main_gpu": main_gpu,
|
||||
"has_helper": false, "helper_on": false,
|
||||
"has_helper": false, "helper_on": false, "split_layers": false,
|
||||
});
|
||||
let kvr = val("--kv-resident");
|
||||
if !kvr.is_empty() {
|
||||
@@ -356,6 +356,7 @@ impl Strata {
|
||||
d["has_helper"] = json!(true);
|
||||
if helper_on(&pc) {
|
||||
d["helper_on"] = json!(true);
|
||||
d["split_layers"] = json!(layer_split(&pc));
|
||||
let hg = gpu_name(h);
|
||||
if !hg.is_empty() {
|
||||
d["helper_gpu"] = json!(hg);
|
||||
@@ -825,6 +826,7 @@ pub async fn serve(
|
||||
("vision", Kind::Bool),
|
||||
("helper", Kind::Bool),
|
||||
("experts", Kind::Str),
|
||||
("split", Kind::Str),
|
||||
],
|
||||
);
|
||||
if let Some(e) = d.err.clone() {
|
||||
@@ -838,6 +840,7 @@ pub async fn serve(
|
||||
vision: d.bool("vision"),
|
||||
helper: d.bool("helper"),
|
||||
experts: d.str("experts"),
|
||||
split: d.str("split"),
|
||||
};
|
||||
if r.preset.contains(['/', '\\']) || r.preset.is_empty() {
|
||||
return fail(StatusCode::BAD_REQUEST, "preset invalide");
|
||||
|
||||
@@ -287,6 +287,13 @@ pub fn helper_on(cfg: &Cfg) -> bool {
|
||||
!h.is_empty() && h != "-1" && cfg_get(cfg, "STRATA_HELPER") != "0"
|
||||
}
|
||||
|
||||
/// `strataLayerSplit` : les deux cartes se partagent les couches
|
||||
/// (`STRATA_SPLIT=layers`) au lieu que la seconde n'aide que pour une part
|
||||
/// des experts. Un choix, jamais imposé : le mode d'aide reste le défaut.
|
||||
pub fn layer_split(cfg: &Cfg) -> bool {
|
||||
helper_on(cfg) && cfg_get(cfg, "STRATA_SPLIT") == "layers"
|
||||
}
|
||||
|
||||
/// `strataResolveExperts` : le mode lancé (drop, ram, arena, disk), d'après
|
||||
/// le choix du preset et la RAM disponible.
|
||||
pub fn resolve_experts(
|
||||
@@ -297,7 +304,9 @@ pub fn resolve_experts(
|
||||
helper_gb: f64,
|
||||
) -> &'static str {
|
||||
let bin_ready = pack_has_experts_bin(args) && paths.engine_installed() == ENGINE_ASSET;
|
||||
let drop_ready = bin_ready && helper_on(cfg) && cfg_get(cfg, "STRATA_DROP") != "0";
|
||||
// (jamais en partage des couches : la seconde carte n'y garde pas d'experts)
|
||||
let drop_ready =
|
||||
bin_ready && helper_on(cfg) && !layer_split(cfg) && cfg_get(cfg, "STRATA_DROP") != "0";
|
||||
let arena = arena_gb(cfg);
|
||||
match cfg_get(cfg, "STRATA_EXPERTS")
|
||||
.trim()
|
||||
@@ -411,7 +420,18 @@ pub fn build_config(base: &Value, cfg: &Cfg, api_key: &str, mode: &str) -> Resul
|
||||
args = set_arg(args, flag, v);
|
||||
}
|
||||
let helper = cfg_get(cfg, "STRATA_HELPER_GPU").trim();
|
||||
let has_helper = helper_on(cfg);
|
||||
let mut has_helper = helper_on(cfg);
|
||||
if layer_split(cfg) {
|
||||
// Partage des couches : la clé « gpu » liste les deux cartes (numéros
|
||||
// nvidia-smi), le serveur de Strata en déduit --layer-split.
|
||||
let main = cfg_get(cfg, "STRATA_MAIN_GPU")
|
||||
.trim()
|
||||
.parse::<i64>()
|
||||
.unwrap_or(0);
|
||||
let second = helper.parse::<i64>().unwrap_or(0);
|
||||
out.insert("gpu".into(), json!([main, second]));
|
||||
has_helper = false;
|
||||
}
|
||||
if has_helper {
|
||||
args = set_arg(args, "--expert-cache-device1", "auto");
|
||||
if !has_arg(&args, "--remote-expert-opt") {
|
||||
@@ -788,6 +808,8 @@ pub struct SettingsReq {
|
||||
pub vision: bool,
|
||||
pub helper: bool,
|
||||
pub experts: String,
|
||||
/// « helper » ou « layers » ; vide = inchangé (anciens clients).
|
||||
pub split: String,
|
||||
}
|
||||
|
||||
/// `strataApplySettings` : réécrit les clés du preset. Pure.
|
||||
@@ -808,6 +830,9 @@ pub fn apply_settings(content: &str, r: &SettingsReq) -> Result<String, String>
|
||||
{
|
||||
return Err(format!("placement des experts inconnu : {}", r.experts));
|
||||
}
|
||||
if !r.split.is_empty() && r.split != "helper" && r.split != "layers" {
|
||||
return Err(format!("répartition inconnue : {}", r.split));
|
||||
}
|
||||
let mut set: Vec<(&str, String)> = vec![
|
||||
("CTX", r.ctx.to_string()),
|
||||
("STRATA_KV", r.kv.clone()),
|
||||
@@ -818,6 +843,11 @@ pub fn apply_settings(content: &str, r: &SettingsReq) -> Result<String, String>
|
||||
if !r.experts.is_empty() {
|
||||
set.push(("STRATA_EXPERTS", r.experts.clone()));
|
||||
}
|
||||
if !r.split.is_empty() {
|
||||
// « helper » est le défaut : la clé disparaît plutôt que d'être écrite
|
||||
let v = if r.split == "layers" { "layers" } else { "" };
|
||||
set.push(("STRATA_SPLIT", v.into()));
|
||||
}
|
||||
let mut lines: Vec<String> = Vec::new();
|
||||
for l in content.trim_end_matches('\n').split('\n') {
|
||||
let k = l.trim().split_once('=').map_or(l.trim(), |(k, _)| k);
|
||||
@@ -827,6 +857,9 @@ pub fn apply_settings(content: &str, r: &SettingsReq) -> Result<String, String>
|
||||
lines.push(l.to_string());
|
||||
}
|
||||
for (k, v) in set {
|
||||
if k == "STRATA_SPLIT" && v.is_empty() {
|
||||
continue;
|
||||
}
|
||||
lines.push(format!("{k}={v}"));
|
||||
}
|
||||
Ok(lines.join("\n") + "\n")
|
||||
|
||||
@@ -405,6 +405,89 @@ fn hors_ram_reserve_et_contexte() {
|
||||
}
|
||||
}
|
||||
|
||||
// `TestStrataBuildConfigLayerSplit`.
|
||||
#[test]
|
||||
fn partage_des_couches() {
|
||||
let base = json!({
|
||||
"args": ["--pack", "/p", "--vram-reserve-mib", "900"],
|
||||
"vision": { "exe": "/v" },
|
||||
});
|
||||
let mut c = cfg(&[
|
||||
("STRATA_MAIN_GPU", "1"),
|
||||
("STRATA_HELPER_GPU", "0"),
|
||||
("STRATA_SPLIT", "layers"),
|
||||
]);
|
||||
let out = build_config(&base, &c, "", "drop").unwrap();
|
||||
assert_eq!(out["gpu"], json!([1, 0]));
|
||||
let a = args_of(&out);
|
||||
assert!(!has_arg(&a, "--remote-expert-opt") && !has_arg(&a, "--expert-cache-device1"));
|
||||
assert_eq!(arg_after(&a, "--vram-reserve-mib"), "900");
|
||||
assert_eq!(arg_after(&a, "--short-read"), "150");
|
||||
assert!(out["env"].get("STRATA_REMOTE_DROP").is_none());
|
||||
assert!(out["env"].get("STRATA_PREFILL_HELPER_SOURCE").is_none());
|
||||
assert!(out["vision"].get("cuda_device").is_none());
|
||||
c.remove("STRATA_SPLIT");
|
||||
let out = build_config(&base, &c, "", "drop").unwrap();
|
||||
assert!(out.get("gpu").is_none());
|
||||
assert!(has_arg(&args_of(&out), "--remote-expert-opt"));
|
||||
c.insert("STRATA_SPLIT".into(), "layers".into());
|
||||
c.insert("STRATA_HELPER".into(), "0".into());
|
||||
assert!(!layer_split(&c));
|
||||
}
|
||||
|
||||
// `TestStrataResolveExpertsLayerSplit`.
|
||||
#[test]
|
||||
fn partage_des_couches_sans_hors_ram() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let p = Paths {
|
||||
home: d.path().to_path_buf(),
|
||||
};
|
||||
let pack = d.path().join("pack");
|
||||
std::fs::create_dir_all(&pack).unwrap();
|
||||
std::fs::write(pack.join("experts.bin"), "x").unwrap();
|
||||
std::fs::create_dir_all(p.src_dir().join("engine-cuda12")).unwrap();
|
||||
std::fs::write(p.engine_marker(), format!("{ENGINE_ASSET}\n")).unwrap();
|
||||
let args = vec!["--pack".to_string(), pack.to_string_lossy().into_owned()];
|
||||
let mut c = cfg(&[
|
||||
("STRATA_CONFIG", "/x/strata-swift-iq3_xxs.json"),
|
||||
("STRATA_HELPER_GPU", "1"),
|
||||
("STRATA_DROP", "1"),
|
||||
]);
|
||||
assert_eq!(resolve_experts(&p, &c, &args, 44.0, 12.0), "drop");
|
||||
c.insert("STRATA_SPLIT".into(), "layers".into());
|
||||
assert_eq!(resolve_experts(&p, &c, &args, 44.0, 12.0), "arena");
|
||||
c.insert("STRATA_EXPERTS".into(), "ram".into());
|
||||
assert_eq!(resolve_experts(&p, &c, &args, 44.0, 12.0), "ram");
|
||||
}
|
||||
|
||||
// `TestStrataApplySettingsSplit`.
|
||||
#[test]
|
||||
fn reglages_de_la_seconde_carte() {
|
||||
let input = "ENGINE=strata\nSTRATA_HELPER_GPU=0\n";
|
||||
let mut r = SettingsReq {
|
||||
ctx: 131072,
|
||||
kv: "fp16".into(),
|
||||
spec: 3,
|
||||
vision: true,
|
||||
helper: true,
|
||||
split: "layers".into(),
|
||||
..SettingsReq::default()
|
||||
};
|
||||
let out = apply_settings(input, &r).unwrap();
|
||||
assert!(out.contains("STRATA_SPLIT=layers\n"), "{out:?}");
|
||||
r.split = "helper".into();
|
||||
let out = apply_settings(&out, &r).unwrap();
|
||||
assert!(!out.contains("STRATA_SPLIT"), "{out:?}");
|
||||
r.split = String::new();
|
||||
let out = apply_settings("STRATA_SPLIT=layers\n", &r).unwrap();
|
||||
assert!(out.contains("STRATA_SPLIT=layers"), "{out:?}");
|
||||
r.split = "nimporte".into();
|
||||
assert_eq!(
|
||||
apply_settings(input, &r).unwrap_err(),
|
||||
"répartition inconnue : nimporte"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reglages_des_experts() {
|
||||
let input = "ENGINE=strata\nSTRATA_EXPERTS=auto\n";
|
||||
|
||||
Reference in new issue
Block a user