Skip to content

Commit d569d4c

Browse files
committed
feat(agentic): surface runtime component metadata
Preserve and render KV offload engines, KV transfer engines, and router names/versions across official, comparison, fixed-sequence, agentic, and unofficial-run tooltips. Add an artifact-backed metadata backfill that merges only runtime keys into historical rows. 中文:展示 Agentic 运行时组件元数据。在正式运行、GPU 对比、固定序列长度、Agentic 及非正式运行提示卡中保留并展示 KV 卸载引擎、KV 传输引擎以及路由器名称和版本;新增基于原始产物的元数据回填,仅向历史数据合并运行时字段。
1 parent bfdc8a5 commit d569d4c

15 files changed

Lines changed: 379 additions & 40 deletions

packages/app/cypress/e2e/gpu-compare-agentic-detail.cy.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ const agenticBenchmarks = AGENTIC_HARDWARE.flatMap((g) =>
115115
kv_offloading: 'dram',
116116
kv_offload_backend: 'mooncake',
117117
kv_offload_backend_version: '0.3.11.post1',
118+
router_name: 'vllm-router',
119+
router_version: '0.1.14',
118120
server_gpu_cache_hit_rate: 0.875,
119121
},
120122
workers: null,
@@ -184,7 +186,8 @@ describe('GPU comparison agentic point detail', () => {
184186
cy.get('[data-chart-tooltip]:visible').should('have.length', 1);
185187
cy.get('[data-chart-tooltip]:visible')
186188
.should('contain', 'Offload Type: DRAM')
187-
.and('contain', 'Offload Backend: Mooncake 0.3.11.post1')
189+
.and('contain', 'KV Offload Engine: Mooncake 0.3.11.post1')
190+
.and('contain', 'Router: vLLM Router 0.1.14')
188191
.and('contain', 'GPU Cache Hit Rate: 87.5%')
189192
.and('not.contain', 'Offload Mode');
190193
cy.get('[data-chart-tooltip]:visible [data-action="view-charts"]')

packages/app/cypress/e2e/unofficial-watermark.cy.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ describe('Unofficial-run watermark', () => {
2525
kv_offloading: 'dram',
2626
kv_offload_backend: 'hicache',
2727
kv_p2p_transfer: 'nixl',
28+
router_name: 'sglang-router',
29+
router_version: '0.3.2',
2830
server_gpu_cache_hit_rate: 0.875,
2931
},
3032
run_url: runUrl,
@@ -74,8 +76,9 @@ describe('Unofficial-run watermark', () => {
7476
expect(tooltip).not.to.equal(null);
7577
expect(tooltip!.style.display).to.equal('block');
7678
expect(tooltip).to.contain.text('Offload Type: DRAM');
77-
expect(tooltip).to.contain.text('Offload Backend: HiCache');
78-
expect(tooltip).to.contain.text('KV Cache Transfer Engine: NIXL');
79+
expect(tooltip).to.contain.text('KV Offload Engine: HiCache');
80+
expect(tooltip).to.contain.text('KV Transfer Engine: NIXL');
81+
expect(tooltip).to.contain.text('Router: SGLang Router 0.3.2');
7982
expect(tooltip).to.contain.text('GPU Cache Hit Rate: 87.5%');
8083
});
8184

packages/app/src/components/inference/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ export interface AggDataEntry {
201201
kv_offload_backend_version?: string;
202202
/** P2P engine used to move KV state between workers on multinode runs. */
203203
kv_p2p_transfer?: string;
204+
/** Request router implementation, for example `vllm-router` or `sglang-router`. */
205+
router_name?: string;
206+
/** Version independently declared for the request router. */
207+
router_version?: string;
204208
/** Actual server-observed GPU prefix-cache hit rate (0..1). */
205209
server_gpu_cache_hit_rate?: number;
206210
/** Actual server-observed CPU prefix-cache hit rate (0..1). */

packages/app/src/components/inference/utils/tooltip-utils.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ describe('generateTooltipContent', () => {
258258
}),
259259
);
260260
expect(html).toContain('<strong>Offload Type:</strong> DRAM');
261-
expect(html).toContain('<strong>Offload Backend:</strong> Mooncake 0.3.11.post1');
261+
expect(html).toContain('<strong>KV Offload Engine:</strong> Mooncake 0.3.11.post1');
262262
expect(html).not.toContain('Offload Mode');
263263
});
264264

@@ -273,19 +273,25 @@ describe('generateTooltipContent', () => {
273273
}),
274274
}),
275275
);
276-
expect(html).toContain('<strong>KV Cache Transfer Engine:</strong> NIXL');
276+
expect(html).toContain('<strong>KV Transfer Engine:</strong> NIXL');
277277
expect(html).toContain('<strong>GPU Cache Hit Rate:</strong> 87.5%');
278278
});
279279

