diff --git a/ml/monitor.html b/ml/monitor.html index bb33288..458ebf5 100644 --- a/ml/monitor.html +++ b/ml/monitor.html @@ -57,6 +57,7 @@ .step.active .ic { background: #5aa9ff22; border-color: var(--accent); color: var(--accent); box-shadow: 0 0 0 4px #5aa9ff1f; } .step.fail .ic { background: #f8717122; border-color: var(--bad); color: var(--bad); } .step .nm { font-size: 12.5px; color: var(--text); white-space: nowrap; } .step .ds { font-size: 11px; color: var(--dim2); white-space: nowrap; } + .step .ds.big { font-size: 14px; font-weight: 650; color: var(--accent); } .step.pending .nm { color: var(--dim); } .step.active .ds { color: var(--accent); } @@ -127,8 +128,9 @@ button.danger { color: var(--bad); border-color: #f8717166; } button.danger:hover { background: #f8717114; } .overall { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .overall .now { font-size: 13px; color: var(--dim); } .overall .now b { display: block; color: var(--text); font-size: 18px; font-weight: 650; margin: 2px 0 2px; } - .sublabel { font-size: 12.5px; color: var(--dim); display: flex; justify-content: space-between; margin-top: 4px; } - .bar.thin { height: 8px; margin: 8px 0 4px; } .bar.ind .fill { width: 30% !important; animation: ind 1.6s ease-in-out infinite; } + .sublabel { font-size: 15px; color: var(--dim); display: flex; justify-content: space-between; align-items: baseline; margin-top: 6px; } + .sublabel b { font: 700 20px/1 var(--mono); color: var(--text); } + .bar.thin { height: 14px; margin: 10px 0 4px; } .bar.ind .fill { width: 30% !important; animation: ind 1.6s ease-in-out infinite; } @keyframes ind { 0% { margin-left: 0; } 50% { margin-left: 70%; } 100% { margin-left: 0; } } .ctlrow { display: flex; gap: 10px; margin-top: 14px; align-items: center; flex-wrap: wrap; } .ctlrow .hint { font-size: 12px; color: var(--dim2); } @@ -500,11 +502,12 @@ function stages(s) { if (P) { // 有流水线记录:以它为准 const plan = P.plan && P.plan.length ? P.plan : STAGE_META.map(x => x[0]).filter(k => k !== 'setup'); const keys = STAGE_META.map(x => x[0]).filter(k => plan.includes(k) || P.stages[k]); + const el = P.elapsed || {}; // 累计用时(跨停止/续跑),没有就退回本段 return keys.map(k => { const r = P.stages[k], nm = SM[k].n; if (!r) return [nm, 'pending', '—']; if (P.current === k) return [nm, 'active', P.progress && P.progress.frac != null ? pct(P.progress.frac, 0) : '进行中']; - if (r.rc === 0) return [nm, 'done', '用时 ' + hmsShort(r.end - r.start)]; + if (r.rc === 0) return [nm, 'done', '用时 ' + hmsShort(el[k] != null ? el[k] : r.end - r.start)]; if (r.rc === -15 || r.rc === 143) return [nm, 'fail', '已停止']; if (r.rc != null) return [nm, 'fail', `失败(返回码 ${r.rc})`]; return [nm, 'fail', '中断']; @@ -531,7 +534,7 @@ function stages(s) { } function renderStatus(s) { const L = stages(s); - $('steps').innerHTML = L.map(([nm, st, ds], i) => `
${st === 'done' ? '✓' : st === 'fail' ? '!' : i + 1}
${nm}
${ds}
`).join(''); + $('steps').innerHTML = L.map(([nm, st, ds], i) => `
${st === 'done' ? '✓' : st === 'fail' ? '!' : i + 1}
${nm}
${ds}
`).join(''); const nDone = L.filter(x => x[1] === 'done').length; $('stepnote').textContent = `${nDone} / ${L.length} 完成`; // GPU + CPU(同一个框:上面是 GPU 环 + 显存/温度/功耗,下面接 CPU 总占用与每核条) @@ -630,7 +633,7 @@ function renderPipe(s) { $('pipe').innerHTML = `

全流程${doneN} / ${plan.length} 步完成

${head}
${(100 * frac).toFixed(1)}%
- ${cur ? `
当前步骤 · ${SM[cur]?.n}${pr.frac != null ? pct(pr.frac) : '无法计量,按用时估'}
+ ${cur ? `
当前步骤 · ${SM[cur]?.n}${pr.frac != null ? `${pct(pr.frac)}` : '无法计量,按用时估'}
` : ''}
总用时
${hms(plan.reduce((a, k) => a + ((P.elapsed || {})[k] || 0), 0))}