mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
NGL=999 : la sentinelle « toutes les couches » devient -ngl auto
Le correctif précédent ne pouvait pas s'appliquer. Il ne posait « -ngl auto »
que si la clé NGL était ABSENTE de config.env — or defaultConfig() y sème
NGL=999 sur chaque installation neuve. La quasi-totalité des configurations la
portent donc sans que personne ne l'ait choisie, le code la lisait comme un
choix délibéré, et l'abandon revenait intact :
W common_fit_params: failed to fit params to free device memory:
n_gpu_layers already set by user to 999, abort
999 n'a jamais été un nombre de couches : c'est la sentinelle historique
« toutes ». Sur un moteur qui sait mesurer la VRAM libre, elle devient donc
« -ngl auto », et Loki le dit sur stderr plutôt que de le faire en douce. Tout
autre nombre reste intouché — c'est un vrai choix. NGL=all force l'ancien
comportement, NGL=auto n'envoie toujours aucun drapeau, et un moteur ancien
reçoit toujours 999 (l'omettre le ferait tourner 100 % CPU).
- La décision sort dans nglArgs(), fonction pure : la seule question qui
demande le moteur arrive déjà tranchée, donc elle se teste sans lancer
llama-server. 10 cas couverts.
- binFitsLayersItself() double la lecture fine de l'aide par la présence de
--load-mode. Les deux sont arrivés dans la même vague ; une description
reformulée ou une colonne plus large ne doit pas faire conclure « moteur
incapable » et réimposer 999.
- L'aide de la clé et le sous-titre du champ disent la nouvelle règle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fedbaf32a0
commit
2585d2c2e1
5 files changed
+91
-20
No files matched your search
@@ -84,6 +84,41 @@ func binSupportsNGLAuto(bin string) bool {
|
|||||||
return strings.Contains(h[i:end], "'auto'")
|
return strings.Contains(h[i:end], "'auto'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// binFitsLayersItself : ce moteur sait-il répartir les couches tout seul ?
|
||||||
|
//
|
||||||
|
// La lecture fine de l'aide (binSupportsNGLAuto) reste la source de vérité, mais
|
||||||
|
// elle dépend de la mise en page d'un texte d'aide — une description reformulée
|
||||||
|
// ou une colonne plus large, et on conclut « non » sur un moteur parfaitement
|
||||||
|
// capable, donc on lui réimpose 999 et l'abandon revient. --load-mode est arrivé
|
||||||
|
// dans la même vague que « -ngl auto » : sa présence sert de second témoin, plus
|
||||||
|
// grossier mais insensible à la mise en page.
|
||||||
|
func binFitsLayersItself(bin string) bool {
|
||||||
|
return binSupportsNGLAuto(bin) || binSupportsLoadMode(bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// nglArgs traduit la valeur NGL du preset en arguments, et renvoie au passage la
|
||||||
|
// note à afficher quand Loki a substitué quelque chose. Fonction pure : la seule
|
||||||
|
// question qui demande le moteur (« sait-il répartir les couches tout seul ? »)
|
||||||
|
// arrive déjà tranchée, ce qui la rend testable sans lancer llama-server.
|
||||||
|
func nglArgs(ngl string, fitsItself bool) ([]string, string) {
|
||||||
|
ngl = strings.TrimSpace(ngl)
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(ngl, "auto"):
|
||||||
|
return nil, "" // rien du tout : le moteur décide seul
|
||||||
|
case ngl == "999" && fitsItself:
|
||||||
|
return []string{"-ngl", "auto"},
|
||||||
|
"NGL=999 (sentinelle « toutes les couches ») → -ngl auto : ce moteur mesure lui-même la " +
|
||||||
|
"VRAM libre. NGL=all pour forcer l'ancien comportement."
|
||||||
|
case ngl != "":
|
||||||
|
return []string{"-ngl", ngl}, ""
|
||||||
|
case fitsItself:
|
||||||
|
return []string{"-ngl", "auto"}, ""
|
||||||
|
default:
|
||||||
|
// Moteur ancien : omettre -ngl le ferait tourner 100 % CPU.
|
||||||
|
return []string{"-ngl", "999"}, ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// hasAnyFlag dit si l'utilisateur a déjà posé l'un de ces drapeaux dans
|
// hasAnyFlag dit si l'utilisateur a déjà posé l'un de ces drapeaux dans
|
||||||
// EXTRA_ARGS. Loki ajoute plusieurs valeurs par défaut (--parallel, -ngl) : les
|
// EXTRA_ARGS. Loki ajoute plusieurs valeurs par défaut (--parallel, -ngl) : les
|
||||||
// ajouter EN PLUS de celles de l'utilisateur fait râler le moteur (« argument
|
// ajouter EN PLUS de celles de l'utilisateur fait râler le moteur (« argument
|
||||||
@@ -240,31 +275,32 @@ func cmdServe(args []string) error {
|
|||||||
if !hasAnyFlag(extra, "--parallel", "-np") {
|
if !hasAnyFlag(extra, "--parallel", "-np") {
|
||||||
llmArgs = append(llmArgs, "--parallel", get("PARALLEL", "1"))
|
llmArgs = append(llmArgs, "--parallel", get("PARALLEL", "1"))
|
||||||
}
|
}
|
||||||
// Couches GPU. Trois cas, dans cet ordre :
|
// Couches GPU. Quatre cas, dans cet ordre :
|
||||||
//
|
//
|
||||||
// NGL=<nombre> → -ngl <nombre> (l'utilisateur tranche)
|
// NGL=auto → rien du tout (le moteur décide seul)
|
||||||
// NGL=auto → rien du tout (compat : anciens presets)
|
// NGL=999 → -ngl auto sur un moteur récent (voir plus bas)
|
||||||
|
// NGL=<nombre> → -ngl <nombre> (l'utilisateur tranche pour de vrai)
|
||||||
// clé absente → -ngl auto si le moteur le propose, sinon -ngl 999
|
// clé absente → -ngl auto si le moteur le propose, sinon -ngl 999
|
||||||
//
|
//
|
||||||
// Imposer un nombre désarme common_fit_params, qui mesure la VRAM libre et
|
// Imposer un NOMBRE désarme common_fit_params, qui mesure la VRAM libre et
|
||||||
// choisit combien de couches y tiennent : « n_gpu_layers already set by user
|
// choisit combien de couches y tiennent : « n_gpu_layers already set by user
|
||||||
// to 999, abort ». Le moteur pousse alors tout sur le GPU, échoue en
|
// to 999, abort ». Le moteur pousse alors tout sur le GPU, échoue en
|
||||||
// cudaMalloc ou se replie à moitié sur le CPU — débit effondré, GPU à 100 %.
|
// cudaMalloc ou se replie à moitié sur le CPU — débit effondré, GPU à 100 %.
|
||||||
// D'où « auto » par défaut dès que le moteur sait le faire. Sur un moteur
|
//
|
||||||
// plus ancien, qui ne connaît pas la valeur, on garde 999 : omettre -ngl le
|
// 999 est traité à part parce que ce n'a JAMAIS été un nombre de couches :
|
||||||
// ferait tourner 100 % CPU.
|
// c'est la sentinelle historique « toutes », semée dans config.env par
|
||||||
|
// defaultConfig() sur chaque installation neuve. La quasi-totalité des
|
||||||
|
// configurations la portent donc sans que personne ne l'ait choisie — la
|
||||||
|
// traiter comme un choix délibéré, c'est condamner tout le monde à l'abandon
|
||||||
|
// ci-dessus. Sur un moteur qui connaît « auto », 999 devient donc auto, et on
|
||||||
|
// le DIT sur stderr plutôt que de le faire en douce. Qui veut réellement
|
||||||
|
// forcer tout sur le GPU écrit NGL=all (ou un nombre qui n'est pas 999).
|
||||||
if !hasAnyFlag(extra, "-ngl", "--n-gpu-layers", "--gpu-layers") {
|
if !hasAnyFlag(extra, "-ngl", "--n-gpu-layers", "--gpu-layers") {
|
||||||
ngl := get("NGL", "")
|
args, note := nglArgs(get("NGL", ""), binFitsLayersItself(bin))
|
||||||
switch {
|
if note != "" {
|
||||||
case strings.EqualFold(ngl, "auto"):
|
fmt.Fprintln(os.Stderr, "[loki serve] "+note)
|
||||||
// rien : le moteur décide seul
|
|
||||||
case ngl != "":
|
|
||||||
llmArgs = append(llmArgs, "-ngl", ngl)
|
|
||||||
case binSupportsNGLAuto(bin):
|
|
||||||
llmArgs = append(llmArgs, "-ngl", "auto")
|
|
||||||
default:
|
|
||||||
llmArgs = append(llmArgs, "-ngl", "999")
|
|
||||||
}
|
}
|
||||||
|
llmArgs = append(llmArgs, args...)
|
||||||
}
|
}
|
||||||
if ktv != "" {
|
if ktv != "" {
|
||||||
llmArgs = append(llmArgs, "-ctk", ktv)
|
llmArgs = append(llmArgs, "-ctk", ktv)
|
||||||
|
|||||||
@@ -56,3 +56,38 @@ func TestNormalizeLoadFlags(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNGLArgs(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
ngl string
|
||||||
|
fitsItself bool
|
||||||
|
want []string
|
||||||
|
wantNote bool
|
||||||
|
}{
|
||||||
|
// Le cas qui motive tout : defaultConfig() sème NGL=999 sur chaque
|
||||||
|
// installation neuve. Personne ne l'a choisi, et le moteur récent
|
||||||
|
// abandonne son calcul de VRAM dès qu'on lui impose un nombre.
|
||||||
|
{"sentinelle 999, moteur récent", "999", true, []string{"-ngl", "auto"}, true},
|
||||||
|
{"sentinelle 999, moteur ancien", "999", false, []string{"-ngl", "999"}, false},
|
||||||
|
{"nombre choisi, jamais touché", "28", true, []string{"-ngl", "28"}, false},
|
||||||
|
{"nombre choisi, moteur ancien", "28", false, []string{"-ngl", "28"}, false},
|
||||||
|
{"all reste all", "all", true, []string{"-ngl", "all"}, false},
|
||||||
|
{"auto : aucun drapeau", "auto", true, nil, false},
|
||||||
|
{"auto insensible à la casse", "AUTO", true, nil, false},
|
||||||
|
{"espaces parasites autour de la sentinelle", " 999 ", true, []string{"-ngl", "auto"}, true},
|
||||||
|
{"clé absente, moteur récent", "", true, []string{"-ngl", "auto"}, false},
|
||||||
|
{"clé absente, moteur ancien", "", false, []string{"-ngl", "999"}, false},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
got, note := nglArgs(c.ngl, c.fitsItself)
|
||||||
|
if !reflect.DeepEqual(got, c.want) {
|
||||||
|
t.Fatalf("args = %q, want %q", got, c.want)
|
||||||
|
}
|
||||||
|
if (note != "") != c.wantNote {
|
||||||
|
t.Fatalf("note = %q, en voulait-on une ? %v", note, c.wantNote)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ var configTemplate = []struct{ key, help string }{
|
|||||||
{"HOST", "adresse d'écoute du moteur (défaut 0.0.0.0)"},
|
{"HOST", "adresse d'écoute du moteur (défaut 0.0.0.0)"},
|
||||||
{"PORT", "port du moteur (défaut 8080)"},
|
{"PORT", "port du moteur (défaut 8080)"},
|
||||||
{"CTX", "taille du contexte (défaut 32768)"},
|
{"CTX", "taille du contexte (défaut 32768)"},
|
||||||
{"NGL", "couches déportées sur le GPU (défaut 999 = tout ; auto = ce qui tient en VRAM)"},
|
{"NGL", "couches déportées sur le GPU (999 ou auto = ce qui tient en VRAM ; all = tout, quitte à saturer)"},
|
||||||
{"BATCH", "batch (défaut 2048)"},
|
{"BATCH", "batch (défaut 2048)"},
|
||||||
{"UBATCH", "micro-batch (défaut 512)"},
|
{"UBATCH", "micro-batch (défaut 512)"},
|
||||||
{"THREADS", "threads CPU, 0 = auto"},
|
{"THREADS", "threads CPU, 0 = auto"},
|
||||||
|
|||||||
@@ -3121,7 +3121,7 @@ html[data-files="1"] #files-btn{color:var(--accent)}
|
|||||||
<span class="pe-row-c"><input id="s-ctx" class="pe-val" type="number" min="0" step="1024" placeholder="32768" oninput="cfgWriteKey('CTX', this.value)"><span class="pe-unit">tok</span></span>
|
<span class="pe-row-c"><input id="s-ctx" class="pe-val" type="number" min="0" step="1024" placeholder="32768" oninput="cfgWriteKey('CTX', this.value)"><span class="pe-unit">tok</span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pe-row">
|
<div class="pe-row">
|
||||||
<span class="pe-row-l">Couches sur GPU<span class="pe-sub">999 = tout sur le GPU · auto = ce qui tient en VRAM</span></span>
|
<span class="pe-row-l">Couches sur GPU<span class="pe-sub">999 ou auto = ce qui tient en VRAM · all = tout, quitte à saturer</span></span>
|
||||||
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"></span>
|
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pe-row">
|
<div class="pe-row">
|
||||||
|
|||||||
@@ -984,7 +984,7 @@ document.documentElement.setAttribute('data-side',localStorage.getItem('loki-sid
|
|||||||
<span class="pe-row-c"><input id="s-ctx" class="pe-val" type="number" min="0" step="1024" placeholder="32768" oninput="cfgWriteKey('CTX', this.value)"><span class="pe-unit">tok</span></span>
|
<span class="pe-row-c"><input id="s-ctx" class="pe-val" type="number" min="0" step="1024" placeholder="32768" oninput="cfgWriteKey('CTX', this.value)"><span class="pe-unit">tok</span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pe-row">
|
<div class="pe-row">
|
||||||
<span class="pe-row-l">Couches sur GPU<span class="pe-sub">999 = tout sur le GPU · auto = ce qui tient en VRAM</span></span>
|
<span class="pe-row-l">Couches sur GPU<span class="pe-sub">999 ou auto = ce qui tient en VRAM · all = tout, quitte à saturer</span></span>
|
||||||
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"></span>
|
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pe-row">
|
<div class="pe-row">
|
||||||
|
|||||||
Reference in new issue
Block a user