2025-12-20 11:37:06 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > AMD Strix Halo (gfx1151) vLLM Benchmarks< / title >
< style >
: root {
--bg-body : #f9fafb ;
--bg-card : #ffffff ;
--text-main : #111827 ;
--text-muted : #6b7280 ;
--border : #e5e7eb ;
--primary : #ef4444 ;
/* AMD Red-ish */
--primary-bg : #fef2f2 ;
--font-sans : - apple-system , BlinkMacSystemFont , "Segoe UI" , Roboto , "Helvetica Neue" , Arial , sans-serif ;
--font-mono : ui-monospace , SFMono-Regular , Menlo , Monaco , Consolas , monospace ;
}
body {
background-color : var ( - - bg - body ) ;
color : var ( - - text - main ) ;
font-family : var ( - - font - sans ) ;
margin : 0 ;
padding : 20 px ;
line-height : 1.5 ;
}
. container {
max-width : 1000 px ;
margin : 20 px auto ;
}
/* Header */
header {
margin-bottom : 20 px ;
text-align : center ;
}
h1 {
font-size : 2.25 rem ;
font-weight : 800 ;
margin : 0 0 10 px 0 ;
letter-spacing : -0.05 rem ;
}
p . subtitle {
color : var ( - - text - muted ) ;
font-size : 1.1 rem ;
margin : 0 ;
}
/* Controls */
. controls {
display : flex ;
gap : 16 px ;
margin-bottom : 24 px ;
background : var ( - - bg - card ) ;
padding : 16 px ;
border-radius : 12 px ;
box-shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.05 ) ;
border : 1 px solid var ( - - border ) ;
align-items : center ;
flex-wrap : wrap ;
}
input [ type = "text" ] ,
select {
padding : 10 px 14 px ;
border : 1 px solid var ( - - border ) ;
border-radius : 8 px ;
font-size : 0.95 rem ;
outline : none ;
transition : border-color 0.15 s ;
}
input [ type = "text" ] : focus ,
select : focus {
border-color : var ( - - primary ) ;
box-shadow : 0 0 0 2 px var ( - - primary - bg ) ;
}
. search {
flex : 1 ;
min-width : 200 px ;
}
/* Section Cards */
. section-card {
background : var ( - - bg - card ) ;
border-radius : 12 px ;
box-shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.05 ) ;
border : 1 px solid var ( - - border ) ;
margin-bottom : 32 px ;
overflow : hidden ;
}
. section-header {
padding : 12 px 16 px ;
border-bottom : 1 px solid var ( - - border ) ;
background : #fcfcfc ;
display : flex ;
justify-content : space-between ;
align-items : center ;
}
. section-header h2 {
margin : 0 ;
font-size : 1.1 rem ;
font-weight : 600 ;
}
/* Table */
. table-responsive {
overflow-x : auto ;
}
table {
width : 100 % ;
border-collapse : collapse ;
font-size : 0.95 rem ;
}
th ,
td {
padding : 8 px 12 px ;
text-align : left ;
border-bottom : 1 px solid var ( - - border ) ;
}
th {
background : #f9fafb ;
color : var ( - - text - muted ) ;
font-weight : 600 ;
font-size : 0.75 rem ;
text-transform : uppercase ;
letter-spacing : 0.05 em ;
}
tr : last-child td {
border-bottom : none ;
}
/* Columns */
. col-model {
width : auto ;
}
. col-data {
text-align : right ;
width : 1 % ;
white-space : nowrap ;
font-family : var ( - - font - mono ) ;
font-feature-settings : "tnum" ;
font-variant-numeric : tabular-nums ;
}
/* Model Cell Styling */
. model-cell {
display : flex ;
flex-direction : column ;
}
. model-name {
font-weight : 600 ;
color : var ( - - text - main ) ;
}
. model-meta {
font-size : 0.8 rem ;
color : var ( - - text - muted ) ;
margin-top : 4 px ;
display : flex ;
gap : 8 px ;
align-items : center ;
}
/* Tags */
. tag {
display : inline-block ;
padding : 2 px 6 px ;
border-radius : 4 px ;
background : #f3f4f6 ;
color : #4b5563 ;
font-size : 0.7 rem ;
font-weight : 500 ;
}
/* Data Styling */
. val {
font-weight : 600 ;
}
. val-na {
color : #d1d5db ;
font-weight : 400 ;
}
. highlight {
color : var ( - - primary ) ;
}
2026-02-02 21:30:17 +00:00
/* Diff Styling */
. val-pos {
color : #16a34a ;
font-weight : 600 ;
}
. val-neg {
color : #dc2626 ;
font-weight : 600 ;
}
. val-neu {
color : #9ca3af ;
}
. col-diff {
background : #f9fafb ;
font-size : 0.9 rem ;
}
2025-12-20 11:37:06 +00:00
/* Modal/Overlay */
# loading {
text-align : center ;
padding : 40 px ;
color : var ( - - text - muted ) ;
}
/* Modal Styles */
. modal-overlay {
position : fixed ;
top : 0 ;
left : 0 ;
width : 100 % ;
height : 100 % ;
background : rgba ( 0 , 0 , 0 , 0.5 ) ;
display : flex ;
justify-content : center ;
align-items : center ;
z-index : 1000 ;
opacity : 0 ;
pointer-events : none ;
transition : opacity 0.2 s ease ;
}
. modal-overlay . active {
opacity : 1 ;
pointer-events : auto ;
}
. modal {
background : var ( - - bg - card ) ;
width : 90 % ;
max-width : 600 px ;
border-radius : 12 px ;
box-shadow : 0 10 px 25 px rgba ( 0 , 0 , 0 , 0.1 ) ;
display : flex ;
flex-direction : column ;
max-height : 85 vh ;
overflow : hidden ;
}
. modal-header {
padding : 20 px 24 px ;
border-bottom : 1 px solid var ( - - border ) ;
display : flex ;
justify-content : space-between ;
align-items : center ;
background : #f9fafb ;
}
. modal-header h3 {
margin : 0 ;
font-size : 1.25 rem ;
}
. modal-close {
background : none ;
border : none ;
font-size : 1.5 rem ;
cursor : pointer ;
color : var ( - - text - muted ) ;
line-height : 1 ;
}
. modal-body {
padding : 24 px ;
overflow-y : auto ;
}
. modal-section {
margin-bottom : 24 px ;
}
. modal-section h4 {
margin : 0 0 8 px 0 ;
font-size : 0.9 rem ;
text-transform : uppercase ;
color : var ( - - text - muted ) ;
letter-spacing : 0.05 em ;
}
. modal-section p {
margin : 0 ;
font-size : 0.95 rem ;
color : var ( - - text - main ) ;
}
. code-block {
background : #f3f4f6 ;
padding : 12 px ;
border-radius : 6 px ;
font-family : var ( - - font - mono ) ;
font-size : 0.85 rem ;
color : #374151 ;
margin-top : 8 px ;
white-space : pre-wrap ;
}
/* Help Button */
. btn-help {
background : none ;
border : 1 px solid var ( - - border ) ;
color : var ( - - text - muted ) ;
width : 24 px ;
height : 24 px ;
border-radius : 50 % ;
display : inline-flex ;
align-items : center ;
justify-content : center ;
font-size : 0.85 rem ;
font-weight : 600 ;
cursor : pointer ;
margin-left : 10 px ;
transition : all 0.2 s ;
}
. btn-help : hover {
border-color : var ( - - primary ) ;
color : var ( - - primary ) ;
background : var ( - - primary - bg ) ;
}
. section-title-row {
display : flex ;
align-items : center ;
}
. section-desc {
color : var ( - - text - muted ) ;
font-size : 0.9 rem ;
font-weight : 400 ;
margin-left : 12 px ;
}
2026-02-02 19:34:33 +00:00
/* Info Box for Cluster */
. info-box {
background : #eff6ff ;
border : 1 px solid #bfdbfe ;
border-radius : 8 px ;
padding : 16 px ;
margin-bottom : 24 px ;
display : flex ;
align-items : flex-start ;
gap : 12 px ;
color : #1e40af ;
font-size : 0.95 rem ;
}
. info-box a {
color : #1d4ed8 ;
font-weight : 600 ;
text-decoration : underline ;
}
2025-12-20 11:37:06 +00:00
/* Footer */
footer {
margin-top : 60 px ;
padding-top : 20 px ;
border-top : 1 px solid var ( - - border ) ;
color : var ( - - text - muted ) ;
font-size : 0.85 rem ;
line-height : 1.6 ;
}
. sys-config {
display : flex ;
flex-direction : column ;
gap : 8 px ;
margin-top : 12 px ;
max-width : 800 px ;
}
. sys-item {
display : grid ;
grid-template-columns : 140 px 1 fr ;
align-items : baseline ;
}
. sys-label {
font-weight : 600 ;
font-size : 0.75 rem ;
text-transform : uppercase ;
letter-spacing : 0.05 em ;
color : #9ca3af ;
}
/* Tabs */
. tab-nav {
display : flex ;
gap : 8 px ;
margin-bottom : 24 px ;
border-bottom : 1 px solid var ( - - border ) ;
padding-bottom : 0 px ;
}
. tab-btn {
background : none ;
border : none ;
padding : 12 px 20 px ;
font-size : 1 rem ;
font-weight : 500 ;
color : var ( - - text - muted ) ;
cursor : pointer ;
border-bottom : 2 px solid transparent ;
transition : all 0.2 s ;
}
. tab-btn : hover {
color : var ( - - text - main ) ;
}
. tab-btn . active {
color : var ( - - primary ) ;
border-bottom-color : var ( - - primary ) ;
font-weight : 600 ;
}
< / style >
< / head >
< body >
< div class = "container" >
< header >
< h1 > AMD Strix Halo (gfx1151) vLLM Benchmarks< / h1 >
< p style = "margin: 4px 0 0 0; font-size: 0.9rem;" >
< a href = "https://github.com/kyuz0/amd-strix-halo-vllm-toolboxes/" target = "_blank"
style = "color: var(--primary); text-decoration: none;" > View on GitHub → < / a >
< / p >
< / header >
< div class = "controls" >
2026-02-02 21:30:17 +00:00
< input type = "text" id = "searchInput" class = "search" placeholder = "Search models..." autocomplete = "off" >
< select id = "quantFilter" style = "max-width: 150px;" >
< option value = "" > All Quants< / option >
2025-12-20 11:37:06 +00:00
< / select >
2026-02-02 21:30:17 +00:00
<!-- Toggles -->
< div
style = "display: flex; gap: 12px; align-items: center; border-left: 1px solid #e5e7eb; padding-left: 12px;" >
< label
style = "font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; gap: 4px; cursor: pointer;" >
< input type = "checkbox" id = "toggleTP1" checked > TP1
< / label >
< label
style = "font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; gap: 4px; cursor: pointer;" >
< input type = "checkbox" id = "toggleTP2" checked > TP2
< / label >
< / div >
<!-- Attention Group -->
< div
style = "display: flex; align-items: center; gap: 8px; border-left: 1px solid #e5e7eb; padding-left: 12px;" >
< span
style = "font-size: 0.8rem; font-weight: 600; text-transform: uppercase; color: #9ca3af; letter-spacing: 0.05em;" > Attention< / span >
< div style = "display: flex; gap: 12px;" >
< label
style = "font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; gap: 4px; cursor: pointer;" >
< input type = "checkbox" id = "toggleTriton" checked > Triton
< / label >
< label
style = "font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; gap: 4px; cursor: pointer;" >
< input type = "checkbox" id = "toggleRocm" > ROCm
< / label >
< / div >
< / div >
2025-12-20 11:37:06 +00:00
< / div >
< nav id = "tabNav" class = "tab-nav" >
<!-- Dynamic Tabs -->
< / nav >
< div id = "dashboard" >
< div id = "loading" > Loading benchmark results...< / div >
< / div >
< footer >
< div style = "font-weight: 600; margin-bottom: 8px;" > System Configuration< / div >
< div class = "sys-config" >
< div class = "sys-item" >
2026-02-02 19:34:33 +00:00
< span class = "sys-label" > Node 1 & 2< / span >
< span > Framework Desktop Mainboard · AMD Ryzen AI MAX 395+ (Strix Halo) · 128GB Unified RAM< / span >
2025-12-20 11:37:06 +00:00
< / div >
< div class = "sys-item" >
< span class = "sys-label" > OS/Kernel< / span >
2026-02-03 08:34:56 +00:00
< span > Fedora 43 · Linux 6.18.5-200.fc43.x86_64< / span >
2026-02-02 19:34:33 +00:00
< / div >
< div class = "sys-item" >
< span class = "sys-label" > Interconnect< / span >
< span > RDMA (RoCE v2) via Intel E810 (Direct Attach) · ~5µs Latency< / span >
2025-12-20 11:37:06 +00:00
< / div >
< / div >
< / footer >
< / div >
<!-- Modal Overlay -->
< div id = "modalOverlay" class = "modal-overlay" >
2026-02-02 21:30:17 +00:00
<!-- ... modal content ... -->
2025-12-20 11:37:06 +00:00
< div class = "modal" >
< div class = "modal-header" >
< h3 id = "modalTitle" > Benchmark Info< / h3 >
< button class = "modal-close" onclick = "closeModal()" > × < / button >
< / div >
< div class = "modal-body" id = "modalContent" >
<!-- Dynamic Content -->
< / div >
< / div >
< / div >
2026-02-02 21:30:17 +00:00
<!-- Script Logic Updates Below -->
2025-12-20 11:37:06 +00:00
< script >
2026-02-02 21:30:17 +00:00
// Helper - Defined at top to avoid ReferenceError
const $ = id => document . getElementById ( id ) ;
2025-12-20 11:37:06 +00:00
// State
let rawRuns = [ ] ;
let tests = [ ] ;
let state = {
search : "" ,
quant : "" ,
2026-02-02 21:30:17 +00:00
activeTab : "Throughput" ,
showTP1 : true ,
showTP2 : true ,
showTriton : true ,
showRocm : false
2025-12-20 11:37:06 +00:00
} ;
2026-02-02 21:30:17 +00:00
// Metadata
2025-12-20 11:37:06 +00:00
const BENCHMARK _INFO = {
"Throughput" : {
short : "Maximum raw compute capacity (Tokens/Sec)." ,
desc : "Measures the absolute maximum number of tokens the system can generate per second by fully saturating the GPU compute capability." ,
2026-02-02 21:30:17 +00:00
usecase : "Demonstrates the raw horsepower and architectural efficiency." ,
details : `
**Test Configuration:**
2026-02-02 22:36:15 +00:00
• <b>Dataset:</b> ShareGPT (Random Sample, 200 Prompts)
2026-02-02 21:30:17 +00:00
• <b>Output Length:</b> 512 Tokens (Fixed)
2026-02-02 22:36:15 +00:00
• <b>Concurrency:</b> 64 Sequences (Saturates Memory Bandwidth)
2026-02-02 21:30:17 +00:00
• <b>GPU Alloc:</b> 90% VRAM per GPU
• <b>Pipeline:</b> <code>vllm bench throughput</code> (Offline)
• <b>Cluster Config:</b> Ray Distributed (RoCE v2 RDMA, TP=2)
2026-02-02 22:36:15 +00:00
<b>Rationale:</b> Throughput is maximized by increasing batch size (64) to utilize the massive memory bandwidth of Strix Halo, and running more prompts (200) to measure sustained steady-state performance.
2026-02-02 21:30:17 +00:00
<b>Metric:</b> Tokens per Second (higher is better). ` ,
2025-12-20 11:37:06 +00:00
unit : " tok/s"
} ,
"TTFT" : {
short : "Time To First Token (Response Latency)." ,
2026-02-02 21:30:17 +00:00
desc : "Delay between sending a request and seeing the first character." ,
usecase : "Responsiveness. Low TTFT makes the AI feel 'snappy'." ,
details : "Command: `vllm bench serve`\nMetric: Milliseconds (lower is better)." ,
2025-12-20 11:37:06 +00:00
unit : " ms"
} ,
"TPOT" : {
short : "Time Per Output Token (Streaming Speed)." ,
2026-02-02 21:30:17 +00:00
desc : "Measures how fast the text generates *after* the first token." ,
usecase : "Fluidity. Industry standard is <50ms (>20 tok/s)." ,
details : "Command: `vllm bench serve`\nMetric: Milliseconds (lower is better)." ,
2025-12-20 11:37:06 +00:00
unit : " ms"
}
} ;
async function init ( ) {
try {
const res = await fetch ( 'results.json' ) ;
const data = await res . json ( ) ;
rawRuns = data . runs || [ ] ;
processData ( ) ;
2026-02-02 21:30:17 +00:00
setupControls ( ) ;
2025-12-20 11:37:06 +00:00
render ( ) ;
} catch ( e ) {
$ ( 'loading' ) . textContent = "Error loading results.json: " + e . message ;
console . error ( e ) ;
}
}
2026-02-02 21:30:17 +00:00
function setupControls ( ) {
// Filters
const quants = new Set ( rawRuns . map ( r => r . quant ) . filter ( Boolean ) ) ;
const sel = $ ( 'quantFilter' ) ;
[ ... quants ] . sort ( ) . forEach ( q => {
const opt = document . createElement ( 'option' ) ;
opt . value = q ;
opt . textContent = q ;
sel . appendChild ( opt ) ;
} ) ;
$ ( 'searchInput' ) . addEventListener ( 'input' , e => { state . search = e . target . value . toLowerCase ( ) ; render ( ) ; } ) ;
sel . addEventListener ( 'change' , e => { state . quant = e . target . value ; render ( ) ; } ) ;
// Toggles
$ ( 'toggleTP1' ) . addEventListener ( 'change' , e => { state . showTP1 = e . target . checked ; render ( ) ; } ) ;
$ ( 'toggleTP2' ) . addEventListener ( 'change' , e => { state . showTP2 = e . target . checked ; render ( ) ; } ) ;
$ ( 'toggleTriton' ) . addEventListener ( 'change' , e => { state . showTriton = e . target . checked ; render ( ) ; } ) ;
$ ( 'toggleRocm' ) . addEventListener ( 'change' , e => { state . showRocm = e . target . checked ; render ( ) ; } ) ;
}
2025-12-20 11:37:06 +00:00
function processData ( ) {
const testGroups = { } ;
rawRuns . forEach ( run => {
2026-02-02 21:30:17 +00:00
let testName = run . test ;
if ( ! testGroups [ testName ] ) {
testGroups [ testName ] = { name : testName , models : { } } ;
2025-12-20 11:37:06 +00:00
}
const modelName = run . model _clean || run . model ;
2026-02-02 21:30:17 +00:00
if ( ! testGroups [ testName ] . models [ modelName ] ) {
testGroups [ testName ] . models [ modelName ] = {
2025-12-20 11:37:06 +00:00
name : modelName ,
quant : run . quant ,
params : run . params _b || run . name _params _b ,
2026-02-02 21:30:17 +00:00
results : {
1 : { triton : null , rocm : null } ,
2 : { triton : null , rocm : null }
}
2025-12-20 11:37:06 +00:00
} ;
}
2026-02-02 21:30:17 +00:00
const m = testGroups [ testName ] . models [ modelName ] ;
const tp = run . tp || 1 ;
2025-12-20 11:37:06 +00:00
2026-02-02 21:30:17 +00:00
if ( ! m . results [ tp ] ) m . results [ tp ] = { triton : null , rocm : null } ;
2025-12-20 11:37:06 +00:00
2026-02-02 21:30:17 +00:00
if ( run . backend === "Triton" ) m . results [ tp ] . triton = run . tps _mean ;
if ( run . backend === "ROCm" ) m . results [ tp ] . rocm = run . tps _mean ;
2025-12-20 11:37:06 +00:00
} ) ;
2026-02-02 21:30:17 +00:00
tests = Object . values ( testGroups ) . map ( g => ( {
name : g . name ,
models : Object . values ( g . models )
} ) ) ;
2026-02-01 19:36:07 +00:00
2026-02-02 21:30:17 +00:00
tests . sort ( ( a , b ) => {
const aTp = a . name . includes ( "Throughput" ) ;
const bTp = b . name . includes ( "Throughput" ) ;
2026-02-01 19:36:07 +00:00
if ( aTp && ! bTp ) return - 1 ;
if ( ! aTp && bTp ) return 1 ;
2025-12-20 11:37:06 +00:00
return a . name . localeCompare ( b . name ) ;
} ) ;
2026-02-02 21:30:17 +00:00
if ( tests . length > 0 ) state . activeTab = tests [ 0 ] . name ;
2025-12-20 11:37:06 +00:00
}
2026-02-02 21:30:17 +00:00
function formatVal ( v , unit ) {
if ( v === null || v === undefined ) return '<span class="val-na">-</span>' ;
if ( v === 0 ) return '<span class="val-na" style="color:#ef4444;font-weight:bold;">X</span>' ;
return ` <span class="val"> ${ v . toFixed ( 2 ) } <span style="font-size:0.75em; color:#9ca3af; margin-left:2px;"> ${ unit } </span></span> ` ;
2025-12-20 11:37:06 +00:00
}
2026-02-02 21:30:17 +00:00
function getMeta ( name ) {
if ( name . includes ( "Throughput" ) ) return BENCHMARK _INFO [ "Throughput" ] ;
if ( name . includes ( "TTFT" ) ) return BENCHMARK _INFO [ "TTFT" ] ;
if ( name . includes ( "TPOT" ) ) return BENCHMARK _INFO [ "TPOT" ] ;
return { short : "" , desc : "" , unit : "" } ;
2025-12-20 11:37:06 +00:00
}
function render ( ) {
const container = $ ( 'dashboard' ) ;
const tabNav = $ ( 'tabNav' ) ;
// Render Tabs
tabNav . innerHTML = "" ;
tests . forEach ( test => {
const btn = document . createElement ( 'button' ) ;
btn . className = ` tab-btn ${ test . name === state . activeTab ? 'active' : '' } ` ;
btn . textContent = test . name ;
2026-02-02 21:30:17 +00:00
btn . onclick = ( ) => { state . activeTab = test . name ; render ( ) ; } ;
2025-12-20 11:37:06 +00:00
tabNav . appendChild ( btn ) ;
} ) ;
container . innerHTML = "" ;
const activeTest = tests . find ( t => t . name === state . activeTab ) ;
if ( ! activeTest ) {
2026-02-02 21:30:17 +00:00
container . innerHTML = '<div id="loading">No Data</div>' ;
2025-12-20 11:37:06 +00:00
return ;
}
2026-02-02 21:30:17 +00:00
// Simplified Info Box logic
if ( state . showTP2 ) {
2026-02-02 19:34:33 +00:00
const infoBox = document . createElement ( 'div' ) ;
2026-02-02 21:30:17 +00:00
infoBox . style . cssText = "background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px; padding:10px 16px; margin-bottom:20px; font-size:0.9rem; color:#64748b; display:flex; justify-content:space-between; align-items:center;" ;
2026-02-02 19:34:33 +00:00
infoBox . innerHTML = `
2026-02-02 21:30:17 +00:00
<span><b>TP2</b> = Distributed Cluster (2x Strix Halo, RDMA RoCE v2).</span>
<a href="https://github.com/kyuz0/amd-strix-halo-vllm-toolboxes/blob/main/rdma_cluster/setup_guide.md" target="_blank" style="color:#3b82f6; text-decoration:none; font-weight:500;">Cluster Setup Guide →</a>
2026-02-02 19:34:33 +00:00
` ;
container . appendChild ( infoBox ) ;
}
2026-02-02 21:30:17 +00:00
// Models Filter & Sort
const models = activeTest . models . filter ( m => {
const matchS = ! state . search || m . name . toLowerCase ( ) . includes ( state . search ) ;
const matchQ = ! state . quant || m . quant === state . quant ;
return matchS && matchQ ;
} ) . sort ( ( a , b ) => ( parseFloat ( a . params ) || 0 ) - ( parseFloat ( b . params ) || 0 ) || a . name . localeCompare ( b . name ) ) ;
2025-12-20 11:37:06 +00:00
2026-02-02 21:30:17 +00:00
// Create Table
2025-12-20 11:37:06 +00:00
const card = document . createElement ( 'div' ) ;
card . className = "section-card" ;
2026-02-02 21:30:17 +00:00
const meta = getMeta ( activeTest . name ) ;
const unit = meta . unit || "" ;
2025-12-20 11:37:06 +00:00
2026-02-02 21:30:17 +00:00
// Header
2025-12-20 11:37:06 +00:00
const header = document . createElement ( 'div' ) ;
header . className = "section-header" ;
header . innerHTML = `
2026-02-02 21:30:17 +00:00
<div class="section-title-row">
<h2> ${ activeTest . name } </h2>
<button class="btn-help" onclick="openModal(' ${ activeTest . name } ')">?</button>
</div>
<span class="section-desc"> ${ meta . short } </span>
` ;
2025-12-20 11:37:06 +00:00
card . appendChild ( header ) ;
2026-02-02 21:30:17 +00:00
// Table
2025-12-20 11:37:06 +00:00
const tableResp = document . createElement ( 'div' ) ;
tableResp . className = "table-responsive" ;
const table = document . createElement ( 'table' ) ;
2026-02-02 21:30:17 +00:00
// Build Dynamic Columns
let cols = [ ] ;
if ( state . showTP1 ) {
if ( state . showTriton ) cols . push ( { id : "tp1_triton" , label : "TP1 Triton" } ) ;
if ( state . showRocm ) cols . push ( { id : "tp1_rocm" , label : "TP1 ROCm" } ) ;
}
if ( state . showTP2 ) {
if ( state . showTriton ) cols . push ( { id : "tp2_triton" , label : "TP2 Triton" } ) ;
if ( state . showRocm ) cols . push ( { id : "tp2_rocm" , label : "TP2 ROCm" } ) ;
}
// Thead
let theadHtml = ` <thead><tr><th class="col-model">Model</th> ` ;
cols . forEach ( c => {
// Style differentiation for TP2
const style = c . id . startsWith ( "tp2" ) ? "background:#eff6ff; color:#1e40af;" : "" ;
theadHtml += ` <th class="col-data" style=" ${ style } "> ${ c . label } </th> ` ;
} ) ;
// Diff Column Header
if ( cols . length === 2 ) {
theadHtml += ` <th class="col-data col-diff">Diff</th> ` ;
}
theadHtml += ` </tr></thead> ` ;
table . innerHTML = theadHtml ;
// Tbody
2025-12-20 11:37:06 +00:00
const tbody = document . createElement ( 'tbody' ) ;
models . forEach ( m => {
const tr = document . createElement ( 'tr' ) ;
2026-02-02 21:30:17 +00:00
// Model Name Cell
2025-12-20 11:37:06 +00:00
let metaHtml = "" ;
if ( m . quant ) metaHtml += ` <span class="tag"> ${ m . quant } </span> ` ;
if ( m . params ) metaHtml += ` <span class="tag"> ${ m . params } B</span> ` ;
2026-02-02 21:30:17 +00:00
let rowHtml = `
<td>
<div class="model-cell">
<a href="https://huggingface.co/ ${ m . name } " target="_blank" class="model-name" style="text-decoration:none;color:inherit;"> ${ m . name } </a>
<div class="model-meta"> ${ metaHtml } </div>
</div>
</td>
` ;
// Data Cells
cols . forEach ( c => {
let val = null ;
if ( c . id === "tp1_triton" ) val = m . results [ 1 ] ? . triton ;
if ( c . id === "tp1_rocm" ) val = m . results [ 1 ] ? . rocm ;
if ( c . id === "tp2_triton" ) val = m . results [ 2 ] ? . triton ;
if ( c . id === "tp2_rocm" ) val = m . results [ 2 ] ? . rocm ;
const bg = c . id . startsWith ( "tp2" ) ? 'style="background:#fbfdff;"' : "" ;
rowHtml += ` <td class="col-data" ${ bg } > ${ formatVal ( val , unit ) } </td> ` ;
} ) ;
// Diff Column Data
if ( cols . length === 2 ) {
const v1 = getVal ( m , cols [ 0 ] . id ) ;
const v2 = getVal ( m , cols [ 1 ] . id ) ;
rowHtml += ` <td class="col-data col-diff"> ${ formatDiff ( v1 , v2 ) } </td> ` ;
2025-12-20 11:49:03 +00:00
}
2025-12-20 11:37:06 +00:00
2026-02-02 21:30:17 +00:00
tr . innerHTML = rowHtml ;
2025-12-20 11:37:06 +00:00
tbody . appendChild ( tr ) ;
} ) ;
2026-02-02 21:30:17 +00:00
2025-12-20 11:37:06 +00:00
table . appendChild ( tbody ) ;
tableResp . appendChild ( table ) ;
card . appendChild ( tableResp ) ;
container . appendChild ( card ) ;
}
2026-02-02 21:30:17 +00:00
// Helper to get value safely
function getVal ( m , colId ) {
if ( colId === "tp1_triton" ) return m . results [ 1 ] ? . triton ;
if ( colId === "tp1_rocm" ) return m . results [ 1 ] ? . rocm ;
if ( colId === "tp2_triton" ) return m . results [ 2 ] ? . triton ;
if ( colId === "tp2_rocm" ) return m . results [ 2 ] ? . rocm ;
return null ;
2025-12-20 11:37:06 +00:00
}
2026-02-02 21:30:17 +00:00
function formatDiff ( v1 , v2 ) {
if ( v1 === null || v2 === null || v1 === undefined || v2 === undefined || v1 === 0 ) return '<span class="val-na">-</span>' ;
const diff = ( ( v2 - v1 ) / v1 ) * 100 ;
const sign = diff > 0 ? "+" : "" ;
const cls = diff > 0.5 ? "val-pos" : ( diff < - 0.5 ? "val-neg" : "val-neu" ) ;
return ` <span class=" ${ cls } "> ${ sign } ${ diff . toFixed ( 1 ) } %</span> ` ;
2025-12-20 11:37:06 +00:00
}
2026-02-02 21:30:17 +00:00
// --- Basic Modal Implementation ---
function openModal ( name ) {
const m = getMeta ( name ) ;
$ ( 'modalTitle' ) . textContent = name ;
$ ( 'modalContent' ) . innerHTML = `
<div class="modal-section"><h4>About</h4><p> ${ m . desc } </p></div>
<div class="modal-section"><h4>Usage</h4><p> ${ m . usecase } </p></div>
<div class="modal-section"><h4>Details</h4><div class="code-block"> ${ m . details } </div></div>
` ;
$ ( 'modalOverlay' ) . classList . add ( 'active' ) ;
2025-12-20 11:37:06 +00:00
}
2026-02-02 21:30:17 +00:00
function closeModal ( ) { $ ( 'modalOverlay' ) . classList . remove ( 'active' ) ; }
$ ( 'modalOverlay' ) . addEventListener ( 'click' , e => { if ( e . target === $ ( 'modalOverlay' ) ) closeModal ( ) ; } ) ;
document . addEventListener ( 'keydown' , e => { if ( e . key === "Escape" ) closeModal ( ) ; } ) ;
2025-12-20 11:37:06 +00:00
init ( ) ;
< / script >
< / body >
< / html >