Skip to content

Commit 3cc1233

Browse files
author
Erik Soehnel
committed
render the graph using db queries
1 parent e27ae9f commit 3cc1233

File tree

10 files changed

+1697
-88
lines changed

10 files changed

+1697
-88
lines changed

app/package-lock.json

Lines changed: 1267 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"@mantine/core": "^7.13.2",
14+
"@mantine/hooks": "^7.13.2",
1315
"@sqlite.org/sqlite-wasm": "^3.46.1-build3",
1416
"react": "^18.3.1",
15-
"react-dom": "^18.3.1"
17+
"react-dom": "^18.3.1",
18+
"vega": "^5.30.0",
19+
"vega-lite": "^5.21.0"
1620
},
1721
"devDependencies": {
1822
"@eslint/js": "^9.9.0",

app/src/App.tsx

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { AppShell, Group, MantineProvider, rem } from "@mantine/core";
12
import "./App.css";
3+
import { Graph } from "./components/Graph";
24
import { DatabaseContextProvider, useDatabase } from "./database";
35

46
function ResultsTable() {
@@ -7,32 +9,47 @@ function ResultsTable() {
79
});
810

911
return (
10-
<table>
11-
<thead>
12-
<tr>
13-
<th>benchmark</th>
14-
<th>name</th>
15-
<th>ops</th>
16-
</tr>
17-
</thead>
18-
<tbody>
19-
{results?.map((r, i) => (
20-
<tr key={i}>
21-
<td>{r.benchmark}</td>
22-
<td>{r.name}</td>
23-
<td>{r.ops}</td>
12+
<>
13+
<h1>sqlite</h1>
14+
15+
<table>
16+
<thead>
17+
<tr>
18+
<th>benchmark</th>
19+
<th>name</th>
20+
<th>ops</th>
2421
</tr>
25-
))}
26-
</tbody>
27-
</table>
22+
</thead>
23+
<tbody>
24+
{results?.map((r, i) => (
25+
<tr key={i}>
26+
<td>{r.benchmark}</td>
27+
<td>{r.name}</td>
28+
<td>{r.ops}</td>
29+
</tr>
30+
))}
31+
</tbody>
32+
</table>
33+
</>
2834
);
2935
}
3036

3137
function App() {
3238
return (
3339
<DatabaseContextProvider>
34-
<h1>sqlite</h1>
35-
<ResultsTable />
40+
<MantineProvider>
41+
<AppShell header={{ height: 60, offset: false }} padding="md">
42+
<AppShell.Header>
43+
<Group h="100%" px="md">
44+
<h1>Benchmark</h1>
45+
</Group>
46+
</AppShell.Header>
47+
48+
<AppShell.Main pt={`calc(${rem(60)} + var(--mantine-spacing-md))`}>
49+
<Graph />
50+
</AppShell.Main>
51+
</AppShell>
52+
</MantineProvider>
3653
</DatabaseContextProvider>
3754
);
3855
}

app/src/components/Graph.tsx

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { useState } from "react";
2+
import * as vega from "vega";
3+
import * as vegaLite from "vega-lite";
4+
import { type Result, BENCHMARKS, COLORS, useDatabase } from "../database";
5+
6+
async function graph({
7+
results,
8+
sortedNames,
9+
colors,
10+
runtimeCount,
11+
}: {
12+
// the benchmark results to display
13+
results: Result[];
14+
// module names in the order that they should appear in the graph
15+
sortedNames: string[];
16+
// the number of selected runtimes to calculate the chart bar height
17+
runtimeCount: number;
18+
// a color map so that each benchmark has the same color in different
19+
// node-versions
20+
colors: string[];
21+
}) {
22+
const values = results.map((r) => ({
23+
...r,
24+
opsLabel: r.ops.toLocaleString("en-US"),
25+
// artificical benchmark name to make sure its always sorted by
26+
// benchmark and node-version
27+
benchmark: [
28+
BENCHMARKS.find((b) => b.name === r.benchmark)?.order,
29+
r.runtime,
30+
r.runtimeVersion,
31+
r.benchmark,
32+
].join("-"),
33+
}));
34+
35+
const vegaSpec = vegaLite.compile({
36+
data: {
37+
values: values,
38+
},
39+
height: { step: 15 / runtimeCount },
40+
background: "transparent", // no white graphs for dark mode users
41+
facet: {
42+
row: {
43+
field: "name",
44+
title: null,
45+
header: {
46+
labelAngle: 0,
47+
labelOrient: "left",
48+
labelAnchor: "middle",
49+
labelAlign: "left",
50+
labelFontSize: 12,
51+
},
52+
sort: sortedNames,
53+
},
54+
},
55+
spec: {
56+
layer: [
57+
{
58+
mark: "bar",
59+
width: 600,
60+
},
61+
{
62+
mark: {
63+
type: "text",
64+
align: "left",
65+
baseline: "middle",
66+
dx: 3,
67+
},
68+
encoding: {
69+
text: { field: "opsLabel" },
70+
},
71+
},
72+
],
73+
encoding: {
74+
x: {
75+
field: "ops",
76+
type: "quantitative",
77+
title: ["operations / sec", "(better ▶)"],
78+
axis: {
79+
orient: "top",
80+
offset: 10,
81+
labelFontSize: 12,
82+
titleFontSize: 14,
83+
titleFontWeight: "normal",
84+
},
85+
},
86+
y: {
87+
field: "benchmark",
88+
type: "nominal",
89+
title: "Benchmark",
90+
axis: null, // to debug the bars: axis: {labelFontSize: 3},
91+
},
92+
color: {
93+
field: "benchmark",
94+
type: "nominal",
95+
legend: null,
96+
scale: {
97+
range: colors,
98+
},
99+
},
100+
},
101+
},
102+
});
103+
104+
const view = new vega.View(vega.parse(vegaSpec.spec), { renderer: "none" });
105+
const svg = await view.toSVG();
106+
107+
return svg;
108+
}
109+
110+
export function Graph() {
111+
const [svg, setSvg] = useState<string | null>(null);
112+
113+
useDatabase(async (db) => {
114+
setSvg(
115+
await graph({
116+
colors: COLORS,
117+
results: await db.findResults(),
118+
runtimeCount: await db.getSelectedRuntimeCount(),
119+
sortedNames: await db.findSortedModuleNames(),
120+
}),
121+
);
122+
});
123+
124+
if (!svg) {
125+
return (
126+
<div style={{ margin: "5rem" }}>
127+
<i>No Benchmark Selected</i>
128+
</div>
129+
);
130+
}
131+
132+
return (
133+
<div
134+
style={{ marginBottom: "1rem" }}
135+
dangerouslySetInnerHTML={{ __html: svg }}
136+
/>
137+
);
138+
}

app/src/database/DatabaseContext.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export function DatabaseContextProvider(props: PropsWithChildren) {
1313

1414
Database.create()
1515
.then(async (conn) => {
16-
await conn.fetchResults();
16+
// fetch results lazily
17+
conn.fetchResults().catch(console.error);
18+
1719
setDb(conn);
1820
})
1921
.catch(console.error);

0 commit comments

Comments
 (0)