Skip to content

Commit 274bf50

Browse files
authored
Merge pull request #2 from danleh/sqlite-wasm
Sqlite Wasm build: build script, README, shell polyfill
2 parents f8d60ba + 1a769a4 commit 274bf50

File tree

10 files changed

+17981
-3
lines changed

10 files changed

+17981
-3
lines changed

JetStreamDriver.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,16 +1109,17 @@ class WasmBenchmark extends Benchmark {
11091109
};
11101110
11111111
oldPrint = globalObject.print;
1112+
oldConsoleLog = globalObject.console.log;
11121113
globalObject.print = globalObject.printErr = (...args) => {
11131114
if (verbose)
1114-
console.log('Intercepted print: ', ...args);
1115+
oldConsoleLog('Intercepted print: ', ...args);
11151116
};
11161117
11171118
let Module = {
11181119
preRun: [],
11191120
postRun: [],
1120-
print: function() { },
1121-
printErr: function() { },
1121+
print: globalObject.print,
1122+
printErr: globalObject.print,
11221123
setStatus: function(text) {
11231124
},
11241125
totalDependencies: 0,
@@ -1822,6 +1823,19 @@ const testPlans = [
18221823
benchmarkClass: WasmBenchmark,
18231824
testGroup: WasmGroup
18241825
},
1826+
{
1827+
name: "sqlite3-wasm",
1828+
files: [
1829+
"./sqlite3/polyfills.js",
1830+
"./sqlite3/build/jswasm/speedtest1.js",
1831+
"./sqlite3/benchmark.js",
1832+
],
1833+
preload: {
1834+
wasmBinary: "./sqlite3/build/jswasm/speedtest1.wasm"
1835+
},
1836+
benchmarkClass: WasmBenchmark,
1837+
testGroup: WasmGroup
1838+
},
18251839
{
18261840
name: "tfjs-wasm",
18271841
files: [

cli.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const isSpiderMonkey = typeof newGlobal !== "undefined";
3535
if (isSpiderMonkey)
3636
globalThis.readFile = readRelativeToScript;
3737

38+
if (typeof arguments !== "undefined" && arguments.length > 0)
39+
testList = arguments.slice();
3840
if (typeof testList === "undefined")
3941
testList = undefined;
4042

sqlite3/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/sqlite-src-*/
2+
/sqlite-src-*.zip

sqlite3/README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Official sqlite3 benchmark, compiled to WebAssembly
2+
3+
This is a Wasm (shell-only) build of SQLite's official `speedtest1.c` benchmark program.
4+
Quoting from https://sqlite.org/cpu.html:
5+
> This program strives to exercise the SQLite library in a way that is typical of real-world applications. Of course, every application is different, and so no test program can exactly mirror the behavior of all applications. The speedtest1.c program is updated from time to time as the SQLite developers' understanding of what constitutes "typical" usage evolves.
6+
7+
## Build Instructions
8+
9+
See `build.sh` or just run it.
10+
See `build.log` for the last build time, used sources, and toolchain versions.
11+
12+
Prerequisites:
13+
- Emscripten: https://emscripten.org. Make sure `emcc` is on your `PATH`, e.g., by running `source /path/to/emsdk_env.sh`.
14+
- `wasm-strip`: Install WABT, e.g., via `sudo apt install wabt` or by compiling yourself from the source at https://github.com/WebAssembly/wabt.
15+
16+
Since this benchmark is meant for the developers of SQLite, it is not part of the official Wasm build of SQLite at https://sqlite.org/wasm/doc/trunk/index.md and also not contained in the "amalgamation" single-file source code of SQLite (see https://sqlite.org/amalgamation.html).
17+
So we need to build it ourselves from the full sources.
18+
You can download the full SQLite source tree from https://sqlite.org/download.html.
19+
See under "Alternative Source Code Formats" or search for "Snapshot of the complete (raw) source tree for SQLite".
20+
21+
## Running in JS shells
22+
23+
The SQLite developers only maintain compatibility of the Wasm build for running inside browsers, so `benchmark.js` contains some polyfills to run it JavaScript shells (such as `d8` (V8), `js` (SpiderMonkey), and `jsc` (JavaScriptCore)).
24+
Ideally, it should run just via `$shell benchmark.js` from the current directory.
25+
26+
To keep the shell runner and browser results consistent, the benchmark is configured to never use OPFS (Origin Private File System) as the underlying storage layer ("VFS" in SQLite), since that is not available in shells.
27+
It might thus show slightly different performance characteristics compared to the upstream `speedtest1.html` running with OPFS.
28+
29+
## Running the upstream version of the benchmark in browsers
30+
31+
Start a webserver in `build/` that serves with the correct headers (CORS/COOP/COEP) set for Wasm execution.
32+
E.g., this simple Python server will do:
33+
```
34+
#!/usr/bin/env python3
35+
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
36+
import sys
37+
38+
class CORSRequestHandler (SimpleHTTPRequestHandler):
39+
def end_headers (self):
40+
self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
41+
self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
42+
43+
SimpleHTTPRequestHandler.end_headers(self)
44+
45+
if __name__ == '__main__':
46+
test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8083)
47+
```
48+
49+
Then browse to http://localhost:8083/speedtest1.html.
50+
(Note that, e.g., Chrome requires `localhost`, not an IP!)
51+
Because the computation happens on the main thread, it may hang for a little while but should show the console output afterwards.

sqlite3/benchmark.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2024 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
const inJetStreamRunner = typeof globalThis.benchmarkTime !== "undefined";
6+
if (!inJetStreamRunner) {
7+
load("polyfills.js");
8+
9+
// Exports `sqlite3InitModule()` and contains the main code.
10+
load("build/jswasm/speedtest1.js");
11+
12+
// Load Wasm binary from disk.
13+
globalThis.Module = {
14+
wasmBinary: read("build/jswasm/speedtest1.wasm", "binary"),
15+
};
16+
}
17+
18+
// Make sure we never initialize OPFS by removing one of it's APIs (see
19+
// `installOpfsVfs` in the generated JavaScript code of sqlite).
20+
// We never want to use it anyway (see VFS config below) and this way we don't
21+
// waste cycles on the browser runner to initialize it.
22+
delete globalThis.FileSystemHandle;
23+
24+
// Simplified from inline JavaScript in `speedtest1.html`.
25+
function runTests(sqlite3Module) {
26+
// Configure the VFS to use.
27+
// Don't use OPFS, WASMFS (which is on top of OPFS), or kvvfs, since they all
28+
// use persistent browser storage (localStorage or OPFS), which is not
29+
// available in JavaScript shells.
30+
// Also don't use memfs, since that crashes with a NULL function pointer.
31+
// Instead, make the default VFS explicit.
32+
const capi = sqlite3Module.capi
33+
console.log("Available SQLite VFS:", capi.sqlite3_js_vfs_list());
34+
const vfs = "unix";
35+
console.log("Using VFS:", vfs);
36+
const pVfs = capi.sqlite3_vfs_find(vfs);
37+
if (!pVfs) {
38+
console.error("Error: Unknown VFS:", vfs);
39+
return;
40+
}
41+
42+
// These arguments should match the upstream browser runner `speedtest1.html`.
43+
let argv = [
44+
"speedtest1",
45+
"--singlethread",
46+
//"--nomutex",
47+
//"--nosync",
48+
//"--memdb", // note that memdb trumps the filename arg
49+
"--nomemstat",
50+
"--big-transactions" /*important for tests 410 and 510!*/,
51+
"--size", "20", // To speedup, default is 100 (and takes about 4s).
52+
"--vfs", vfs, // See VFS comment above.
53+
];
54+
55+
console.log("Calling main with argv:", argv);
56+
const wasm = sqlite3Module.wasm;
57+
wasm.scopedAllocPush(); // Required for `scopedAllocMainArgv()`.
58+
wasm.xCall("wasm_main", argv.length, wasm.scopedAllocMainArgv(argv));
59+
wasm.scopedAllocPop();
60+
}
61+
62+
async function doRun() {
63+
let start = benchmarkTime();
64+
const sqliteModule = await sqlite3InitModule(Module);
65+
reportCompileTime(benchmarkTime() - start);
66+
67+
start = benchmarkTime();
68+
runTests(sqliteModule);
69+
reportRunTime(benchmarkTime() - start);
70+
}
71+
if (!inJetStreamRunner) {
72+
sqlite3InitModule(Module).then(runTests);
73+
}

sqlite3/build.log

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Built on 2024-12-05 14:24:19+01:00
2+
3+
Toolchain versions
4+
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.71 (4171ae200b77a6c266b0e1ebb507d61d1ade3501)
5+
wasm-strip 1.0.34
6+
7+
Getting sources from https://sqlite.org/2024/sqlite-src-3470100.zip
8+
9+
Building...
10+
Copying files from sqlite-src-*/ext/wasm/ into build/
11+
Build success

sqlite3/build.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
3+
set -e
4+
set -o pipefail
5+
6+
# Cleanup old files.
7+
rm sqlite-src-*.zip
8+
rm -rf sqlite-src-*/
9+
rm -rf build/
10+
11+
BUILD_LOG="$(realpath build.log)"
12+
echo -e "Built on $(date --rfc-3339=seconds)\n" | tee "$BUILD_LOG"
13+
14+
echo "Toolchain versions" | tee -a "$BUILD_LOG"
15+
emcc --version | head -n1 | tee -a "$BUILD_LOG"
16+
echo -e "wasm-strip $(wasm-strip --version)\n" | tee -a "$BUILD_LOG"
17+
18+
# Check https://sqlite.org/download.html and update the source link, if needed.
19+
SQLITE_SRC_URL="https://sqlite.org/2024/sqlite-src-3470100.zip"
20+
echo -e "Getting sources from $SQLITE_SRC_URL\n" | tee -a "$BUILD_LOG"
21+
SQLITE_SRC_FILE="$(basename $SQLITE_SRC_URL)"
22+
curl -o "$SQLITE_SRC_FILE" $SQLITE_SRC_URL
23+
unzip "$SQLITE_SRC_FILE"
24+
25+
# Paths and information in make output could be sensitive, so don't save in log.
26+
echo "Building..." | tee -a "$BUILD_LOG"
27+
pushd sqlite-src-*/
28+
./configure
29+
cd ext/wasm
30+
make dist
31+
popd
32+
33+
echo "Copying files from sqlite-src-*/ext/wasm/ into build/" | tee -a "$BUILD_LOG"
34+
mkdir -p build/{common,jswasm} | tee -a "$BUILD_LOG"
35+
cp sqlite-src-*/ext/wasm/jswasm/speedtest1.{js,wasm} build/jswasm/ | tee -a "$BUILD_LOG"
36+
# The next files are only needed for the upstream browser build, not the
37+
# JetStream version, hence don't copy them by default.
38+
# cp sqlite-src-*/ext/wasm/speedtest1.html build/ | tee -a "$BUILD_LOG"
39+
# cp sqlite-src-*/ext/wasm/common/{emscripten.css,SqliteTestUtil.js,testing.css} build/common/ | tee -a "$BUILD_LOG"
40+
41+
echo "Build success" | tee -a "$BUILD_LOG"

0 commit comments

Comments
 (0)