Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a486f7f
blog: draft the rind launch post with interactive benchmark charts
kixelated Nov 6, 2026
a4301d9
blog(rind): measure the runtimes chart and both CPUs' QUIC rows
kixelated Nov 6, 2026
8ab77bc
blog(rind): settle the draft's decisions and fill in the AI tally
kixelated Nov 6, 2026
ce08829
blog(rind): show the AI tally's totals only, without per-day metrics
kixelated Nov 6, 2026
17a7799
blog(rind): time the extended Bun-on-rind prototype
kixelated Nov 6, 2026
9a4d5e0
blog(rind): headline-first figures, every library, and a proof heatmap
kixelated Nov 7, 2026
3945390
blog(rind): end with a speed heatmap of every benchmark
kixelated Nov 7, 2026
5957bd5
blog(rind): time 55 asymmetric calls per runtime, and map them all
kixelated Nov 7, 2026
e0ddc47
blog(rind): runtimes.mjs needs no Deno permissions, as runtimes.sh ru…
kixelated Nov 7, 2026
9268f28
blog
kixelated Nov 7, 2026
50cece9
blog(rind): refresh the data from rind main, with Apple M4's build cost
kixelated Nov 7, 2026
2425f69
blog(rind): add Apple M4 to the library charts, with proofs credited …
kixelated Nov 7, 2026
a84c7af
Update the final rind launch cost
kixelated Nov 7, 2026
4edecc6
Show only Opus usage in the rind receipt
kixelated Nov 7, 2026
597fc54
blog(rind): add the rind logo, headline the best CPU, assume DIT is held
kixelated Nov 8, 2026
dbb1be6
vibe slop
kixelated Nov 8, 2026
87e7d69
blog(rind): average the QUIC headline over every CPU, rustls librarie…
kixelated Nov 8, 2026
b8f5b89
blog(rind): average the build race over every CPU
kixelated Nov 8, 2026
6e7dc90
blog(rind): add the "I'm tired, boss" meme
kixelated Nov 8, 2026
44ec194
wip
kixelated Nov 8, 2026
514712f
uh
kixelated Nov 8, 2026
056ed75
blog(rind): drop the unused Speed and QuicScore charts, note DIT in f…
kixelated Nov 8, 2026
1b7247e
frontmatter
kixelated Nov 8, 2026
347787a
blog(rind): date it November 8, fill the aws-lc-rs snippet
kixelated Nov 8, 2026
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
31 changes: 31 additions & 0 deletions public/blog/rind/cover.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions public/blog/rind/rind.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/blog/rind/tired.webm
Binary file not shown.
134 changes: 134 additions & 0 deletions src/components/rind/build.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// What rustls costs to build from scratch on each crypto library: a race, in seconds averaged over every CPU.
import { createSignal, For, onCleanup, onMount } from "solid-js";
import { commit, cpu, day, Figure, frames, geomean, midscreen, name, reduced } from "./chart";
import data from "./data/build.json";

const RACERS = ["rustls-rind", "rustls-ring", "rustls-aws-lc-rs"];
// Race seconds per real second.
const SPEED = 12;

const TOOLS: Record<string, string> = { cc: "C compiler", make: "make", perl: "perl", "pkg-config": "pkg-config" };
const needs = (tools: string[]) =>
tools.length ? `needs ${tools.map((t) => TOOLS[t] ?? t).join(", ")}` : "rustc only";
const label = (build: string) =>
build.startsWith("rustls-") ? `rustls + ${name(build.slice("rustls-".length))}` : name(build);

type Host = (typeof data.hosts)[number];
const seconds = (h: Host, build: string) => {
const b = h.builds.find((b) => b.name === build);
if (!b) throw new Error(`build.json's ${h.name} has no ${build}`);
return b;
};

export default function Build() {
// Each racer's build, its time the geometric mean over every CPU.
const racers = RACERS.map((r) => {
const builds = data.hosts.map((h) => seconds(h, r));
const tools = builds[0].tools;
if (builds.some((b) => b.tools.join() !== tools.join())) throw new Error(`${r} needs different tools per CPU`);
return { name: r, seconds: geomean(builds.map((b) => b.seconds)), tools };
});
const max = Math.max(...racers.map((r) => r.seconds));
const time = (r: string) => {
const racer = racers.find((x) => x.name === r);
if (!racer) throw new Error(`${r} isn't racing`);
return racer.seconds;
};
const ratio = (x: Host) => seconds(x, "rustls-aws-lc-rs").seconds / seconds(x, "rustls-rind").seconds;

// The race clock rests at the finish, so the figure reads complete before it plays.
const [clock, setClock] = createSignal(max);
let figure: HTMLElement | undefined;
let cancel = () => {};
const race = () => {
cancel();
setClock(0);
cancel = frames((s) => {
setClock(Math.min(max, s * SPEED));
return s * SPEED < max;
});
};
onMount(() => {
if (figure && !reduced()) midscreen(figure, race);
});
onCleanup(() => cancel());

return (
<Figure
ref={(el) => {
figure = el;
}}
kicker={`rustls, cold release build · averaged over ${data.hosts.length} CPUs`}
number={`${(time("rustls-aws-lc-rs") / time("rustls-rind")).toFixed(1)}×`}
headline={
<>
faster to
<br />
build
</>
}
label={`Seconds to build rustls on rind, ring, and aws-lc-rs, averaged over ${data.hosts.length} CPUs, as a race.`}
table={{
head: ["CPU", "Build", "Time", "CPU time", "Binary", "Tools"],
rows: data.hosts.flatMap((x) =>
x.builds.map((b) => [
x.name,
label(b.name),
`${b.seconds.toFixed(1)} s`,
`${b.cpu_seconds.toFixed(1)} s`,
`${(b.bytes / 1024 / 1024).toFixed(2)} MiB`,
needs(b.tools),
]),
),
}}
source={
<>
rind's admin/build-cost: the median of cold builds with an empty target directory and a warm download cache.{" "}
{data.hosts.map((x, i) => (
<>
{i ? "; " : ""}
{x.name}: {cpu(x.source.cpu)}, {x.source.jobs} jobs, {x.source.runs} runs, {day(x.source.date)}, at{" "}
{commit(x.source.rind)}
</>
))}
. A tool counts when the build fails without it.
</>
}
>
<div class="race-head">
<div />
<div class="clock">
<strong>{clock().toFixed(1)} s</strong>race clock, {SPEED}× speed
</div>
</div>
<div class="bars race">
<For each={racers}>
{(r) => {
const done = () => clock() >= r.seconds;
return (
<div class={`bar${r.name.endsWith("rind") ? " me" : ""}${done() ? " done" : ""}`}>
<div class="name">
{label(r.name)}
<br />
<span class={`chip${r.tools.length ? "" : " ok"}`}>{needs(r.tools)}</span>
</div>
<div class="track">
<div class="go" style={{ width: `${(100 * Math.min(clock(), r.seconds)) / max}%` }} />
<div class="time">{done() ? `${r.seconds.toFixed(1)} s ✓` : "compiling…"}</div>
</div>
</div>
);
}}
</For>
</div>
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="fine" style={{ margin: 0 }}>
The geometric mean over CPUs. {data.hosts.map((x) => `${x.name}: ${ratio(x).toFixed(1)}×`).join(", ")}.
</p>
<button type="button" class="replay" onClick={race}>
↻ Race again
</button>
</div>
</Figure>
);
}
Loading
Loading