280280
it('uses Chinese labels for new cache metadata on /zh surfaces', () => {
281281
const html = generateTooltipContent(
282282
tooltipConfig({
283283
locale: 'zh',
284-
data: pt({ kv_offloading: 'dram', kv_offload_backend: 'lmcache' }),
284+
data: pt({
285+
kv_offloading: 'dram',
286+
kv_offload_backend: 'lmcache',
287+
router_name: 'vllm-router',
288+
router_version: '0.1.14',
289+
}),
285290
}),
286291
);
287292
expect(html).toContain('<strong>卸载类型:</strong> DRAM');
288-
expect(html).toContain('<strong>卸载后端:</strong> LMCache');
293+
expect(html).toContain('<strong>KV 卸载引擎:</strong> LMCache');
294+
expect(html).toContain('<strong>路由器:</strong> vLLM Router 0.1.14');
289295
});
290296

291297
it('localizes an empty offload tier on /zh surfaces', () => {
@@ -386,12 +392,17 @@ describe('generateOverlayTooltipContent', () => {
386392
benchmark_type: 'agentic_traces',
387393
kv_offloading: 'dram',
388394
kv_offload_backend: 'hicache',
395+
kv_p2p_transfer: 'nixl',
396+
router_name: 'sglang-router',
397+
router_version: '0.3.2',
389398
server_cpu_cache_hit_rate: 0.42,
390399
}),
391400
}),
392401
);
393402
expect(html).toContain('<strong>Offload Type:</strong> DRAM');
394-
expect(html).toContain('<strong>Offload Backend:</strong> HiCache');
403+
expect(html).toContain('<strong>KV Offload Engine:</strong> HiCache');
404+
expect(html).toContain('<strong>KV Transfer Engine:</strong> NIXL');
405+
expect(html).toContain('<strong>Router:</strong> SGLang Router 0.3.2');
395406
expect(html).toContain('<strong>CPU Cache Hit Rate:</strong> 42.0%');
396407
});
397408
});

