mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 15:08:16 +02:00
VRAM : le bilan mentait, un GET coupait le moteur, la dictée bloquait
Relecture du bouton « Libérer la VRAM » (009b585) — six défauts, tous
sur la même feature :
- gpuUsedSettled comptait une lecture ratée de nvidia-smi comme « 0 Mo »
(pilote en réinitialisation juste après l'arrêt) : freed = before, et
l'interface annonçait 14 Gio rendus alors que rien n'avait bougé. Elle
rendait aussi la main au premier palier, AVANT que le pilote ait réagi
(taskkill et Process.Kill reviennent avant le ménage CUDA) : « 0 Mo »
après un déchargement qui marchait. gpuSettle saute les lectures
ratées, n'accepte un palier qu'une fois la baisse observée, et est
testable (sampler injecté).
- /api/vram/unload et /reload acceptaient GET : sans clé de pilotage,
une balise <img> sur une page tierce suffisait à couper le moteur.
405 + Allow: POST.
- whisperShutdown prend wsrvMu, que whisperEnsure garde jusqu'à deux
minutes pendant un chargement de modèle : le geste dépassait le délai
du navigateur, moteur pourtant déjà arrêté. whisperShutdownVite tue le
processus en train de démarrer (poignée atomique hors verrou) au lieu
d'attendre derrière lui.
- Sous systemd, une unité en crash-loop répond « activating », pas
« active » : le stop était sauté et systemd relançait llama-server
toutes les trois secondes pendant que l'UI disait « déjà arrêté ».
engineNeedsStop élargit aux états transitoires.
- Un moteur planté au chargement était présenté comme « modèle
déchargé — recharge-le » : LOAD_ERROR distingue les deux, le conseil
renvoie vers l'erreur affichée dans le moniteur.
- Deux clics concurrents (moniteur + réglages) lançaient un stop au
milieu d'un start ; VRAM_BUSY fait verrou, et le bouton se repeint
depuis l'état renvoyé par le serveur, pas depuis l'ancien poll.
Quelques Mo de bruit entre deux lectures ne font plus « VRAM libérée :
0.0 Gio ».
Au passage, le 404 d'un téléchargement nomme le fichier manquant : sur
un dépôt qui publie six fragments sur sept (table PLE livrée à part),
« la révision a pu être réécrite » envoyait chercher au mauvais endroit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01961iDyM6pwn2dE2SW23gYX
This commit is contained in:
1 parent
009b585e75
commit
33de4a1144
8 files changed
+279
-32
No files matched your search
@@ -21,6 +21,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -170,6 +171,13 @@ const whisperIdle = 10 * time.Minute
|
||||
const whisperReady = 120 * time.Second
|
||||
|
||||
var wsrvMu sync.Mutex
|
||||
|
||||
// wsrvDemarrage : le processus en cours de démarrage, visible SANS le verrou.
|
||||
// whisperStartLocked garde wsrvMu pendant tout le chargement du modèle ; c'est
|
||||
// la seule poignée qu'un autre appelant (whisperShutdownVite) a sur lui pour
|
||||
// l'interrompre. Nil hors démarrage.
|
||||
var wsrvDemarrage atomic.Pointer[exec.Cmd]
|
||||
|
||||
var wsrv struct {
|
||||
cmd *exec.Cmd
|
||||
port int
|
||||
@@ -231,7 +239,10 @@ func whisperStartLocked(cfg DictateCfg) (int, error) {
|
||||
}
|
||||
wsrv.cmd, wsrv.port, wsrv.cfg = cmd, port, dictateCfgLoad()
|
||||
wsrv.log, wsrv.note, wsrv.depuis = log, note, time.Now()
|
||||
if err := whisperAttendPret(cmd, port, log); err != nil {
|
||||
wsrvDemarrage.Store(cmd)
|
||||
err = whisperAttendPret(cmd, port, log)
|
||||
wsrvDemarrage.Store(nil)
|
||||
if err != nil {
|
||||
whisperStopLocked()
|
||||
return 0, err
|
||||
}
|
||||
@@ -301,6 +312,30 @@ func whisperShutdown() {
|
||||
whisperStopLocked()
|
||||
}
|
||||
|
||||
// whisperShutdownVite arrête le serveur sans jamais attendre derrière un
|
||||
// démarrage. whisperShutdown prend wsrvMu, et whisperEnsure le garde pendant
|
||||
// tout le chargement du modèle — jusqu'à whisperReady (deux minutes) depuis un
|
||||
// disque lent. Appelé par un geste de l'interface (libérer la VRAM), ce blocage
|
||||
// ferait abandonner le navigateur alors que le moteur, lui, est déjà arrêté.
|
||||
//
|
||||
// Si le verrou est pris, on tue le processus en train de démarrer : sa mort
|
||||
// fait sortir whisperAttendPret, le verrou se libère, et on finit le ménage
|
||||
// par la voie normale. La dictée qui attendait reçoit une erreur de démarrage —
|
||||
// c'est l'utilisateur qui vient de demander la carte, pas une panne.
|
||||
func whisperShutdownVite() {
|
||||
for i := 0; i < 20; i++ {
|
||||
if wsrvMu.TryLock() {
|
||||
whisperStopLocked()
|
||||
wsrvMu.Unlock()
|
||||
return
|
||||
}
|
||||
if cmd := wsrvDemarrage.Load(); cmd != nil && cmd.Process != nil {
|
||||
_ = cmd.Process.Kill()
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// whisperInfer garantit le serveur puis lui soumet le WAV.
|
||||
func whisperInfer(ctx context.Context, wav []byte) (string, error) {
|
||||
port, err := whisperEnsure()
|
||||
|
||||
Reference in new issue
Block a user