feat: add interactive granular benchmark details to UI and update MTP summary data format
This commit is contained in:
@@ -103,9 +103,90 @@
|
||||
font-size: 11px;
|
||||
background: #f1f5ff;
|
||||
color: #1d4ed8;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.toolbox-pill.radv {
|
||||
background: #fdf2f8;
|
||||
color: #9d174d;
|
||||
}
|
||||
|
||||
/* Expandable row interactivity */
|
||||
.mtp-table tbody tr.main-row {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.mtp-table tbody tr.main-row:hover {
|
||||
background-color: var(--hover);
|
||||
}
|
||||
|
||||
.mtp-table tbody tr.main-row td:first-child::before {
|
||||
content: "▶";
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
margin-right: 8px;
|
||||
color: var(--muted);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.mtp-table tbody tr.main-row.expanded td:first-child::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* Details row and sub-table */
|
||||
.details-row {
|
||||
background-color: #f8fafc;
|
||||
}
|
||||
|
||||
.details-row.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.details-row td {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.granular-wrap {
|
||||
padding: 16px 24px;
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
.granular-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.granular-table th, .granular-table td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.granular-table th {
|
||||
background: #f1f5f9;
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.granular-table td.num {
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.granular-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.granular-table tbody tr:hover {
|
||||
background-color: var(--hover);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ function renderTable(runs, tbody) {
|
||||
|
||||
rows.forEach(row => {
|
||||
const tr = document.createElement("tr");
|
||||
tr.className = "main-row";
|
||||
|
||||
// Model
|
||||
const tdModel = document.createElement("td");
|
||||
@@ -87,7 +88,22 @@ function renderTable(runs, tbody) {
|
||||
tr.appendChild(makeMetricCell(mtp3Speed));
|
||||
tr.appendChild(makeSpeedupCell(baseSpeed, mtp3Speed));
|
||||
|
||||
// Details row
|
||||
const detailsTr = document.createElement("tr");
|
||||
detailsTr.className = "details-row hidden";
|
||||
const detailsTd = document.createElement("td");
|
||||
detailsTd.colSpan = 8;
|
||||
|
||||
detailsTd.innerHTML = makeDetailsHTML(row);
|
||||
detailsTr.appendChild(detailsTd);
|
||||
|
||||
tr.addEventListener("click", () => {
|
||||
tr.classList.toggle("expanded");
|
||||
detailsTr.classList.toggle("hidden");
|
||||
});
|
||||
|
||||
tbody.appendChild(tr);
|
||||
tbody.appendChild(detailsTr);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,3 +142,99 @@ function makeSpeedupCell(base, mtp) {
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
function makeDetailsHTML(row) {
|
||||
if (!row.baseline || !row.baseline.results || row.baseline.results.length === 0) {
|
||||
return `<div class="granular-wrap"><p style="font-size: 13px; color: var(--muted); margin: 0;">Granular data not available for this run. Re-run benchmarks to capture prompt-level metrics.</p></div>`;
|
||||
}
|
||||
|
||||
const tasks = new Map();
|
||||
const modes = [
|
||||
{ key: "base", data: row.baseline },
|
||||
{ key: "mtp2", data: row.mtp2 },
|
||||
{ key: "mtp3", data: row.mtp3 }
|
||||
];
|
||||
|
||||
modes.forEach(mode => {
|
||||
if (!mode.data || !mode.data.results) return;
|
||||
mode.data.results.forEach(res => {
|
||||
if (!tasks.has(res.name)) {
|
||||
tasks.set(res.name, { name: res.name });
|
||||
}
|
||||
const t = tasks.get(res.name);
|
||||
t[`${mode.key}_prefill`] = res.prompt_per_second;
|
||||
t[`${mode.key}_toks`] = res.predicted_per_second;
|
||||
t[`${mode.key}_acc`] = res.accept_rate;
|
||||
});
|
||||
});
|
||||
|
||||
let html = `
|
||||
<div class="granular-wrap">
|
||||
<table class="granular-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prompt Task</th>
|
||||
<th class="num" title="Prefill (Prompt Processing) tok/s (Baseline)">Prefill (Base)</th>
|
||||
<th class="num" title="Prefill tok/s (MTP-2)">Prefill (MTP-2)</th>
|
||||
<th class="num" title="Prefill tok/s (MTP-3)">Prefill (MTP-3)</th>
|
||||
<th class="num" title="Baseline Gen tok/s">Base Gen</th>
|
||||
<th class="num" title="MTP-2 Gen tok/s">MTP-2 Gen</th>
|
||||
<th class="num" title="MTP-2 Accept Rate">Acc%</th>
|
||||
<th class="num" title="MTP-3 Gen tok/s">MTP-3 Gen</th>
|
||||
<th class="num" title="MTP-3 Accept Rate">Acc%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
tasks.forEach(t => {
|
||||
const p_base_val = t.base_prefill;
|
||||
const p_mtp2_val = t.mtp2_prefill;
|
||||
const p_mtp3_val = t.mtp3_prefill;
|
||||
|
||||
const p_base = p_base_val ? p_base_val.toFixed(1) : "—";
|
||||
let p_mtp2 = p_mtp2_val ? p_mtp2_val.toFixed(1) : "—";
|
||||
let p_mtp3 = p_mtp3_val ? p_mtp3_val.toFixed(1) : "—";
|
||||
|
||||
if (p_base_val && p_mtp2_val) {
|
||||
const pct = ((p_mtp2_val - p_base_val) / p_base_val) * 100;
|
||||
const color = pct >= 0 ? '#16a34a' : '#dc2626';
|
||||
const sign = pct > 0 ? '+' : '';
|
||||
p_mtp2 += ` <span style="font-size: 10px; color: ${color}; margin-left: 4px;">${sign}${pct.toFixed(1)}%</span>`;
|
||||
}
|
||||
|
||||
if (p_base_val && p_mtp3_val) {
|
||||
const pct = ((p_mtp3_val - p_base_val) / p_base_val) * 100;
|
||||
const color = pct >= 0 ? '#16a34a' : '#dc2626';
|
||||
const sign = pct > 0 ? '+' : '';
|
||||
p_mtp3 += ` <span style="font-size: 10px; color: ${color}; margin-left: 4px;">${sign}${pct.toFixed(1)}%</span>`;
|
||||
}
|
||||
|
||||
const g_base = t.base_toks ? t.base_toks.toFixed(1) : "—";
|
||||
const g_mtp2 = t.mtp2_toks ? t.mtp2_toks.toFixed(1) : "—";
|
||||
const a_mtp2 = t.mtp2_acc !== null && t.mtp2_acc !== undefined ? (t.mtp2_acc * 100).toFixed(1) + "%" : "—";
|
||||
const g_mtp3 = t.mtp3_toks ? t.mtp3_toks.toFixed(1) : "—";
|
||||
const a_mtp3 = t.mtp3_acc !== null && t.mtp3_acc !== undefined ? (t.mtp3_acc * 100).toFixed(1) + "%" : "—";
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${t.name}</td>
|
||||
<td class="num">${p_base}</td>
|
||||
<td class="num">${p_mtp2}</td>
|
||||
<td class="num">${p_mtp3}</td>
|
||||
<td class="num">${g_base}</td>
|
||||
<td class="num">${g_mtp2}</td>
|
||||
<td class="num" style="color: var(--muted);">${a_mtp2}</td>
|
||||
<td class="num">${g_mtp3}</td>
|
||||
<td class="num" style="color: var(--muted);">${a_mtp3}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user