packages/app/src/components/inference/utils/tooltipUtils.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,19 @@ export const fmt = (v: number): string => {
9696
const CACHE_STRINGS = {
9797
en: {
9898
offloadType: 'Offload Type',
99-
offloadBackend: 'Offload Backend',
100-
transferEngine: 'KV Cache Transfer Engine',
99+
offloadBackend: 'KV Offload Engine',
100+
transferEngine: 'KV Transfer Engine',
101+
router: 'Router',
101102
gpuHitRate: 'GPU Cache Hit Rate',
102103
cpuHitRate: 'CPU Cache Hit Rate',
103104
theoreticalHitRate: 'Theoretical Cache Hit Rate',
104105
none: 'None',
105106
},
106107
zh: {
107108
offloadType: '卸载类型',
108-
offloadBackend: '卸载后端',
109-
transferEngine: 'KV Cache 传输引擎',
109+
offloadBackend: 'KV 卸载引擎',
110+
transferEngine: 'KV 传输引擎',
111+
router: '路由器',
110112
gpuHitRate: 'GPU Cache 命中率',
111113
cpuHitRate: 'CPU Cache 命中率',
112114
theoreticalHitRate: '理论 Cache 命中率',
@@ -122,8 +124,11 @@ const CACHE_IMPLEMENTATION_LABELS: Record<string, string> = {
122124
moriio: 'MoRI-IO',
123125
'mori-io': 'MoRI-IO',
124126
nixl: 'NIXL',
127+
atomesh: 'AtoMesh',
125128
'vllm-native': 'vLLM Native',
129+
'vllm-router': 'vLLM Router',
126130
'vllm-simple': 'vLLM Simple',
131+
'sglang-router': 'SGLang Router',
127132
};
128133

129134
const cacheImplementationLabel = (value: string): string =>
@@ -150,9 +155,14 @@ const generateCacheMetadataHTML = (d: InferenceData, locale: Locale): string =>
150155
const version = d.kv_offload_backend_version ? ` ${d.kv_offload_backend_version}` : '';
151156
parts.push(tooltipLine(t.offloadBackend, `${backend}${version}`));
152157
}
153-
if (d.is_multinode && d.kv_p2p_transfer) {
158+
if (d.kv_p2p_transfer) {
154159
parts.push(tooltipLine(t.transferEngine, cacheImplementationLabel(d.kv_p2p_transfer)));
155160
}
161+
if (d.router_name) {
162+
const router = cacheImplementationLabel(d.router_name);
163+
const version = d.router_version ? ` ${d.router_version}` : '';
164+
parts.push(tooltipLine(t.router, `${router}${version}`));
165+
}
156166

157167
const gpuHit = formatPct(d.server_gpu_cache_hit_rate);
158168
const cpuHit = formatPct(d.server_cpu_cache_hit_rate);

packages/app/src/lib/benchmark-transform.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ describe('rowToAggDataEntry', () => {
131131
kv_offload_backend: 'mooncake',
132132
kv_offload_backend_version: '0.3.11.post1',
133133
kv_p2p_transfer: 'nixl',
134+
router_name: 'vllm-router',
135+
router_version: '0.1.14',
134136
} as unknown as BenchmarkRow['metrics'],
135137
}),
136138
);
@@ -139,6 +141,8 @@ describe('rowToAggDataEntry', () => {
139141
expect(entry.kv_offload_backend).toBe('mooncake');
140142
expect(entry.kv_offload_backend_version).toBe('0.3.11.post1');
141143
expect(entry.kv_p2p_transfer).toBe('nixl');
144+
expect(entry.router_name).toBe('vllm-router');
145+
expect(entry.router_version).toBe('0.1.14');
142146
});
143147

144148
it('passes through measured power telemetry fields when present', () => {

packages/app/src/lib/benchmark-transform.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ export function rowToAggDataEntry(row: BenchmarkRow): AggDataEntry {
168168
kv_offload_backend: stringMetric('kv_offload_backend'),
169169
kv_offload_backend_version: stringMetric('kv_offload_backend_version'),
170170
kv_p2p_transfer: stringMetric('kv_p2p_transfer'),
171+
router_name: stringMetric('router_name'),
172+
router_version: stringMetric('router_version'),
171173
server_gpu_cache_hit_rate: m.server_gpu_cache_hit_rate,
172174
server_cpu_cache_hit_rate: m.server_cpu_cache_hit_rate,
173175
theoretical_cache_hit_rate: m.theoretical_cache_hit_rate,

packages/db/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"db:backfill-chart-series": "dotenv -e ../../.env -- tsx src/backfill-chart-series.ts",
2424
"db:backfill-dataset-stats": "dotenv -e ../../.env -- tsx src/backfill-dataset-stats.ts",
2525
"db:backfill-request-timeline": "dotenv -e ../../.env -- tsx src/backfill-request-timeline.ts",
26+
"db:backfill-runtime-metadata": "dotenv -e ../../.env -- tsx src/backfill-runtime-metadata.ts",
2627
"db:dump": "dotenv -e ../../.env -- tsx src/dump-db.ts",
2728
"db:load-dump": "dotenv -e ../../.env -- tsx src/load-dump.ts",
2829
"db:reset": "dotenv -e ../../.env -- tsx src/reset-db.ts",
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/**
2+
* Restore runtime component metadata that older app ingest versions dropped.
3+
*
4+
* The benchmark producer began emitting nested router/offload component objects
5+
* and `kv_p2p_transfer` on 2026-07-13. The raw GitHub Actions benchmark
6+
* artifacts remain authoritative, so this script downloads only the small
7+
* benchmark-result artifacts and merges those metadata keys into matching DB
8+
* rows. It never replaces measured metrics or topology/config data.
9+
*
10+
* Usage:
11+
* pnpm --filter @semianalysisai/inferencex-db db:backfill-runtime-metadata
12+
* pnpm --filter @semianalysisai/inferencex-db db:backfill-runtime-metadata --yes
13+
*/
14+
15+
import fs from 'node:fs';
16+
import os from 'node:os';
17+
import path from 'node:path';
18+
19+
import { hasNoSslFlag } from './cli-utils.js';
20+
import { mapBenchmarkRow } from './etl/benchmark-mapper.js';
21+
import { createAdminSql, refreshLatestBenchmarks } from './etl/db-utils.js';
22+
import { createSkipTracker } from './etl/skip-tracker.js';
23+
import { downloadArtifact, listRunArtifacts } from './lib/github-artifacts.js';
24+
import { confirmProceed, runBackfillMain } from './lib/backfill-runner.js';
25+
import {
26+
repositoryFromRunUrl,
27+
selectBenchmarkArtifacts,
28+
} from './lib/runtime-metadata-artifacts.js';
29+
30+
const REPO = 'SemiAnalysisAI/InferenceX';
31+
const FIRST_METADATA_DATE = '2026-07-14';
32+
const RUNTIME_KEYS = [
33+
'kv_offloading',
34+
'kv_offload_backend',
35+
'kv_offload_backend_version',
36+
'kv_p2p_transfer',
37+
'router_name',
38+
'router_version',
39+
] as const;
40+
41+
const sql = createAdminSql({ noSsl: hasNoSslFlag(), max: 2, onnotice: () => {} });
42+
43+
function findJsonFiles(root: string): string[] {
44+
const files: string[] = [];
45+
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
46+
const pathname = path.join(root, entry.name);
47+
if (entry.isDirectory()) files.push(...findJsonFiles(pathname));
48+
else if (entry.isFile() && entry.name.endsWith('.json')) files.push(pathname);
49+
}
50+
return files;
51+
}
52+
53+
async function backfillRawRow(githubRunId: number, rawRow: Record<string, unknown>) {
54+
const mapped = mapBenchmarkRow(rawRow, createSkipTracker());
55+
if (!mapped) return 'unmapped' as const;
56+
57+
const metadata = Object.fromEntries(
58+
RUNTIME_KEYS.flatMap((key) =>
59+
mapped.metrics[key] === undefined ? [] : [[key, mapped.metrics[key]]],
60+
),
61+
);
62+
if (Object.keys(metadata).length === 0) return 'empty' as const;
63+
64+
const c = mapped.config;
65+
const updated = await sql<{ id: number }[]>`
66+
update benchmark_results br
67+
set metrics = br.metrics || ${sql.json(metadata)}
68+
from workflow_runs wr, configs cfg
69+
where br.workflow_run_id = wr.id
70+
and br.config_id = cfg.id
71+
and wr.github_run_id = ${githubRunId}
72+
and cfg.hardware = ${c.hardware}
73+
and cfg.framework = ${c.framework}
74+
and cfg.model = ${c.model}
75+
and cfg.precision = ${c.precision}
76+
and cfg.spec_method = ${c.specMethod}
77+
and cfg.disagg = ${c.disagg}
78+
and cfg.is_multinode = ${c.isMultinode}
79+
and cfg.prefill_tp = ${c.prefillTp}
80+
and cfg.prefill_ep = ${c.prefillEp}
81+
and cfg.prefill_dp_attention = ${c.prefillDpAttn}
82+
and cfg.prefill_num_workers = ${c.prefillNumWorkers}
83+
and cfg.decode_tp = ${c.decodeTp}
84+
and cfg.decode_ep = ${c.decodeEp}
85+
and cfg.decode_dp_attention = ${c.decodeDpAttn}
86+
and cfg.decode_num_workers = ${c.decodeNumWorkers}
87+
and cfg.num_prefill_gpu = ${c.numPrefillGpu}
88+
and cfg.num_decode_gpu = ${c.numDecodeGpu}
89+
and br.benchmark_type = ${mapped.benchmarkType}
90+
and br.isl is not distinct from ${mapped.isl}
91+
and br.osl is not distinct from ${mapped.osl}
92+
and br.conc = ${mapped.conc}
93+
and br.offload_mode = ${mapped.offloadMode}
94+
returning br.id
95+
`;
96+
return updated.length > 0 ? ('updated' as const) : ('missing' as const);
97+
}
98+
99+
async function main(): Promise<void> {
100+
console.log('=== backfill-runtime-metadata ===');
101+
const runs = await sql<{ github_run_id: number; html_url: string | null }[]>`
102+
select distinct wr.github_run_id, wr.html_url
103+
from workflow_runs wr
104+
join benchmark_results br on br.workflow_run_id = wr.id
105+
where wr.date >= ${FIRST_METADATA_DATE}::date
106+
order by wr.github_run_id
107+
`;
108+
if (runs.length === 0) {
109+
console.log(' Nothing to do.');
110+
return;
111+
}
112+
if (!(await confirmProceed(`${runs.length} workflow run(s) may contain runtime metadata.`))) {
113+
return;
114+
}
115+
116+
let updated = 0;
117+
let missing = 0;
118+
let empty = 0;
119+
let unmapped = 0;
120+
for (const [index, run] of runs.entries()) {
121+
const runId = Number(run.github_run_id);
122+
const repository = repositoryFromRunUrl(run.html_url) ?? REPO;
123+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `runtime-metadata-${runId}-`));
124+
try {
125+
const artifacts = selectBenchmarkArtifacts(listRunArtifacts(repository, String(runId)));
126+
let files = 0;
127+
for (const artifact of artifacts) {
128+
const artifactDir = downloadArtifact(artifact, tempDir);
129+
for (const file of findJsonFiles(artifactDir)) {
130+
files++;
131+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8')) as unknown;
132+
const rawRows = Array.isArray(parsed) ? parsed : [parsed];
133+
for (const raw of rawRows) {
134+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
135+
const result = await backfillRawRow(runId, raw as Record<string, unknown>);
136+
if (result === 'updated') updated++;
137+
else if (result === 'missing') missing++;
138+
else if (result === 'empty') empty++;
139+
else unmapped++;
140+
}
141+
}
142+
}
143+
console.log(
144+
` [${index + 1}/${runs.length}] ${repository} run ${runId}: ` +
145+
`${artifacts.length} artifact(s), ${files} file(s)`,
146+
);
147+
} finally {
148+
fs.rmSync(tempDir, { recursive: true, force: true });
149+
}
150+
}
151+
152+
await refreshLatestBenchmarks(sql);
153+
console.log(
154+
` Rows: ${updated} updated, ${empty} without runtime metadata, ` +
155+
`${unmapped} unmapped, ${missing} missing DB match`,
156+
);
157+
if (missing > 0) process.exitCode = 1;
158+
}
159+
160+
runBackfillMain('backfill-runtime-metadata', sql, main);

packages/db/src/etl/benchmark-mapper.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ describe('mapBenchmarkRow', () => {
136136

137137
expect((result!.metrics as Record<string, unknown>).kv_p2p_transfer).toBe('nixl');
138138
});
139+
140+
it('flattens router metadata for fixed-sequence rows', () => {
141+
const tracker = createSkipTracker();
142+
const result = mapBenchmarkRow(
143+
makeV1Row({ router: { name: 'sglang-router', version: '0.3.2' } }),
144+
tracker,
145+
);
146+
147+
expect((result!.metrics as Record<string, unknown>).router_name).toBe('sglang-router');
148+
expect((result!.metrics as Record<string, unknown>).router_version).toBe('0.3.2');
149+
});
139150
});
140151

141152
describe('v2 schema', () => {
@@ -882,6 +893,17 @@ describe('mapBenchmarkRow — v3 agentic nested agg schema', () => {
882893
expect(metrics.kv_offload_backend_version).toBe('0.5.1');
883894
});
884895

896+
it('flattens agentic router metadata and preserves its version', () => {
897+
const tracker = createSkipTracker();
898+
const result = mapBenchmarkRow(
899+
makeV3AgenticRow({ router: { name: 'vllm-router', version: '0.1.14' } }),
900+
tracker,
901+
);
902+
const metrics = result!.metrics as Record<string, unknown>;
903+
expect(metrics.router_name).toBe('vllm-router');
904+
expect(metrics.router_version).toBe('0.1.14');
905+
});
906+
885907
it('still applies the failed-run guard to v3 rows', () => {
886908
const tracker = createSkipTracker();
887909
const result = mapBenchmarkRow(

0 commit comments

Comments
 (0)