mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-12 01:37:06 +02:00
Moniteur : corrections de relecture — un nvidia-smi pendu ne fige plus les jauges
gpuStatsCached tient son verrou pendant la requête : c'est ce qui fait partager une seule lecture aux onglets. Mais la requête n'était pas bornée, et le code le dit ailleurs (nvidiaGPUCount) : un pilote coincé peut faire pendre nvidia-smi. Avant le cache, chaque nouvelle requête relançait son propre nvidia-smi et les jauges revenaient avec le pilote ; avec le verrou, un seul processus pendu bloquait /api/vram pour tous les onglets jusqu'au redémarrage de Loki. - nvidiaSmiQuery : CommandContext borné à 10 s (large pour une première lecture lente sans mode persistant), WaitDelay d'une seconde. Au-delà, une erreur ordinaire, retentée au délai normal du cache. - Le déchargement profite de la même borne : une lecture pendue devient une mesure ratée, que gpuSettle sait déjà sauter. - Test : la vraie requête, binaire absent du PATH, rend bien exec.ErrNotFound — la seule erreur que le cache garde une minute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4f34694400
commit
9b2e974942
2 files changed
+27
-2
No files matched your search
@@ -13,6 +13,7 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
@@ -36,12 +37,25 @@ type gpuStat struct {
|
||||
|
||||
// nvidiaSmiQuery lance la requête nvidia-smi. Variable pour que les tests
|
||||
// substituent un faux exécutable et comptent les lancements.
|
||||
//
|
||||
// Bornée dans le temps, comme nvidiaGPUCount : un pilote coincé peut faire
|
||||
// pendre nvidia-smi, et gpuStatsCached tient son verrou pendant la requête. Sans
|
||||
// borne, un seul nvidia-smi pendu figeait les jauges de TOUS les onglets
|
||||
// jusqu'au redémarrage de Loki, même une fois le pilote revenu. Dix secondes :
|
||||
// large pour une première lecture lente (pilote sans mode persistant, plusieurs
|
||||
// cartes), une erreur ordinaire au-delà — retentée au délai normal.
|
||||
var nvidiaSmiQuery = func() ([]byte, error) {
|
||||
return hideCmd(exec.Command("nvidia-smi",
|
||||
ctx, cancel := context.WithTimeout(context.Background(), nvidiaSmiTimeout)
|
||||
defer cancel()
|
||||
cmd := hideCmd(exec.CommandContext(ctx, "nvidia-smi",
|
||||
"--query-gpu=name,memory.used,memory.total,utilization.gpu,temperature.gpu",
|
||||
"--format=csv,noheader,nounits")).Output()
|
||||
"--format=csv,noheader,nounits"))
|
||||
cmd.WaitDelay = time.Second // un descendant qui garderait la sortie ouverte ne retient pas Wait
|
||||
return cmd.Output()
|
||||
}
|
||||
|
||||
const nvidiaSmiTimeout = 10 * time.Second
|
||||
|
||||
// gpuStats interroge nvidia-smi. Renvoie nil quand il est absent (machine sans
|
||||
// GPU NVIDIA, Mac, CPU seul) : l'absence de mesure n'est pas une erreur, elle
|
||||
// prive juste le déchargement de son bilan chiffré. Toujours une lecture
|
||||
|
||||
@@ -170,3 +170,14 @@ func TestGpuSettleSampleFrais(t *testing.T) {
|
||||
t.Errorf("jauges : %d, attendu la lecture en cache 19000", g[0].Used)
|
||||
}
|
||||
}
|
||||
|
||||
// Le cache ne mémorise une minute que l'ABSENCE de nvidia-smi : il faut donc que
|
||||
// la vraie requête (bornée dans le temps) rende toujours exec.ErrNotFound quand
|
||||
// le binaire n'est pas dans le PATH — sinon Mac et CPU seul relanceraient une
|
||||
// recherche toutes les deux secondes.
|
||||
func TestNvidiaSmiQueryAbsent(t *testing.T) {
|
||||
t.Setenv("PATH", t.TempDir())
|
||||
if _, err := nvidiaSmiQuery(); !errors.Is(err, exec.ErrNotFound) {
|
||||
t.Fatalf("erreur %v, attendu exec.ErrNotFound", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user