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
2 changes: 1 addition & 1 deletion docs/bench/architecture/read-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ order is the curated `GROUP_ORDER` in `queries.ts`:
Compression, Compression Size, Random Access, Clickbench,
TPC-H (NVMe/S3) SF=1, SF=10, SF=100 (alternating),
TPC-DS (NVMe) SF=1,
Statistical and Population Genetics, PolarSignals Profiling,
Statistical and Population Genetics, Polar Signals Profiling,
fineweb (NVMe/S3), Appian (NVMe)
```

Expand Down
2 changes: 1 addition & 1 deletion scripts/parity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ JSON path with both values:
```text
/api/group/{slug}?n=50: body differs $.charts[3].series["datafusion:parquet"][41]: 1.25 != 1.26
/api/chart/{slug}?n=100: cache-control "public, s-maxage=300, stale-while-revalidate=3600" != "no-store"
/chart/{slug}: title "TPC-H Q1 - Vortex Benchmarks" != "Vortex Benchmarks"
/chart/{slug}: title "TPC-H Q1 | Vortex" != "Benchmarks | Vortex"
```

When two bodies parse to the same JSON but differ in bytes, the line gives the byte offset and the
Expand Down
4 changes: 2 additions & 2 deletions src/app/(bench)/bench/chart/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const getChart = cache(async (slug: string, n: string | null): Promise<ChartResp
});

/**
* The browser-tab title mirrors v3: `{display_name} - Vortex Benchmarks`. The
* The browser-tab title is `{display_name} | Vortex`, the system's page title. The
* description gives each series' newest value, and the canonical URL is the
* chart's canonical slug without a window.
*/
Expand All @@ -133,7 +133,7 @@ export async function generateMetadata({
return {};
}
const key = chartKeyFromSlug(slug);
const title = `${chart.display_name} - Vortex Benchmarks`;
const title = `${chart.display_name} | Vortex`;
const description = chartDescription(chart, key.k);
const url = chartUrl(chartKeyToSlug(key));
return {
Expand Down
4 changes: 2 additions & 2 deletions src/app/(bench)/bench/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import '@/bench/styles/globals.css';
export async function generateMetadata(): Promise<Metadata> {
const base = await requestBenchBase();
return {
title: 'Vortex Benchmarks',
title: 'Benchmarks | Vortex',
description: BENCH_DESCRIPTION,
// The canonical and Open Graph URLs are bench's public ones, written out
// in full. No `metadataBase`: it would also resolve the icons' paths, which
// belong to the host serving the page, against bench.vortex.dev.
openGraph: openGraph('Vortex Benchmarks', BENCH_DESCRIPTION, `${BENCH_URL}/`),
openGraph: openGraph('Benchmarks | Vortex', BENCH_DESCRIPTION, `${BENCH_URL}/`),
// Theme-aware favicons, ported from `render.rs::favicon_links`: the black
// sigil on light-mode tabs, the white sigil on dark-mode tabs, with the dark
// sigil as the unmediated fallback (and the apple-touch icon). The files are
Expand Down
2 changes: 1 addition & 1 deletion src/app/(bench)/bench/methodology/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { BenchHeader } from '@/bench/components/BenchHeader';
import { METHODOLOGY } from '@/bench/lib/methodology';
import { BENCH_URL, openGraph } from '@/bench/lib/site-files';

const TITLE = 'Methodology - Vortex Benchmarks';
const TITLE = 'Methodology | Vortex';
const DESCRIPTION =
'How the Vortex benchmarks run: the machines, storage, engines, and formats, how each ' +
'result is measured, and how the summaries are scored.';
Expand Down
13 changes: 8 additions & 5 deletions src/app/(site)/blog/[slug]/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { notFound } from "next/navigation";
import { getAllSlugs, getPostBySlug } from "@/lib/blog";
import { OG_CONTENT_TYPE, OG_SIZE, renderPostOgImage } from "@/lib/og";
import { siteName } from "@/lib/constants";
import { OG_CONTENT_TYPE, OG_SIZE, renderOgCard } from "@/lib/og";
import { formatPostDate } from "@/lib/posts";

export const alt = "Vortex blog post";
Expand All @@ -22,9 +23,11 @@ export default async function OgImage({
const post = getPostBySlug(slug);
if (!post) notFound();

return renderPostOgImage({
slug,
title: post.title,
date: formatPostDate(post.date)
return renderOgCard({
seed: slug,
eyebrow: `${siteName} blog`,
title: [post.title],
face: "display",
foot: formatPostDate(post.date)
});
}
6 changes: 3 additions & 3 deletions src/app/(site)/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ export async function generateMetadata({

if (!post) {
return {
title: "Post Not Found | Vortex Blog"
title: "Post not found | Vortex"
};
}

const description = post.excerpt || `Read "${post.title}" on the Vortex blog`;

return {
title: `${post.title} | Vortex Blog`,
title: `${post.title} | Vortex`,
description,
openGraph: {
title: `${post.title} | Vortex Blog`,
title: `${post.title} | Vortex`,
description,
siteName,
url: `${baseUrl}/blog/${slug}`,
Expand Down
14 changes: 9 additions & 5 deletions src/app/(site)/blog/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { OG_CONTENT_TYPE, OG_SIZE, renderOgImage } from "@/lib/og";
import { siteName } from "@/lib/constants";
import { OG_CONTENT_TYPE, OG_SIZE, renderOgCard } from "@/lib/og";

export const alt = "Vortex Blog";
export const alt = "Vortex blog";
export const size = OG_SIZE;
export const contentType = OG_CONTENT_TYPE;

export default function OgImage() {
return renderOgImage({
title: "Blog",
description: "Updates and insights from the Vortex team."
return renderOgCard({
seed: "blog",
eyebrow: siteName,
title: ["Blog"],
face: "display",
foot: "Updates and insights from the Vortex team."
});
}
17 changes: 11 additions & 6 deletions src/app/(site)/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { OG_CONTENT_TYPE, OG_SIZE, renderOgImage } from "@/lib/og";
import { siteName } from "@/lib/constants";
import { OG_CONTENT_TYPE, OG_SIZE, renderOgCard } from "@/lib/og";

export const alt = "Vortex — an extensible, SOTA columnar file format";
export const alt = "Vortex, the frontier file format.";
export const size = OG_SIZE;
export const contentType = OG_CONTENT_TYPE;

// What Vortex is, over the homepage's standfirst, in the homepage's mono
// voice. The card does not repeat the homepage's headline.
export default function OgImage() {
return renderOgImage({
title: "An extensible, SOTA columnar file format",
description:
"Tools for working with compressed Apache Arrow arrays in-memory, on-disk, and over-the-wire."
return renderOgCard({
seed: "home",
eyebrow: siteName,
title: ["The frontier", "file format"],
face: "mono",
foot: "An open-source columnar file format for fast scans, random access, and compression."
});
}
5 changes: 3 additions & 2 deletions src/app/(site)/rss/[type]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ export async function GET(
// JSON Feed marks a link item (`external_url`). In RSS and Atom a link item
// reads as our own post, so the three feeds would disagree.
const posts = getAllPosts();
const date = new Date();

const feed = new Feed({
title: "Vortex Blog",
description: "Updates and insights from the Vortex team",
id: baseUrl,
link: baseUrl,
favicon: `${baseUrl}/favicon.ico`,
copyright: `All rights reserved ${date.getFullYear()}, Vortex`,
// The posts are CC-BY-4.0 (REUSE.toml), and the project is a Series of
// LF Projects, LLC.
copyright: "CC-BY-4.0, Vortex a Series of LF Projects, LLC",
generator: "rss feed",
feedLinks: {
rss2: `${baseUrl}/rss/feed.xml`,
Expand Down
2 changes: 1 addition & 1 deletion src/bench/components/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ export function Chart({ slug, name, index, groupSlug, initialPayload }: ChartIsl
step={1}
defaultValue={100}
data-role="scope-slider"
aria-label="Custom commit window"
aria-label="Show commits"
ref={sliderRef}
/>
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/bench/components/GroupNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { GroupNav, jumpToGroup, type GroupNavItem } from '@/bench/components/Gro

const GROUPS: GroupNavItem[] = [
{ name: 'Random Access', slug: 'random_access.abc' },
{ name: 'PolarSignals Profiling', slug: 'qmg.polar' },
{ name: 'Polar Signals Profiling', slug: 'qmg.polar' },
];

describe('GroupNav markup', () => {
Expand All @@ -25,7 +25,7 @@ describe('GroupNav markup', () => {
expect(html).not.toContain('group-nav-panel--open');
expect(html).toContain('id="group-nav-panel"');
expect(html).toContain('>Random Access</button>');
expect(html).toContain('>PolarSignals Profiling</button>');
expect(html).toContain('>Polar Signals Profiling</button>');
});

it('marks the whole menu as needing JavaScript, since neither its toggle nor its entries work without it', () => {
Expand All @@ -49,7 +49,7 @@ describe('jumpToGroup', () => {
document.body.innerHTML = `
<div id="group-nav-panel"></div>
<section id="polarsignals-profiling" data-group-slug="qmg.polar">
<details class="group-disclosure"><summary>PolarSignals</summary></details>
<details class="group-disclosure"><summary>Polar Signals</summary></details>
</section>
<section id="random-access" data-group-slug="random_access.abc">
<details class="group-disclosure"><summary>Random Access</summary></details>
Expand Down Expand Up @@ -139,7 +139,7 @@ describe('GroupNav jump-menu clicks', () => {
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
document.body.innerHTML = `
<section id="polarsignals-profiling" data-group-slug="qmg.polar">
<details class="group-disclosure" open><summary>PolarSignals</summary></details>
<details class="group-disclosure" open><summary>Polar Signals</summary></details>
</section>
<section id="random-access" data-group-slug="random_access.abc">
<details class="group-disclosure"><summary>Random Access</summary></details>
Expand Down
2 changes: 1 addition & 1 deletion src/bench/components/SummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function seriesTitle(item: SeriesRanking, coverageUnit: string): string {
const label = displaySeriesLabel(item.name);
return item.measured >= item.total
? label
: `${label} - measured in ${item.measured} of ${item.total} ${coverageUnit}; the rest scored by the missing-series penalty`;
: `${label} · measured in ${item.measured} of ${item.total} ${coverageUnit} · the rest scored by the missing-series penalty`;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/bench/lib/anchor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ describe('groupAnchors', () => {
]);
});

it('keeps the anchor a renamed group had, so shared links still land on it', () => {
expect(groupAnchor('Polar Signals Profiling')).toBe('polarsignals-profiling');
});

it('keeps the full production group list collision-free', () => {
const names = [
'Compression',
Expand All @@ -55,7 +59,7 @@ describe('groupAnchors', () => {
'TPC-DS (S3) (SF=100)',
'Random Access',
'Statistical and Population Genetics',
'PolarSignals Profiling',
'Polar Signals Profiling',
'fineweb [nvme]',
'fineweb [s3]',
'appian [nvme]',
Expand Down
16 changes: 15 additions & 1 deletion src/bench/lib/anchor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@
* URL. The API keeps the opaque slug.
*/

/**
* Anchors that stay as they were when a group's name changed, so links that
* readers already shared still land on the group. The group was named
* "PolarSignals Profiling" until its owners' spelling replaced it.
*/
const KEPT_ANCHORS: Readonly<Record<string, string>> = {
'Polar Signals Profiling': 'polarsignals-profiling',
};

/**
* Derive a URL anchor from a group display name: lowercase, every run of
* non-alphanumerics collapsed to a single `-`, leading/trailing dashes
* trimmed. `TPC-H (NVMe) (SF=1)` becomes `tpc-h-nvme-sf-1`. A name with no
* alphanumerics at all falls back to `group` so the anchor is never empty.
* alphanumerics at all falls back to `group` so the anchor is never empty. A
* renamed group keeps its old anchor (`KEPT_ANCHORS`).
*/
export function groupAnchor(name: string): string {
const kept = KEPT_ANCHORS[name];
if (kept !== undefined) {
return kept;
}
const anchor = name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
Expand Down
4 changes: 2 additions & 2 deletions src/bench/lib/data-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,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:v10:n100',
'data-cache:group-charts:v11:n100',
]);
expect(cacheCalls.map((call) => call.keyParts)).toContainEqual(['data-cache:groups:v10']);
expect(cacheCalls.map((call) => call.keyParts)).toContainEqual(['data-cache:groups:v11']);
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 src/bench/lib/data-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const CACHE_OPTIONS = { tags: [BENCH_DATA_TAG], revalidate: DATA_CACHE_BACKSTOP_
* code can serve payloads the old code computed until the next ingest.
* It is independent of the producer-facing benchmark schema version.
*/
const GROUP_PAYLOAD_CACHE_VERSION = 'v10';
const GROUP_PAYLOAD_CACHE_VERSION = 'v11';

// 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: 3 additions & 3 deletions src/bench/lib/descriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ describe('groupDescription', () => {
'analytics data',
);
expect(groupDescription('Statistical and Population Genetics')).toBe(
'A suite of Statistical and Population genetics queries using the gnomAD dataset',
'A suite of statistical and population genetics queries using the gnomAD dataset',
);
expect(groupDescription('PolarSignals Profiling')).toBe(
'Profiling data benchmark modeled on PolarSignals/Parca, exercising scan-layer performance ' +
expect(groupDescription('Polar Signals Profiling')).toBe(
'Profiling data benchmark modeled on Polar Signals/Parca, exercising scan-layer performance ' +
'with projection and filter pushdown on deeply nested schemas',
);
});
Expand Down
6 changes: 3 additions & 3 deletions src/bench/lib/descriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ function staticDescription(name: string): string | null {
'analytics data'
);
case 'Statistical and Population Genetics':
return 'A suite of Statistical and Population genetics queries using the gnomAD dataset';
case 'PolarSignals Profiling':
return 'A suite of statistical and population genetics queries using the gnomAD dataset';
case 'Polar Signals Profiling':
return (
'Profiling data benchmark modeled on PolarSignals/Parca, exercising scan-layer ' +
'Profiling data benchmark modeled on Polar Signals/Parca, exercising scan-layer ' +
'performance with projection and filter pushdown on deeply nested schemas'
);
default:
Expand Down
6 changes: 3 additions & 3 deletions src/bench/lib/groups.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1252,16 +1252,16 @@ describe('groupNameQuery v2-name special-cases (PR-5.0.5, no DB)', () => {
const name = groupNameQuery('statpopgen', null, null, 'nvme');
expect(name).toBe('Statistical and Population Genetics');
expect(groupDescription(name)).toBe(
'A suite of Statistical and Population genetics queries using the gnomAD dataset',
'A suite of statistical and population genetics queries using the gnomAD dataset',
);
});

it('maps polarsignals to its v2 name and attaches the profiling description', () => {
// Same null scale_factor as statpopgen in production.
const name = groupNameQuery('polarsignals', null, null, 'nvme');
expect(name).toBe('PolarSignals Profiling');
expect(name).toBe('Polar Signals Profiling');
expect(groupDescription(name)).toBe(
'Profiling data benchmark modeled on PolarSignals/Parca, exercising scan-layer ' +
'Profiling data benchmark modeled on Polar Signals/Parca, exercising scan-layer ' +
'performance with projection and filter pushdown on deeply nested schemas',
);
});
Expand Down
16 changes: 8 additions & 8 deletions src/bench/lib/methodology.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ export interface MethodologySection {
export const SCORES = {
query:
'the geometric mean, over the queries, of the series’ time divided by the fastest ' +
'series’ time on that query. 1.00x is the fastest; lower is better.',
'series’ time on that query. 1.00× is the fastest. Lower is better.',
/** No vector search results reach bench yet; `llms.txt` prints this only if some do. */
vectorSearch:
'the geometric mean, over the thresholds, of the series’ time divided by the fastest ' +
'series’ time at that threshold. 1.00x is the fastest; lower is better.',
'series’ time at that threshold. 1.00× is the fastest. Lower is better.',
randomAccess:
'the geometric mean, over the datasets, of the series’ time divided by the fastest ' +
'series’ time on that dataset. 1.00x is the fastest; lower is better.',
'series’ time on that dataset. 1.00× is the fastest. Lower is better.',
throughput:
'the geometric mean, over the datasets, of the format’s throughput divided by ' +
'Parquet’s. Higher is better.',
Expand All @@ -49,8 +49,8 @@ export const METHODOLOGY: readonly MethodologySection[] = [
'Every push to the develop branch of https://github.com/vortex-data/vortex runs the ' +
'compression, string encoding, random access, and SQL query benchmarks, and bench ' +
'records their results. A nightly run at 00:00 UTC adds TPC-H at scale factor 100 ' +
'and TPC-DS at scale factors 10 and 100. Benchmarks run on pull requests only ' +
'comment on the pull request; their results never reach bench.',
'and TPC-DS at scale factors 10 and 100. Benchmarks that run on pull requests only ' +
'comment on the pull request. Their results never reach bench.',
],
},
{
Expand All @@ -68,7 +68,7 @@ export const METHODOLOGY: readonly MethodologySection[] = [
text: [
'Queries run on DataFusion 55 and DuckDB 2.0. The formats are Vortex (its default ' +
'and compact write strategies), Apache Parquet, Lance 13, Arrow IPC, DuckDB’s own ' +
'format, and, for random access, LitData; not every suite runs every format. The ' +
'format, and, for random access, LitData. Not every suite runs every format. The ' +
'compression and file size benchmarks write Parquet with parquet-rs 59 and zstd at ' +
'level 3. ClickBench reads its published Parquet files.',
],
Expand All @@ -77,12 +77,12 @@ export const METHODOLOGY: readonly MethodologySection[] = [
title: 'How a result is measured',
text: [
'SQL suites drop the operating system’s page cache before each query, run it ' +
'several times, and record the median time. Most suites run each query 5 times; ' +
'several times, and record the median time. Most suites run each query 5 times. ' +
'TPC-H at scale factors 1 and 10 and Appian run it 10 times, TPC-DS at scale ' +
'factor 100 runs it 3 times, and the Vortex queries run it 100 times.',
'Random access drops the page cache before each dataset, format, access pattern, ' +
'and open mode, repeats the lookups for 10 seconds, and records the median. Hot ' +
'results keep one file open after a one-second untimed warm-up; cold results open ' +
'results keep one file open after a one-second untimed warm-up. Cold results open ' +
'the file again, footer included, for each lookup.',
'The compression benchmark drops the page cache before each dataset, writes and ' +
'scans it 5 times, and records the fastest run.',
Expand Down
Loading
Loading