Дашборд: карточка загрузки GPU (util/Вт/°C из results/gpustat.json)
Веб в Docker без nvidia-smi: хост-сервис gausse-gpustat пишет JSON рядом с базой, /api/overview отдаёт поле gpu (протухшее >30с — честно null). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,7 @@ PAGE_HTML = r"""<!doctype html>
|
|||||||
<div class="card"><div class="k">Нереализуемо</div><div class="v" id="c-infeas">—</div></div>
|
<div class="card"><div class="k">Нереализуемо</div><div class="v" id="c-infeas">—</div></div>
|
||||||
<div class="card"><div class="k">Доля реализуемых</div><div class="v" id="c-pct">—</div></div>
|
<div class="card"><div class="k">Доля реализуемых</div><div class="v" id="c-pct">—</div></div>
|
||||||
<div class="card"><div class="k">Лучший КПД / скорость</div><div class="v" id="c-best" style="font-size:20px">—</div></div>
|
<div class="card"><div class="k">Лучший КПД / скорость</div><div class="v" id="c-best" style="font-size:20px">—</div></div>
|
||||||
|
<div class="card"><div class="k">GPU (GTX 1070)</div><div class="v" id="c-gpu" style="font-size:20px">—</div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid2">
|
<div class="grid2">
|
||||||
@@ -131,6 +132,10 @@ async function refresh(){
|
|||||||
let best = (o.top && o.top.length) ? o.top[0].efficiency : null;
|
let best = (o.top && o.top.length) ? o.top[0].efficiency : null;
|
||||||
let bestV = (o.top_by_velocity && o.top_by_velocity.length) ? o.top_by_velocity[0].exit_velocity_mps : null;
|
let bestV = (o.top_by_velocity && o.top_by_velocity.length) ? o.top_by_velocity[0].exit_velocity_mps : null;
|
||||||
document.getElementById('c-best').textContent = fmtPct(best) + (bestV!=null ? ' / '+fmt(bestV,0)+' м/с' : '');
|
document.getElementById('c-best').textContent = fmtPct(best) + (bestV!=null ? ' / '+fmt(bestV,0)+' м/с' : '');
|
||||||
|
const g = o.gpu;
|
||||||
|
document.getElementById('c-gpu').textContent = g
|
||||||
|
? `${g.util_pct}% · ${fmt(g.power_w,0)}Вт · ${g.temp_c}°C`
|
||||||
|
: 'нет данных';
|
||||||
renderTop(o);
|
renderTop(o);
|
||||||
|
|
||||||
const hist=document.getElementById('hist'); hist.innerHTML='';
|
const hist=document.getElementById('hist'); hist.innerHTML='';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Агрегаты по таблице `runs` для веб-морды — считаются запросами к SQLite."""
|
"""Агрегаты по таблице `runs` для веб-морды — считаются запросами к SQLite."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from gausse.storage.database import fetch_run_by_id, fetch_runs, open_connection
|
from gausse.storage.database import fetch_run_by_id, fetch_runs, open_connection
|
||||||
@@ -13,6 +14,23 @@ def _tail_log(log_path: Path, n_lines: int = 40) -> list[str]:
|
|||||||
return lines[-n_lines:]
|
return lines[-n_lines:]
|
||||||
|
|
||||||
|
|
||||||
|
def _gpu_stat(db_path: Path) -> dict | None:
|
||||||
|
"""Загрузка GPU из gpustat.json рядом с базой (пишет gausse-gpustat на хосте).
|
||||||
|
|
||||||
|
Веб живёт в Docker без доступа к nvidia-smi, поэтому хост-сервис раз в
|
||||||
|
несколько секунд кладёт JSON в каталог результатов. Протухшие данные
|
||||||
|
(>30с — писатель умер/GPU нет) честно не показываем.
|
||||||
|
"""
|
||||||
|
p = db_path.parent / "gpustat.json"
|
||||||
|
try:
|
||||||
|
stat = json.loads(p.read_text(encoding="utf-8"))
|
||||||
|
if time.time() - float(stat.get("ts", 0)) > 30:
|
||||||
|
return None
|
||||||
|
return stat
|
||||||
|
except (OSError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def overview(db_path: Path, log_path: Path | None = None, top_n: int = 15) -> dict:
|
def overview(db_path: Path, log_path: Path | None = None, top_n: int = 15) -> dict:
|
||||||
"""Сводка для дашборда: счётчики, гистограмма КПД, топ конфигураций, хвост лога."""
|
"""Сводка для дашборда: счётчики, гистограмма КПД, топ конфигураций, хвост лога."""
|
||||||
conn = open_connection(db_path)
|
conn = open_connection(db_path)
|
||||||
@@ -71,6 +89,7 @@ def overview(db_path: Path, log_path: Path | None = None, top_n: int = 15) -> di
|
|||||||
"top": top,
|
"top": top,
|
||||||
"top_by_velocity": top_by_velocity,
|
"top_by_velocity": top_by_velocity,
|
||||||
"log_tail": _tail_log(log_path, 40) if log_path else [],
|
"log_tail": _tail_log(log_path, 40) if log_path else [],
|
||||||
|
"gpu": _gpu_stat(db_path),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user