Moniteur : un seul nvidia-smi pour tous les onglets, aucun pour un onglet caché

Chaque onglet ouvert (et chaque téléphone) interrogeait /api/vram toutes les
3 s, et chaque requête lançait son propre nvidia-smi — y compris depuis un
onglet en arrière-plan que personne ne regarde, pendant que llama-server
génère. Rien de tout cela ne touche au modèle : seules les jauges sont
concernées.

- gpuStatsCached : lecture partagée de 2 s, verrou tenu pendant la requête
  pour que des appels simultanés attendent la même lecture. nvidia-smi
  introuvable (Mac, CPU seul) mémorisé une minute ; une autre erreur se
  retente au délai normal.
- Seul handleVram passe par le cache. Le déchargement (lecture « avant » et
  gpuSettle) garde des lectures fraîches : deux valeurs égales servies par
  le cache feraient conclure gpuSettle à tort. Le cache est vidé après un
  déchargement.
- UI : statut, VRAM et RAM ne sont plus interrogés dans un onglet caché ;
  lecture immédiate au retour.
- Tests : cache (réutilisation, erreur, binaire absent, appels simultanés)
  et échantillonneur du déchargement qui contourne le cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-04 01:57:55 +02:00
1 parent 3dff7e0e04
commit 4f34694400
5 files changed
+214 -19

No files matched your search

+3 -2
View File
@@ -189,10 +189,11 @@ func handleServiceLog(w http.ResponseWriter, r *http.Request) {
// handleVram expose l'état des cartes à l'interface (jauges du moniteur).
// La lecture nvidia-smi elle-même vit dans web_vram.go, avec le déchargement
// de la VRAM qui s'en sert pour chiffrer la mémoire rendue.
// de la VRAM qui s'en sert pour chiffrer la mémoire rendue. Lecture partagée
// (gpuStatsCached) : tous les onglets se contentent d'un seul nvidia-smi.
func handleVram(w http.ResponseWriter, r *http.Request) {
gpus := []map[string]any{}
for _, g := range gpuStats() {
for _, g := range gpuStatsCached() {
gpus = append(gpus, map[string]any{
"name": g.Name, "used": g.Used, "total": g.Total, "util": g.Util, "temp": g.Temp,
})