Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions packages/app/src/app/api/unofficial-run/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ export function normalizeArtifactRows(
const params = mapBenchmarkRow(raw as Record<string, any>, tracker);
if (!params) continue;
const { config } = params;
const specMethod =
typeof params.techniques.spec_method === 'string' ? params.techniques.spec_method : 'none';
results.push({
hardware: config.hardware,
framework: config.framework,
model: config.model,
precision: config.precision,
spec_method: config.specMethod,
spec_method: specMethod,
techniques: params.techniques,
disagg: config.disagg,
is_multinode: config.isMultinode,
prefill_tp: config.prefillTp,
Expand All @@ -62,13 +65,17 @@ export function normalizeArtifactRows(
return results;
}

function evalConfigKey(config: EvalParams['config']): string {
function evalConfigKey(
config: EvalParams['config'],
techniques: Record<string, string | number>,
): string {
return [
config.hardware,
config.framework,
config.model,
config.precision,
config.specMethod,
typeof techniques.spec_method === 'string' ? techniques.spec_method : 'none',
typeof techniques.mtp_layers === 'number' ? String(techniques.mtp_layers) : 'none',
config.disagg ? '1' : '0',
config.prefillTp,
config.prefillEp,
Expand Down Expand Up @@ -107,14 +114,17 @@ export function normalizeEvalArtifactRows(
const params = mapAggEvalRow(raw as Record<string, any>, tracker);
if (!params) continue;

const key = evalConfigKey(params.config);
const key = evalConfigKey(params.config, params.techniques);
let localId = configIds.get(key);
if (!localId) {
localId = nextLocalId;
configIds.set(key, localId);
nextLocalId += 1;
}

const specMethod =
typeof params.techniques.spec_method === 'string' ? params.techniques.spec_method : 'none';

rows.push({
// Synthetic id — unofficial rows are never persisted to eval_results, so
// there's no real PK to surface. -1 signals "no DB-side row" to the
Expand All @@ -125,7 +135,8 @@ export function normalizeEvalArtifactRows(
framework: params.config.framework,
model: params.config.model,
precision: params.config.precision,
spec_method: params.config.specMethod,
spec_method: specMethod,
techniques: params.techniques,
disagg: params.config.disagg,
is_multinode: params.config.isMultinode,
prefill_tp: params.config.prefillTp,
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/components/evaluation/chart-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function evalRow(overrides: Partial<EvalRow> = {}): EvalRow {
model: 'dsr1',
precision: 'fp8',
spec_method: 'none',
techniques: {},
disagg: false,
is_multinode: false,
prefill_tp: 8,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function stubRow(overrides: Partial<BenchmarkRow> = {}): BenchmarkRow {
model: 'dsr1',
precision: 'fp8',
spec_method: 'none',
techniques: {},
disagg: false,
is_multinode: false,
prefill_tp: 8,
Expand Down
4 changes: 4 additions & 0 deletions packages/app/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export interface BenchmarkRow {
framework: string;
model: string;
precision: string;
/** Derived from techniques.spec_method by the API; 'none' when absent. */
spec_method: string;
techniques: Record<string, string | number>;
disagg: boolean;
is_multinode: boolean;
prefill_tp: number;
Expand Down Expand Up @@ -83,7 +85,9 @@ export interface EvalRow {
framework: string;
model: string;
precision: string;
/** Derived from techniques.spec_method by the API; 'none' when absent. */
spec_method: string;
techniques: Record<string, string | number>;
disagg: boolean;
is_multinode: boolean;
prefill_tp: number;
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/lib/benchmark-transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function makeRow(overrides: Partial<BenchmarkRow> = {}): BenchmarkRow {
model: 'dsr1',
precision: 'fp8',
spec_method: 'none',
techniques: {},
disagg: false,
is_multinode: false,
prefill_tp: 8,
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/lib/compare-pair-defaults.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function makeRow(overrides: Partial<BenchmarkRow>): BenchmarkRow {
model: 'dsr1',
precision: 'fp8',
spec_method: 'none',
techniques: {},
disagg: false,
is_multinode: false,
prefill_tp: 1,
Expand Down
8 changes: 8 additions & 0 deletions packages/constants/src/metric-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,12 @@ export const METRIC_KEYS = new Set([
'p99_intvty',
'p99.9_intvty',
'std_intvty',
// speculative-decoding acceptance — fraction of draft tokens accepted [0,1]
'median_acceptance_rate',
'mean_acceptance_rate',
'p99_acceptance_rate',
// speculative-decoding tokens per forward step — 1.0 when spec-dec is off
'median_tokens_per_step',
'mean_tokens_per_step',
'p99_tokens_per_step',
]);
1 change: 1 addition & 0 deletions packages/constants/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const DB_MODEL_TO_DISPLAY: Record<string, string> = {
glm5: 'GLM-5',
'glm5.1': 'GLM-5',
dsv4: 'DeepSeek-V4-Pro',
gemma4: 'Gemma-4-31B-it',
};

/**
Expand Down
72 changes: 72 additions & 0 deletions packages/db/migrations/006_skinny_configs.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
-- ============================================================
-- Migration 006 — skinny configs, techniques per measurement
-- ============================================================
--
-- Demotes spec_method from a config dimension to a measurement-level
-- "technique flag" stored in a jsonb bag. Same shape will absorb any future
-- runtime knob (mtp_layers, kv_cache_dtype, chunked_prefill, prefix_cache, …)
-- without further DDL — each lands as a key in techniques.
--
-- configs now describes the DEPLOYMENT (model, hw, framework, precision,
-- parallelism). techniques describes HOW THE RECIPE WAS TUNED for that run.
--
-- Full-rewrite migration: data tables are TRUNCATEd and re-ingested from
-- artifacts. Safe because ingest is idempotent and (for vngcloud fork) very
-- little production data exists.

-- 1. Drop spec_method from configs
alter table configs drop constraint configs_natural_key;
alter table configs drop constraint configs_spec_method_lowercase;
alter table configs drop column spec_method;
alter table configs add constraint configs_natural_key unique (
hardware, framework, model, precision,
disagg, is_multinode,
prefill_tp, prefill_ep, prefill_dp_attention, prefill_num_workers,
decode_tp, decode_ep, decode_dp_attention, decode_num_workers,
num_prefill_gpu, num_decode_gpu
);

-- 2. Add techniques jsonb on the two measurement tables
alter table benchmark_results add column techniques jsonb not null default '{}'::jsonb;
alter table eval_results add column techniques jsonb not null default '{}'::jsonb;

-- 3. Expression indexes on the two hot technique keys
create index benchmark_results_spec_method_idx
on benchmark_results ((techniques->>'spec_method')) where error is null;
create index benchmark_results_mtp_layers_idx
on benchmark_results ((techniques->>'mtp_layers')) where error is null;

-- 4. Rebuild latest_benchmarks MV with techniques as part of row identity.
-- Without this, two formerly-different configs (same hw/fw/precision but
-- different spec_method) now share one config_id and would collide on the
-- MV's unique PK at (config_id, conc, isl, osl).
drop materialized view latest_benchmarks;

create materialized view latest_benchmarks as
select distinct on (br.config_id, br.conc, br.isl, br.osl, br.techniques)
br.*
from benchmark_results br
join latest_workflow_runs wr on wr.id = br.workflow_run_id
where br.error is null
order by br.config_id, br.conc, br.isl, br.osl, br.techniques,
br.date desc, wr.run_started_at desc nulls last;

create unique index latest_benchmarks_pk
on latest_benchmarks (config_id, conc, isl, osl, techniques);
create index latest_benchmarks_model_idx on latest_benchmarks (config_id);

-- 5. Rebuild the seq-history covering index to include techniques so
-- historical-trends queries can still get an index-only scan when grouping
-- by technique.
drop index if exists benchmark_results_seq_history_idx;
create index benchmark_results_seq_history_idx
on benchmark_results (isl, osl, date, config_id, conc, techniques)
include (image, metrics)
where error is null;

-- 6. Full-rewrite TRUNCATE. Re-ingest from artifacts after deploy.
-- configs is also truncated because its natural key changed shape.
truncate benchmark_results, eval_results, eval_samples, run_stats,
availability, changelog_entries, server_logs, workflow_runs
restart identity cascade;
truncate configs restart identity cascade;
10 changes: 7 additions & 3 deletions packages/db/src/apply-overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,13 @@ async function purge(wrIds: number[]): Promise<void> {
await sql.begin(async (_tx) => {
const tx = _tx as unknown as Sql;

// Capture availability keys + server_log_ids before deleting benchmarks
// Capture availability keys + server_log_ids before deleting benchmarks.
// spec_method is now a measurement-level technique flag (see migration 006).
const availKeys = await tx`
SELECT DISTINCT c.model, br.isl, br.osl, c.precision, c.hardware,
c.framework, c.spec_method, c.disagg, br.date::text AS date
c.framework,
COALESCE(br.techniques->>'spec_method', 'none') AS spec_method,
c.disagg, br.date::text AS date
FROM benchmark_results br
JOIN configs c ON c.id = br.config_id
WHERE br.workflow_run_id = ANY(${wrIds})
Expand Down Expand Up @@ -210,7 +213,8 @@ async function purge(wrIds: number[]): Promise<void> {
JOIN configs c ON c.id = br.config_id
WHERE c.model = a.model AND br.isl = a.isl AND br.osl = a.osl
AND c.precision = a.precision AND c.hardware = a.hardware
AND c.framework = a.framework AND c.spec_method = a.spec_method
AND c.framework = a.framework
AND COALESCE(br.techniques->>'spec_method', 'none') = a.spec_method
AND c.disagg = a.disagg AND br.date = a.date AND br.error IS NULL
)
`;
Expand Down
24 changes: 18 additions & 6 deletions packages/db/src/etl/benchmark-ingest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ export async function bulkIngestBenchmarkRows(
const concs = deduped.map((r) => r.conc);
const images = deduped.map((r) => r.image);
const metricsJsons = deduped.map((r) => JSON.stringify(r.metrics));
const techniquesJsons = deduped.map((r) => JSON.stringify(r.techniques));

const result = await sql<{ inserted: boolean; id: number }[]>`
insert into benchmark_results (
workflow_run_id, config_id, benchmark_type, date,
isl, osl, conc, image, metrics
isl, osl, conc, image, metrics, techniques
)
select
${workflowRunId},
Expand All @@ -55,11 +56,13 @@ export async function bulkIngestBenchmarkRows(
unnest(${sql.array(osls)}::int[]),
unnest(${sql.array(concs)}::int[]),
unnest(${sql.array(images)}),
unnest(${sql.array(metricsJsons)}::jsonb[])
unnest(${sql.array(metricsJsons)}::jsonb[]),
unnest(${sql.array(techniquesJsons)}::jsonb[])
on conflict (workflow_run_id, config_id, benchmark_type, isl, osl, conc)
do update set
metrics = excluded.metrics,
image = excluded.image
image = excluded.image,
techniques = excluded.techniques
returning (xmax = 0) as inserted, id
`;

Expand Down Expand Up @@ -143,6 +146,14 @@ export async function bulkIngestRunStats(
* Rows are deduplicated within the batch before sending. ON CONFLICT DO NOTHING
* makes re-runs idempotent.
*/
/**
* availability.spec_method is a denormalized projection of techniques.spec_method
* (kept for filter ergonomics on the date picker). Default to 'none' when absent.
*/
function specMethodFor(t: Record<string, string | number>): string {
return typeof t.spec_method === 'string' ? t.spec_method : 'none';
}

export async function bulkUpsertAvailability(
sql: Sql,
rows: {
Expand All @@ -152,7 +163,7 @@ export async function bulkUpsertAvailability(
precision: string;
hardware: string;
framework: string;
specMethod: string;
techniques: Record<string, string | number>;
disagg: boolean;
}[],
date: string,
Expand All @@ -162,7 +173,8 @@ export async function bulkUpsertAvailability(
const seen = new Set<string>();
const unique: typeof rows = [];
for (const r of rows) {
const key = `${r.model}|${r.isl}|${r.osl}|${r.precision}|${r.hardware}|${r.framework}|${r.specMethod}|${r.disagg}|${date}`;
const sm = specMethodFor(r.techniques);
const key = `${r.model}|${r.isl}|${r.osl}|${r.precision}|${r.hardware}|${r.framework}|${sm}|${r.disagg}|${date}`;
if (!seen.has(key)) {
seen.add(key);
unique.push(r);
Expand All @@ -178,7 +190,7 @@ export async function bulkUpsertAvailability(
unnest(${sql.array(unique.map((r) => r.precision))}::text[]),
unnest(${sql.array(unique.map((r) => r.hardware))}::text[]),
unnest(${sql.array(unique.map((r) => r.framework))}::text[]),
unnest(${sql.array(unique.map((r) => r.specMethod))}::text[]),
unnest(${sql.array(unique.map((r) => specMethodFor(r.techniques)))}::text[]),
unnest(${sql.array(unique.map((r) => r.disagg))}::bool[]),
${date}::date
on conflict do nothing
Expand Down
35 changes: 27 additions & 8 deletions packages/db/src/etl/benchmark-mapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('mapBenchmarkRow', () => {
expect(result!.config.framework).toBe('vllm');
expect(result!.config.model).toBe('dsr1');
expect(result!.config.precision).toBe('fp8');
expect(result!.config.specMethod).toBe('none');
expect(result!.techniques).toEqual({});
expect(result!.config.disagg).toBe(false);
expect(result!.config.isMultinode).toBe(false);
expect(result!.isl).toBe(1024);
Expand Down Expand Up @@ -286,11 +286,11 @@ describe('mapBenchmarkRow', () => {
expect(result!.config.disagg).toBe(true);
});

it('handles spec_decoding=mtp', () => {
it('handles spec_decoding=mtp (legacy field → techniques.spec_method)', () => {
const tracker = createSkipTracker();
const result = mapBenchmarkRow(makeV1Row({ spec_decoding: 'mtp' }), tracker);

expect(result!.config.specMethod).toBe('mtp');
expect(result!.techniques.spec_method).toBe('mtp');
});
});

Expand Down Expand Up @@ -331,19 +331,38 @@ describe('mapBenchmarkRow', () => {
});
});

describe('spec_decoding', () => {
it('normalizes spec_decoding to lowercase', () => {
describe('techniques (spec_decoding legacy + new shape)', () => {
it('normalizes legacy spec_decoding to lowercase under techniques.spec_method', () => {
const tracker = createSkipTracker();
const result = mapBenchmarkRow(makeV1Row({ spec_decoding: 'Eagle' }), tracker);

expect(result!.config.specMethod).toBe('eagle');
expect(result!.techniques.spec_method).toBe('eagle');
});

it('defaults to none when absent', () => {
it('omits spec_method when absent (techniques bag stays empty)', () => {
const tracker = createSkipTracker();
const result = mapBenchmarkRow(makeV1Row(), tracker);

expect(result!.config.specMethod).toBe('none');
expect(result!.techniques).toEqual({});
});

it('reads new-shape techniques object directly', () => {
const tracker = createSkipTracker();
const result = mapBenchmarkRow(
makeV1Row({ techniques: { spec_method: 'mtp', mtp_layers: 4 } }),
tracker,
);

expect(result!.techniques).toEqual({ spec_method: 'mtp', mtp_layers: 4 });
});

it('infers mtp_layers from gemma4n4/gemma4n6 model prefix (legacy)', () => {
const tracker = createSkipTracker();
const result = mapBenchmarkRow(makeV1Row({ infmax_model_prefix: 'gemma4n6' }), tracker);

expect(result!.config.model).toBe('gemma4');
expect(result!.techniques.mtp_layers).toBe(6);
expect(result!.techniques.spec_method).toBe('mtp');
});
});

Expand Down
Loading
Loading