Skip to content

Commit bd4ca47

Browse files
committed
refactor: share benchmark loading and series dedupe
中文:共享基准测试加载与序列去重逻辑。
1 parent ae7c94f commit bd4ca47

6 files changed

Lines changed: 122 additions & 138 deletions

File tree

packages/app/src/components/inference/hooks/useChartData.test.ts

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,6 @@
11
import { describe, it, expect } from 'vitest';
22

3-
import {
4-
buildComparisonDates,
5-
dedupeRowsToLatestPerConfig,
6-
filterByGPU,
7-
flipRooflineDirection,
8-
} from './useChartData';
9-
10-
interface DedupeInput {
11-
id: number;
12-
hardware: string;
13-
framework: string;
14-
spec_method: string;
15-
disagg: boolean;
16-
precision: string;
17-
offload_mode?: string | null;
18-
date: string;
19-
}
20-
21-
const drow = (over: Partial<DedupeInput> = {}): DedupeInput => ({
22-
id: 1,
23-
hardware: 'b300',
24-
framework: 'vllm',
25-
spec_method: 'none',
26-
disagg: false,
27-
precision: 'fp4',
28-
offload_mode: 'off',
29-
date: '2026-06-01',
30-
...over,
31-
});
32-
33-
describe('dedupeRowsToLatestPerConfig', () => {
34-
it('keeps only the latest date within a single series', () => {
35-
const rows = [
36-
drow({ id: 1, date: '2026-06-01' }),
37-
drow({ id: 2, date: '2026-06-03' }),
38-
drow({ id: 3, date: '2026-06-02' }),
39-
];
40-
expect(dedupeRowsToLatestPerConfig(rows).map((r) => r.id)).toEqual([2]);
41-
});
42-
43-
it('keeps BOTH offload variants even when they were ingested on different dates', () => {
44-
// The regression: offload=on sweep landed LATER than offload=off. Without
45-
// offload in the key, the on-variant's newer date would win the shared group
46-
// and silently drop the (older) off-variant series entirely.
47-
const rows = [
48-
drow({ id: 1, offload_mode: 'off', date: '2026-06-01' }),
49-
drow({ id: 2, offload_mode: 'on', date: '2026-06-05' }),
50-
];
51-
const kept = dedupeRowsToLatestPerConfig(rows)
52-
.map((r) => r.offload_mode)
53-
.toSorted();
54-
expect(kept).toEqual(['off', 'on']);
55-
});
56-
57-
it('still dedupes each offload variant to its own latest date', () => {
58-
const rows = [
59-
drow({ id: 1, offload_mode: 'off', date: '2026-06-01' }),
60-
drow({ id: 2, offload_mode: 'off', date: '2026-06-04' }),
61-
drow({ id: 3, offload_mode: 'on', date: '2026-06-02' }),
62-
drow({ id: 4, offload_mode: 'on', date: '2026-06-05' }),
63-
];
64-
expect(
65-
dedupeRowsToLatestPerConfig(rows)
66-
.map((r) => r.id)
67-
.toSorted(),
68-
).toEqual([2, 4]);
69-
});
70-
71-
it('normalizes a missing offload_mode to "off" (matches the SQL lineKey)', () => {
72-
// A row with no offload_mode collides with an explicit offload=off row of the
73-
// same config — both are the "off" series, so latest-date dedup applies.
74-
const rows = [
75-
drow({ id: 1, offload_mode: undefined, date: '2026-06-01' }),
76-
drow({ id: 2, offload_mode: 'off', date: '2026-06-03' }),
77-
];
78-
expect(dedupeRowsToLatestPerConfig(rows).map((r) => r.id)).toEqual([2]);
79-
});
80-
});
3+
import { buildComparisonDates, filterByGPU, flipRooflineDirection } from './useChartData';
814

