Files
Loki/internal/loki/backend_strata_split_test.go
T
MichaelandClaude Opus 5.5 615e58dd2f 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>
2026-10-16 15:16:37 +02:00

125 lines
5.0 KiB
Go

package loki
import (
"os"
"path/filepath"
"strings"
"testing"
)
// Partage des couches (#121 amont) : la clé « gpu » liste les deux cartes (le
// serveur de Strata en déduit --layer-split), et rien du mode d'aide ne subsiste.
func TestStrataBuildConfigLayerSplit(t *testing.T) {
base := map[string]any{
"args": []any{"--pack", "/p", "--vram-reserve-mib", "900"},
"vision": map[string]any{"exe": "/v"},
}
cfg := map[string]string{"STRATA_MAIN_GPU": "1", "STRATA_HELPER_GPU": "0", "STRATA_SPLIT": "layers"}
out, err := strataBuildConfig(base, cfg, "", "drop")
if err != nil {
t.Fatal(err)
}
g, ok := out["gpu"].([]any)
if !ok || len(g) != 2 || g[0] != 1 || g[1] != 0 {
t.Fatalf("gpu = %v, attendu [1 0] (principale d'abord, numéros nvidia-smi)", out["gpu"])
}
a := strataArgs(t, out)
if strataHasArg(a, "--remote-expert-opt") || strataHasArg(a, "--expert-cache-device1") {
t.Errorf("options du mode d'aide en partage des couches : %v", a)
}
if argAfter(a, "--vram-reserve-mib") != "900" {
t.Errorf("la réserve de VRAM de l'installeur doit rester : %v", a)
}
if argAfter(a, "--short-read") != "150" {
t.Errorf("lecture des prompts par la carte d'aide en partage des couches : %v", a)
}
env := out["env"].(map[string]any)
if env["STRATA_REMOTE_DROP"] != nil || env["STRATA_PREFILL_HELPER_SOURCE"] != nil {
t.Errorf("experts hors RAM ou source d'aide (mode d'aide) en partage des couches : %v", env)
}
if _, has := out["vision"].(map[string]any)["cuda_device"]; has {
t.Errorf("encodeur d'images déplacé sur la seconde carte en partage des couches")
}
// Sans la clé, rien ne change : le mode d'aide reste le défaut.
delete(cfg, "STRATA_SPLIT")
out, _ = strataBuildConfig(base, cfg, "", "drop")
if _, has := out["gpu"]; has {
t.Errorf("clé gpu posée en mode d'aide : %v", out["gpu"])
}
if !strataHasArg(strataArgs(t, out), "--remote-expert-opt") {
t.Errorf("mode d'aide perdu sans STRATA_SPLIT")
}
// Seconde carte coupée : pas de partage même si la clé traîne.
cfg["STRATA_SPLIT"], cfg["STRATA_HELPER"] = "layers", "0"
if strataLayerSplit(cfg) {
t.Errorf("partage des couches avec la seconde carte coupée")
}
}
// En partage des couches, la seconde carte ne garde pas d'experts : le mode
// hors RAM (qui compte sur elle pour en loger une part) n'est jamais choisi.
func TestStrataResolveExpertsLayerSplit(t *testing.T) {
home := t.TempDir()
t.Setenv("LOKI_HOME", home)
pack := filepath.Join(home, "pack")
_ = os.MkdirAll(pack, 0o755)
_ = os.WriteFile(filepath.Join(pack, "experts.bin"), []byte("x"), 0o644)
_ = os.MkdirAll(filepath.Join(strataSrcDir(), "engine-cuda12"), 0o755)
_ = os.WriteFile(strataEngineMarker(), []byte(strataEngineAsset+"\n"), 0o644)
args := []string{"--pack", pack}
cfg := map[string]string{"STRATA_CONFIG": "/x/strata-swift-iq3_xxs.json", "STRATA_HELPER_GPU": "1", "STRATA_DROP": "1"}
if got := strataResolveExperts(cfg, args, 44, 12); got != "drop" {
t.Fatalf("mode d'aide : %s, attendu drop", got)
}
cfg["STRATA_SPLIT"] = "layers"
if got := strataResolveExperts(cfg, args, 44, 12); got != "arena" {
t.Errorf("partage des couches : %s, attendu arena", got)
}
cfg["STRATA_EXPERTS"] = "ram"
if got := strataResolveExperts(cfg, args, 44, 12); got != "ram" {
t.Errorf("partage des couches, experts en RAM : %s, attendu ram", got)
}
}
func TestStrataApplySettingsSplit(t *testing.T) {
in := "ENGINE=strata\nSTRATA_HELPER_GPU=0\n"
req := strataSettingsReq{Ctx: 131072, KV: "fp16", Spec: 3, Vision: true, Helper: true, Split: "layers"}
out, err := strataApplySettings(in, req)
if err != nil || !strings.Contains(out, "STRATA_SPLIT=layers\n") {
t.Fatalf("STRATA_SPLIT=layers attendu : %q (%v)", out, err)
}
req.Split = "helper"
if out, _ = strataApplySettings(out, req); strings.Contains(out, "STRATA_SPLIT") {
t.Errorf("retour au mode d'aide : la clé doit disparaître : %q", out)
}
// un ancien client n'envoie pas « split » : la clé est conservée
req.Split = ""
out, _ = strataApplySettings("STRATA_SPLIT=layers\n", req)
if !strings.Contains(out, "STRATA_SPLIT=layers") {
t.Errorf("clé effacée par un client qui ne la connaît pas : %q", out)
}
req.Split = "nimporte"
if _, err := strataApplySettings(in, req); err == nil {
t.Errorf("répartition inconnue acceptée")
}
}
func TestStrataDetailsForLayerSplit(t *testing.T) {
home := t.TempDir()
t.Setenv("LOKI_HOME", home)
base := filepath.Join(home, "base.json")
_ = os.WriteFile(base, []byte(`{"args":["--pack","/p"],"vision":{"exe":"v"}}`), 0o644)
_ = os.MkdirAll(presetsDir(), 0o755)
preset := "ENGINE=strata\nSTRATA_CONFIG=" + base + "\nSTRATA_MAIN_GPU=1\nSTRATA_HELPER_GPU=0\nSTRATA_SPLIT=layers\n"
_ = os.WriteFile(filepath.Join(presetsDir(), "X.env"), []byte(preset), 0o644)
env := strataEnv{GPUs: []strataGPU{{Index: 0, Name: "NVIDIA GeForce RTX 3060", VRAMGB: 12}, {Index: 1, Name: "NVIDIA GeForce RTX 3060", VRAMGB: 12}}}
d := strataDetailsFor("X", env)
if d == nil {
t.Fatal("pas de détails")
}
if !d.Split || !d.HelperOn || d.HelperGPU == "" || d.VisionGPU != d.MainGPU || d.ShortRead != "150" {
t.Errorf("%+v", *d)
}
}