Skip to content
Open
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
2 changes: 1 addition & 1 deletion web/lib/benchmark-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('groupDocPath', () => {
expect(groupDocPath({ k: 'CompressionTimeGroup' })).toBe('benchmarks/compress-bench/README.md');
// Two measurement kinds of one benchmark, so one doc.
expect(groupDocPath({ k: 'CompressionSizeGroup' })).toBe('benchmarks/compress-bench/README.md');
expect(groupDocPath({ k: 'RandomAccessGroup' })).toBe(
expect(groupDocPath({ k: 'RandomAccessGroup', storage: 'nvme' })).toBe(
'benchmarks/random-access-bench/README.md',
);
});
Expand Down
4 changes: 2 additions & 2 deletions web/lib/data-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ describe('data-cache wrappers', () => {
expect(BENCH_DATA_TAG).toBe('bench-data');
expect(DATA_CACHE_BACKSTOP_SECONDS).toBe(86400);
expect(cacheCalls.map((call) => call.keyParts)).toContainEqual([
'data-cache:group-charts:v8:n100',
'data-cache:group-charts:v9:n100',
]);
expect(cacheCalls.map((call) => call.keyParts)).toContainEqual(['data-cache:groups:v8']);
expect(cacheCalls.map((call) => call.keyParts)).toContainEqual(['data-cache:groups:v9']);
for (const call of cacheCalls) {
expect(call.options.tags).toEqual([BENCH_DATA_TAG]);
expect(call.options.revalidate).toBe(DATA_CACHE_BACKSTOP_SECONDS);
Expand Down
2 changes: 1 addition & 1 deletion web/lib/data-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const CACHE_OPTIONS = { tags: [BENCH_DATA_TAG], revalidate: DATA_CACHE_BACKSTOP_
* This value must change when a deployment cannot read the preceding shape.
* It is independent of the producer-facing benchmark schema version.
*/
const GROUP_PAYLOAD_CACHE_VERSION = 'v8';
const GROUP_PAYLOAD_CACHE_VERSION = 'v9';

// The default last-100 group bundle, keyed by group slug. The slug is the cache
// key (an `unstable_cache` argument), so one wrapper covers every group. A
Expand Down
6 changes: 6 additions & 0 deletions web/lib/descriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { groupDescription } from './descriptions';
// Pure string logic, so these run without Docker. They mirror the Rust
// `descriptions.rs` unit tests verbatim (the v2 contract).
describe('groupDescription', () => {
it.each(['NVMe', 'S3'])('describes random access on %s', (storage) => {
expect(groupDescription(`Random Access (${storage})`)).toBe(
`Tests performance of selecting arbitrary row indices from a file on ${storage} storage`,
);
});

it('returns the v2 static descriptions verbatim', () => {
expect(groupDescription('Random Access')).toBe(
'Tests performance of selecting arbitrary row indices from a file on NVMe storage',
Expand Down
3 changes: 3 additions & 0 deletions web/lib/descriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export function groupDescription(name: string): string | null {
function staticDescription(name: string): string | null {
switch (name) {
case 'Random Access':
case 'Random Access (NVMe)':
return 'Tests performance of selecting arbitrary row indices from a file on NVMe storage';
case 'Random Access (S3)':
return 'Tests performance of selecting arbitrary row indices from a file on S3 storage';
case 'Compression':
return 'Measures write and scan throughput for Vortex, Parquet, and Lance files';
case 'Compression Size':
Expand Down
69 changes: 59 additions & 10 deletions web/lib/groups.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ describe.skipIf(!dockerAvailable())(

it('orders groups by the canonical GROUP_ORDER, with unknown groups last', async () => {
const groups = await collectGroups();
// `Random Access` is directly before Clickbench in GROUP_ORDER.
// Random-access sections precede Clickbench in GROUP_ORDER.
expect(groups.map((g) => g.name)).toEqual([
'Compression',
'Compression Size',
'Random Access',
'Random Access (NVMe)',
'TPC-H (NVMe) (SF=1)',
'cohere-large-10m / partitioned',
]);
Expand All @@ -77,7 +77,7 @@ describe.skipIf(!dockerAvailable())(
it('computes the random-access summary (geomean ratio to fastest)', async () => {
const groups = await collectGroups();
const summary = expectDefined(
groups.find((g) => g.name === 'Random Access')?.summary,
groups.find((g) => g.name === 'Random Access (NVMe)')?.summary,
'random access summary',
);
if (summary.type !== 'randomAccess') {
Expand Down Expand Up @@ -210,7 +210,7 @@ describe.skipIf(!dockerAvailable())(

it('attaches editorial descriptions and omits them where v2 has none', async () => {
const groups = await collectGroups();
expect(groups.find((g) => g.name === 'Random Access')?.description).toBe(
expect(groups.find((g) => g.name === 'Random Access (NVMe)')?.description).toBe(
'Tests performance of selecting arbitrary row indices from a file on NVMe storage',
);
expect(groups.find((g) => g.name === 'TPC-H (NVMe) (SF=1)')?.description).toBe(
Expand All @@ -234,7 +234,7 @@ describe.skipIf(!dockerAvailable())(
expect(body.groups.map((g) => g.name)).toEqual([
'Compression',
'Compression Size',
'Random Access',
'Random Access (NVMe)',
'TPC-H (NVMe) (SF=1)',
'cohere-large-10m / partitioned',
]);
Expand Down Expand Up @@ -325,7 +325,7 @@ describe.skipIf(!dockerAvailable())(
const pool = getPool();
await pool.query("DELETE FROM random_access_times WHERE open_mode = 'reopen'");

const summary = await collectGroupSummary({ k: 'RandomAccessGroup' });
const summary = await collectGroupSummary({ k: 'RandomAccessGroup', storage: 'nvme' });
if (summary === null || summary.type !== 'randomAccess') {
throw new Error('expected a randomAccess summary');
}
Expand All @@ -337,7 +337,10 @@ describe.skipIf(!dockerAvailable())(
expect(summary.coldRankings).toEqual([]);

const group = expectDefined(
await collectGroupCharts({ k: 'RandomAccessGroup' }, parseCommitWindow(null)),
await collectGroupCharts(
{ k: 'RandomAccessGroup', storage: 'nvme' },
parseCommitWindow(null),
),
'cached-only random access group',
);
expect(Object.keys(group.charts[0].series).sort()).toEqual([
Expand Down Expand Up @@ -463,6 +466,52 @@ describe.skipIf(!dockerAvailable())('summary math fidelity (testcontainers Postg
);
}

it('splits random-access groups, summaries, and chart bundles by storage', async () => {
const sha = 'a'.repeat(40);
await insertCommit(sha, '2026-04-23T12:00:00Z');
for (const dataset of ['taxi', 'taxi/uniform', 'taxi-s3', 'taxi-s3/uniform']) {
await insertRandomAccess(sha, dataset, 'vortex', 100);
}

const groups = await collectGroups();
expect(groups.map((group) => group.name)).toEqual([
'Random Access (NVMe)',
'Random Access (S3)',
]);
for (const [index, storage] of (['nvme', 's3'] as const).entries()) {
const datasets =
storage === 'nvme' ? ['taxi', 'taxi/uniform'] : ['taxi-s3', 'taxi-s3/uniform'];
expect(groupKeyFromSlug(groups[index].slug)).toEqual({ k: 'RandomAccessGroup', storage });
expect(groups[index].charts).toEqual(
datasets.map((dataset) => ({
name: dataset,
slug: chartKeyToSlug({ k: 'RandomAccess', dataset }),
})),
);
const bundle = await collectGroupCharts(
{ k: 'RandomAccessGroup', storage },
parseCommitWindow(null),
);
expect(bundle?.charts.map((chart) => chart.display_name)).toEqual(datasets);
expect(bundle?.summary).toMatchObject({
type: 'randomAccess',
hotRankings: [{ name: 'vortex', totalRuntime: 200, measured: 1, total: 1 }],
coldRankings: [],
});
}

await getPool().query(
"DELETE FROM random_access_times WHERE dataset IN ('taxi', 'taxi/uniform')",
);
expect((await collectGroups()).map((group) => group.name)).toEqual(['Random Access (S3)']);
expect(
await collectGroupCharts(
{ k: 'RandomAccessGroup', storage: 'nvme' },
parseCommitWindow(null),
),
).toBeNull();
});

it('ranks random access over every chart, not the alphabetically first one', async () => {
// The bug this pins: the old summary walked the group's chart links and
// published the first populated chart's raw times under the group-wide
Expand All @@ -484,7 +533,7 @@ describe.skipIf(!dockerAvailable())('summary math fidelity (testcontainers Postg
await insertRandomAccess(sha, 'taxi', 'vortex-file-compressed', 1_000_000);

const summary = expectDefined(
await collectGroupSummary({ k: 'RandomAccessGroup' }),
await collectGroupSummary({ k: 'RandomAccessGroup', storage: 'nvme' }),
'random-access summary',
);
if (summary.type !== 'randomAccess') {
Expand Down Expand Up @@ -512,7 +561,7 @@ describe.skipIf(!dockerAvailable())('summary math fidelity (testcontainers Postg
await insertRandomAccess(newer, 'taxi', 'vortex-file-compressed', 1_000_000);

const summary = expectDefined(
await collectGroupSummary({ k: 'RandomAccessGroup' }),
await collectGroupSummary({ k: 'RandomAccessGroup', storage: 'nvme' }),
'random-access summary',
);
if (summary.type !== 'randomAccess') {
Expand All @@ -536,7 +585,7 @@ describe.skipIf(!dockerAvailable())('summary math fidelity (testcontainers Postg
await insertRandomAccess(sha, 'taxi', 'vortex-file-compressed', 50_000);

const summary = expectDefined(
await collectGroupSummary({ k: 'RandomAccessGroup' }),
await collectGroupSummary({ k: 'RandomAccessGroup', storage: 'nvme' }),
'random-access summary',
);
if (summary.type !== 'randomAccess') {
Expand Down
25 changes: 17 additions & 8 deletions web/lib/queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,24 +330,33 @@ describe.skipIf(!dockerAvailable())('chartPayload (testcontainers Postgres)', ()
// exercised end-to-end only by the Docker-gated collectGroups test; this no-DB
// test pins the ordering directly so it stays verifiable without testcontainers.
describe('compareGroupSortKey canonical group ordering (no DB)', () => {
it('orders Random Access directly before Clickbench', () => {
const sorted = ['PolarSignals Profiling', 'Random Access', 'Clickbench', 'Compression'].sort(
compareGroupSortKey,
);
it('orders NVMe and S3 Random Access directly before Clickbench', () => {
const sorted = [
'PolarSignals Profiling',
'Random Access (S3)',
'Random Access (NVMe)',
'Clickbench',
'Compression',
].sort(compareGroupSortKey);
expect(sorted).toEqual([
'Compression',
'Random Access',
'Random Access (NVMe)',
'Random Access (S3)',
'Clickbench',
'PolarSignals Profiling',
]);
expect(sorted.indexOf('Random Access') + 1).toBe(sorted.indexOf('Clickbench'));
expect(sorted.indexOf('Random Access (S3)') + 1).toBe(sorted.indexOf('Clickbench'));
});

it('sorts listed groups before unknown groups, unknowns alphabetically last', () => {
const sorted = ['cohere-large-10m / partitioned', 'Random Access', 'Compression'].sort(
const sorted = ['cohere-large-10m / partitioned', 'Random Access (NVMe)', 'Compression'].sort(
compareGroupSortKey,
);
expect(sorted).toEqual(['Compression', 'Random Access', 'cohere-large-10m / partitioned']);
expect(sorted).toEqual([
'Compression',
'Random Access (NVMe)',
'cohere-large-10m / partitioned',
]);
});

it('places the appian group directly after both fineweb groups', () => {
Expand Down
29 changes: 20 additions & 9 deletions web/lib/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
*/

import { getPool } from './db';
import { randomAccessStorage } from './random-access';
import { groupDescription } from './descriptions';
import type { FilterUniverse } from './chart-format';
import { compareCodeUnits, FAMILIES, type GroupKind } from './families';
Expand Down Expand Up @@ -685,7 +686,8 @@ export interface GroupChartsResponse {
const GROUP_ORDER: readonly string[] = [
'Compression',
'Compression Size',
'Random Access',
'Random Access (NVMe)',
'Random Access (S3)',
'Clickbench',
'TPC-H (NVMe) (SF=1)',
'TPC-H (S3) (SF=1)',
Expand Down Expand Up @@ -1001,22 +1003,31 @@ async function collectCompressionSizeGroup(): Promise<Group[]> {
];
}

/** The single `Random Access` group, or `[]` if the fact table is empty. */
/** One random-access group per storage backend, omitting empty sections. */
async function collectRandomAccessGroup(): Promise<Group[]> {
const text = `
SELECT DISTINCT dataset
FROM random_access_times
ORDER BY dataset
`;
const rows = (await getPool().query<{ dataset: string }>(text)).rows;
if (rows.length === 0) {
return [];
const groups: Group[] = [];
for (const storage of ['nvme', 's3'] as const) {
const charts: ChartLink[] = rows
.filter((row) => randomAccessStorage(row.dataset) === storage)
.map((row) => ({
name: row.dataset,
slug: chartKeyToSlug({ k: 'RandomAccess', dataset: row.dataset }),
}));
if (charts.length > 0) {
groups.push({
name: `Random Access (${storage === 'nvme' ? 'NVMe' : 'S3'})`,
slug: groupKeyToSlug({ k: 'RandomAccessGroup', storage }),
charts,
});
}
}
const charts: ChartLink[] = rows.map((row) => ({
name: row.dataset,
slug: chartKeyToSlug({ k: 'RandomAccess', dataset: row.dataset }),
}));
return [{ name: 'Random Access', slug: groupKeyToSlug({ k: 'RandomAccessGroup' }), charts }];
return groups;
}

type VectorSearchGroupRow = { dataset: string; layout: string; threshold: number };
Expand Down
21 changes: 21 additions & 0 deletions web/lib/random-access.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

import { describe, expect, it } from 'vitest';
import { randomAccessStorage } from './random-access';

// Matches push_v3_random_access_record in the monorepo random-access producer.
describe('randomAccessStorage', () => {
it.each([
['taxi', 'nvme'],
['taxi/correlated', 'nvme'],
['feature-vectors/uniform', 'nvme'],
['taxi-s3', 's3'],
['taxi-s3/correlated', 's3'],
['feature-vectors-s3/uniform', 's3'],
['taxi/pattern-s3', 'nvme'],
['taxi-s3-copy/uniform', 'nvme'],
] as const)('assigns %s to %s', (dataset, storage) => {
expect(randomAccessStorage(dataset)).toBe(storage);
});
});
12 changes: 12 additions & 0 deletions web/lib/random-access.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

export type RandomAccessStorage = 'nvme' | 's3';

/**
* The producer encodes S3 storage as `{dataset}-s3/{pattern}` (or legacy
* `taxi-s3`), since random_access_times has no separate storage dimension.
*/
export function randomAccessStorage(dataset: string): RandomAccessStorage {
return dataset.split('/')[0].endsWith('-s3') ? 's3' : 'nvme';
}
15 changes: 14 additions & 1 deletion web/lib/slug.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const GROUP_KEYS: GroupKey[] = [
{ k: 'QueryGroup', dataset: 'tpch', dataset_variant: null, scale_factor: '1', storage: 'nvme' },
{ k: 'CompressionTimeGroup' },
{ k: 'CompressionSizeGroup' },
{ k: 'RandomAccessGroup' },
{ k: 'RandomAccessGroup', storage: 'nvme' },
{ k: 'RandomAccessGroup', storage: 's3' },
{ k: 'VectorSearchGroup', dataset: 'cohere', layout: 'partitioned' },
];

Expand Down Expand Up @@ -83,6 +84,18 @@ describe('group slug round-trip', () => {
expect(chartPrefix).not.toBe(groupPrefix);
});

it('resolves legacy random-access group slugs to NVMe', () => {
const legacy = 'rag.' + Buffer.from('{"k":"RandomAccessGroup"}').toString('base64url');
expect(groupKeyFromSlug(legacy)).toEqual({ k: 'RandomAccessGroup', storage: 'nvme' });
});

it.each(['disk', '', null, 1])('rejects invalid random-access storage %s', (storage) => {
const slug =
'rag.' +
Buffer.from(JSON.stringify({ k: 'RandomAccessGroup', storage })).toString('base64url');
expect(() => groupKeyFromSlug(slug)).toThrow();
});

it('rejects a malformed group slug', () => {
expect(() => groupKeyFromSlug('not-a-slug')).toThrow();
expect(() => groupKeyFromSlug('qmg.****')).toThrow();
Expand Down
Loading
Loading