825
describe('buildComparisonDates', () => {
836
it('returns empty when no GPUs selected (comparison disabled)', () => {

packages/app/src/components/inference/hooks/useChartData.ts

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
getModelSortIndex,
2424
hardwareKeyMatchesAnyBase,
2525
} from '@/lib/constants';
26+
import { dedupeRowsToLatestPerConfig } from '@/lib/benchmark-series';
2627
import { mergeRunScopedRows, transformBenchmarkRows } from '@/lib/benchmark-transform';
2728
import { Sequence, type Model } from '@/lib/data-mappings';
2829
import { isPersistedBenchmarkId } from '@/lib/benchmark-id';
@@ -139,42 +140,6 @@ export function flipRooflineDirection(dir: RooflineDirection): RooflineDirection
139140
return FLIP_MAP[dir];
140141
}
141142

142-
/** The dedup key fields a chart series is identified by. */
143-
interface DedupeRow {
144-
hardware: string;
145-
framework: string;
146-
spec_method: string;
147-
disagg: boolean;
148-
precision: string;
149-
offload_mode?: string | null;
150-
date: string;
151-
}
152-
153-
// offload_mode normalized `?? 'off'` to match the SQL layer's getBenchmarksForRun
154-
// lineKey — agentic offload=on and offload=off are distinct series.
155-
const dedupeSeriesKey = (r: DedupeRow): string =>
156-
`${r.hardware}|${r.framework}|${r.spec_method}|${r.disagg}|${r.precision}|${r.offload_mode ?? 'off'}`;
157-
158-
/**
159-
* For each series — (hardware, framework, spec_method, disagg, precision,
160-
* offload_mode) — keep only the rows from that series' most recent date. When
161-
* parallelism settings change between runs, old config_ids create stale points
162-
* under the same legend line; dropping all-but-latest removes them.
163-
*
164-
* Without `offload_mode` in the key, an offload=on sweep ingested on a LATER date
165-
* than the offload=off sweep would win the shared group and silently drop the
166-
* (earlier-dated) offload=off variant — a data-loss regression.
167-
*/
168-
export function dedupeRowsToLatestPerConfig<T extends DedupeRow>(rows: T[]): T[] {
169-
const maxDatePerGroup = new Map<string, string>();
170-
for (const r of rows) {
171-
const k = dedupeSeriesKey(r);
172-
const cur = maxDatePerGroup.get(k);
173-
if (!cur || r.date > cur) maxDatePerGroup.set(k, r.date);
174-
}
175-
return rows.filter((r) => r.date === maxDatePerGroup.get(dedupeSeriesKey(r)));
176-
}
177-
178143
export function useChartData(
179144
selectedModel: Model,
180145
selectedSequence: Sequence,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { FIXTURES_MODE, getDb } from '@semianalysisai/inferencex-db/connection';
2+
import {
3+
type BenchmarkRow,
4+
getLatestBenchmarks,
5+
} from '@semianalysisai/inferencex-db/queries/benchmarks';
6+
7+
import { cachedQuery } from '@/lib/api-cache';
8+
import { loadFixture } from '@/lib/test-fixtures';
9+
10+
export const getCachedBenchmarks = cachedQuery(
11+
(dbModelKeys: string[]) => {
12+
if (FIXTURES_MODE) return Promise.resolve(loadFixture<BenchmarkRow[]>('benchmarks'));
13+
14+
return getLatestBenchmarks(getDb(), dbModelKeys);
15+
},
16+
'benchmarks',
17+
{ blobOnly: true },
18+
);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { dedupeRowsToLatestPerConfig } from './benchmark-series';
4+
5+
interface DedupeInput {
6+
id: number;
7+
hardware: string;
8+
framework: string;
9+
spec_method: string;
10+
disagg: boolean;
11+
precision: string;
12+
offload_mode?: string | null;
13+
date: string;
14+
}
15+
16+
const drow = (over: Partial<DedupeInput> = {}): DedupeInput => ({
17+
id: 1,
18+
hardware: 'b300',
19+
framework: 'vllm',
20+
spec_method: 'none',
21+
disagg: false,
22+
precision: 'fp4',
23+
offload_mode: 'off',
24+
date: '2026-06-01',
25+
...over,
26+
});
27+
28+
describe('dedupeRowsToLatestPerConfig', () => {
29+
it('keeps only the latest date within a single series', () => {
30+
const rows = [
31+
drow({ id: 1, date: '2026-06-01' }),
32+
drow({ id: 2, date: '2026-06-03' }),
33+
drow({ id: 3, date: '2026-06-02' }),
34+
];
35+
expect(dedupeRowsToLatestPerConfig(rows).map((r) => r.id)).toEqual([2]);
36+
});
37+
38+
it('keeps BOTH offload variants even when they were ingested on different dates', () => {
39+
// The regression: offload=on sweep landed LATER than offload=off. Without
40+
// offload in the key, the on-variant's newer date would win the shared group
41+
// and silently drop the (older) off-variant series entirely.
42+
const rows = [
43+
drow({ id: 1, offload_mode: 'off', date: '2026-06-01' }),
44+
drow({ id: 2, offload_mode: 'on', date: '2026-06-05' }),
45+
];
46+
const keptOffloadModes = dedupeRowsToLatestPerConfig(rows)
47+
.map((r) => r.offload_mode)
48+
.toSorted();
49+
expect(keptOffloadModes).toEqual(['off', 'on']);
50+
});
51+
52+
it('still dedupes each offload variant to its own latest date', () => {
53+
const rows = [
54+
drow({ id: 1, offload_mode: 'off', date: '2026-06-01' }),
55+
drow({ id: 2, offload_mode: 'off', date: '2026-06-04' }),
56+
drow({ id: 3, offload_mode: 'on', date: '2026-06-02' }),
57+
drow({ id: 4, offload_mode: 'on', date: '2026-06-05' }),
58+
];
59+
const keptIds = dedupeRowsToLatestPerConfig(rows)
60+
.map((r) => r.id)
61+
.toSorted();
62+
expect(keptIds).toEqual([2, 4]);
63+
});
64+
65+
it('normalizes a missing offload_mode to "off" (matches the SQL lineKey)', () => {
66+
// A row with no offload_mode collides with an explicit offload=off row of the
67+
// same config — both are the "off" series, so latest-date dedup applies.
68+
const rows = [
69+
drow({ id: 1, offload_mode: undefined, date: '2026-06-01' }),
70+
drow({ id: 2, offload_mode: 'off', date: '2026-06-03' }),
71+
];
72+
const missingOffloadNormalizedToOff = dedupeRowsToLatestPerConfig(rows).map((r) => r.id);
73+
expect(missingOffloadNormalizedToOff).toEqual([2]);
74+
});
75+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export interface BenchmarkSeriesRow {
2+
hardware: string;
3+
framework: string;
4+
spec_method: string;
5+
disagg: boolean;
6+
precision: string;
7+
offload_mode?: string | null;
8+
date: string;
9+
}
10+
11+
const benchmarkSeriesKey = (row: BenchmarkSeriesRow): string =>
12+
`${row.hardware}|${row.framework}|${row.spec_method}|${row.disagg}|${row.precision}|${row.offload_mode ?? 'off'}`;
13+
14+
/** Keep only the rows from each benchmark series' most recent date. */
15+
export function dedupeRowsToLatestPerConfig<T extends BenchmarkSeriesRow>(rows: T[]): T[] {
16+
const maxDatePerSeries = new Map<string, string>();
17+
for (const row of rows) {
18+
const key = benchmarkSeriesKey(row);
19+
const maxDate = maxDatePerSeries.get(key);
20+
if (!maxDate || row.date > maxDate) maxDatePerSeries.set(key, row.date);
21+
}
22+
23+
return rows.filter((row) => row.date === maxDatePerSeries.get(benchmarkSeriesKey(row)));
24+
}

packages/app/src/lib/compare-ssr.ts

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,11 @@ import {
1818
SITE_URL,
1919
sequenceToIslOsl,
2020
} from '@semianalysisai/inferencex-constants';
21-
import { FIXTURES_MODE, getDb } from '@semianalysisai/inferencex-db/connection';
22-
23-
import {
24-
type BenchmarkRow,
25-
getLatestBenchmarks,
26-
} from '@semianalysisai/inferencex-db/queries/benchmarks';
21+
import type { BenchmarkRow } from '@semianalysisai/inferencex-db/queries/benchmarks';
2722

2823
import { interpolateForGPU } from '@/components/calculator/interpolation';
2924
import type { GPUDataPoint, InterpolatedResult } from '@/components/calculator/types';
30-
import { cachedQuery } from '@/lib/api-cache';
25+
import { getCachedBenchmarks } from '@/lib/benchmark-data.server';
3126
import { rowToAggDataEntry } from '@/lib/benchmark-transform';
3227
import { getHardwareKey } from '@/lib/chart-utils';
3328
import {
@@ -39,24 +34,8 @@ import {
3934
compareModelSeoName,
4035
} from '@/lib/compare-slug';
4136
import { getHardwareConfig, getGpuSpecs } from '@/lib/constants';
42-
import { loadFixture } from '@/lib/test-fixtures';
43-
44-
// ---------------------------------------------------------------------------
45-
// Cached benchmark fetch
46-
// ---------------------------------------------------------------------------
4737

48-
/** Cache slot is keyed on the dbKeys array. Both `/compare/<slug>` and
49-
* `/compare-per-dollar/<slug>` for the same model hit the same blob entry —
50-
* the per-dollar route doesn't duplicate the fetch or the cache. */
51-
export const getCachedBenchmarks = cachedQuery(
52-
(dbModelKeys: string[]) => {
53-
if (FIXTURES_MODE) return Promise.resolve(loadFixture<BenchmarkRow[]>('benchmarks'));
54-
55-
return getLatestBenchmarks(getDb(), dbModelKeys);
56-
},
57-
'benchmarks',
58-
{ blobOnly: true },
59-
);
38+
export { getCachedBenchmarks };
6039

6140
// ---------------------------------------------------------------------------
6241
// URL-param validators (shared by both routes' overrides)

0 commit comments

Comments
 (0)