|
| 1 | +import { resolveFrameworkPartLabel } from '@semianalysisai/inferencex-constants'; |
| 2 | + |
| 3 | +import type { BenchmarkRow } from './api'; |
| 4 | +import { dedupeRowsToLatestPerConfig } from './benchmark-series'; |
| 5 | +import { getHardwareConfig, getModelSortIndex } from './constants'; |
| 6 | +import { getModelLabel, PRECISION_OPTIONS, type Model, type Precision } from './data-mappings'; |
| 7 | +import { |
| 8 | + computeTcoFeed, |
| 9 | + computeTcoScores, |
| 10 | + DEFAULT_TIER_WEIGHTS, |
| 11 | + type TcoTierBoundary, |
| 12 | +} from './tco-feed'; |
| 13 | + |
| 14 | +export const OVERVIEW_WORKLOAD = { isl: 8192, osl: 1024 } as const; |
| 15 | +export const OVERVIEW_TIERS = [30, 50, 75, 100] as const; |
| 16 | + |
| 17 | +export interface OverviewTierValue { |
| 18 | + tier: number; |
| 19 | + value: number | null; |
| 20 | + boundary: TcoTierBoundary; |
| 21 | +} |
| 22 | + |
| 23 | +export interface OverviewHardwareResult { |
| 24 | + hardware: string; |
| 25 | + hardwareLabel: string; |
| 26 | + precision: string; |
| 27 | + decodeMode: 'speculative' | 'standard_fallback'; |
| 28 | + decodeLabel: string; |
| 29 | + score: number; |
| 30 | + tierValues: OverviewTierValue[]; |
| 31 | + latestDate: string; |
| 32 | + oldestFrontierDate: string; |
| 33 | +} |
| 34 | + |
| 35 | +export interface OverviewModelSummary { |
| 36 | + model: Model; |
| 37 | + modelLabel: string; |
| 38 | + selectedPrecision: string | null; |
| 39 | + winner: OverviewHardwareResult | null; |
| 40 | + runnerUp: OverviewHardwareResult | null; |
| 41 | + runnerUpGapPercent: number | null; |
| 42 | + hardwareResults: OverviewHardwareResult[]; |
| 43 | + emptyReason: 'no_8k1k_single_turn_data' | null; |
| 44 | +} |
| 45 | + |
| 46 | +export interface OverviewPageData { |
| 47 | + models: OverviewModelSummary[]; |
| 48 | + latestDate: string | null; |
| 49 | +} |
| 50 | + |
| 51 | +function precisionRank(precision: string): number { |
| 52 | + const index = PRECISION_OPTIONS.indexOf(precision as Precision); |
| 53 | + return index === -1 ? PRECISION_OPTIONS.length : index; |
| 54 | +} |
| 55 | + |
| 56 | +export function selectOverviewPrecision(rows: BenchmarkRow[]): string | null { |
| 57 | + const curvesByPrecision = new Map<string, Set<string>>(); |
| 58 | + |
| 59 | + for (const row of rows) { |
| 60 | + let curves = curvesByPrecision.get(row.precision); |
| 61 | + if (!curves) { |
| 62 | + curves = new Set<string>(); |
| 63 | + curvesByPrecision.set(row.precision, curves); |
| 64 | + } |
| 65 | + curves.add( |
| 66 | + `${row.hardware}|${row.framework}|${row.spec_method}|${row.disagg}|${row.offload_mode}`, |
| 67 | + ); |
| 68 | + } |
| 69 | + |
| 70 | + return ( |
| 71 | + [...curvesByPrecision.entries()] |
| 72 | + .toSorted( |
| 73 | + ([precisionA, curvesA], [precisionB, curvesB]) => |
| 74 | + curvesB.size - curvesA.size || |
| 75 | + precisionRank(precisionA) - precisionRank(precisionB) || |
| 76 | + precisionA.localeCompare(precisionB), |
| 77 | + ) |
| 78 | + .at(0)?.[0] ?? null |
| 79 | + ); |
| 80 | +} |
| 81 | + |
| 82 | +type DecodePolicy = Pick<OverviewHardwareResult, 'decodeMode' | 'decodeLabel'>; |
| 83 | + |
| 84 | +function emptyModelSummary(model: Model, selectedPrecision: string | null): OverviewModelSummary { |
| 85 | + return { |
| 86 | + model, |
| 87 | + modelLabel: getModelLabel(model), |
| 88 | + selectedPrecision, |
| 89 | + winner: null, |
| 90 | + runnerUp: null, |
| 91 | + runnerUpGapPercent: null, |
| 92 | + hardwareResults: [], |
| 93 | + emptyReason: 'no_8k1k_single_turn_data', |
| 94 | + }; |
| 95 | +} |
| 96 | + |
| 97 | +export function buildOverviewModelSummary( |
| 98 | + model: Model, |
| 99 | + rows: BenchmarkRow[], |
| 100 | +): OverviewModelSummary { |
| 101 | + const workloadRows = rows.filter( |
| 102 | + (row) => |
| 103 | + row.benchmark_type === 'single_turn' && |
| 104 | + row.isl === OVERVIEW_WORKLOAD.isl && |
| 105 | + row.osl === OVERVIEW_WORKLOAD.osl, |
| 106 | + ); |
| 107 | + const dedupedRows = dedupeRowsToLatestPerConfig(workloadRows); |
| 108 | + const selectedPrecision = selectOverviewPrecision(dedupedRows); |
| 109 | + if (selectedPrecision === null) return emptyModelSummary(model, null); |
| 110 | + |
| 111 | + const rowsByHardware = new Map<string, BenchmarkRow[]>(); |
| 112 | + for (const row of dedupedRows) { |
| 113 | + if (row.precision !== selectedPrecision) continue; |
| 114 | + const hardwareRows = rowsByHardware.get(row.hardware); |
| 115 | + if (hardwareRows) hardwareRows.push(row); |
| 116 | + else rowsByHardware.set(row.hardware, [row]); |
| 117 | + } |
| 118 | + |
| 119 | + const retainedRows: BenchmarkRow[] = []; |
| 120 | + const decodePolicyByHardware = new Map<string, DecodePolicy>(); |
| 121 | + for (const [hardware, hardwareRows] of rowsByHardware) { |
| 122 | + const speculativeRows = hardwareRows.filter((row) => row.spec_method !== 'none'); |
| 123 | + if (speculativeRows.length > 0) { |
| 124 | + retainedRows.push(...speculativeRows); |
| 125 | + const decodeLabel = [...new Set(speculativeRows.map((row) => row.spec_method))] |
| 126 | + .toSorted((a, b) => a.localeCompare(b)) |
| 127 | + .map((method) => resolveFrameworkPartLabel(model, method)) |
| 128 | + .join(', '); |
| 129 | + decodePolicyByHardware.set(hardware, { decodeMode: 'speculative', decodeLabel }); |
| 130 | + } else { |
| 131 | + retainedRows.push(...hardwareRows); |
| 132 | + decodePolicyByHardware.set(hardware, { |
| 133 | + decodeMode: 'standard_fallback', |
| 134 | + decodeLabel: 'Standard decode fallback', |
| 135 | + }); |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + const feed = computeTcoFeed(retainedRows, [OVERVIEW_WORKLOAD], OVERVIEW_TIERS); |
| 140 | + const scores = computeTcoScores( |
| 141 | + feed, |
| 142 | + [OVERVIEW_WORKLOAD], |
| 143 | + OVERVIEW_TIERS, |
| 144 | + DEFAULT_TIER_WEIGHTS, |
| 145 | + [1], |
| 146 | + 0, |
| 147 | + ); |
| 148 | + |
| 149 | + const hardwareResults = scores |
| 150 | + .map((score): OverviewHardwareResult => { |
| 151 | + const policy = decodePolicyByHardware.get(score.hardware)!; |
| 152 | + const tierValues = feed |
| 153 | + .filter((row) => row.hardware === score.hardware) |
| 154 | + .map( |
| 155 | + (row): OverviewTierValue => ({ |
| 156 | + tier: row.tier, |
| 157 | + value: |
| 158 | + row.boundary === 'unreachable' && row.output_tput_per_gpu === 0 |
| 159 | + ? null |
| 160 | + : row.output_tput_per_gpu, |
| 161 | + boundary: row.boundary, |
| 162 | + }), |
| 163 | + ); |
| 164 | + |
| 165 | + return { |
| 166 | + hardware: score.hardware, |
| 167 | + hardwareLabel: getHardwareConfig(score.hardware, model).label, |
| 168 | + precision: selectedPrecision, |
| 169 | + ...policy, |
| 170 | + score: score.score, |
| 171 | + tierValues, |
| 172 | + latestDate: score.latest_date, |
| 173 | + oldestFrontierDate: score.oldest_frontier_date, |
| 174 | + }; |
| 175 | + }) |
| 176 | + .toSorted( |
| 177 | + (a, b) => |
| 178 | + b.score - a.score || |
| 179 | + getModelSortIndex(a.hardware) - getModelSortIndex(b.hardware) || |
| 180 | + a.hardware.localeCompare(b.hardware), |
| 181 | + ); |
| 182 | + |
| 183 | + if (hardwareResults.length === 0) return emptyModelSummary(model, selectedPrecision); |
| 184 | + |
| 185 | + const winner = hardwareResults[0]; |
| 186 | + const runnerUp = hardwareResults[1] ?? null; |
| 187 | + |
| 188 | + return { |
| 189 | + model, |
| 190 | + modelLabel: getModelLabel(model), |
| 191 | + selectedPrecision, |
| 192 | + winner, |
| 193 | + runnerUp, |
| 194 | + runnerUpGapPercent: |
| 195 | + runnerUp && runnerUp.score > 0 ? (winner.score / runnerUp.score - 1) * 100 : null, |
| 196 | + hardwareResults, |
| 197 | + emptyReason: null, |
| 198 | + }; |
| 199 | +} |
0 commit comments