Skip to content

Commit d8d8aee

Browse files
authored
Merge pull request #319 from fitzgen/sightglass-kotlin-richards
New benchmark: a port of Richards to Kotlin/Wasm
2 parents 3ab06d5 + b89561d commit d8d8aee

16 files changed

Lines changed: 680 additions & 25 deletions

File tree

.github/workflows/benchmarks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ jobs:
7575
run: |
7676
cargo run benchmark \
7777
--engine=artifacts/wasmtime-main/libengine.so \
78-
--engine-flags "-Wgc -Wfunction-references" \
78+
--engine-flags "-Wgc -Wfunction-references -Wexceptions" \
7979
--processes=4 \
8080
--iterations-per-process=1 \
8181
-- "${PARTITION_SUITE}"

benchmarks/all.suite

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ cm-online-stats/cm-online-stats.wasm
1313
hex-simd/benchmark.wasm
1414
# image-classification/image-classification-benchmark.wasm
1515
intgemm-simd/benchmark.wasm
16+
kotlin-richards/kotlin-richards.wasm
1617
libsodium/libsodium-aead_aegis128l.wasm
1718
libsodium/libsodium-aead_aegis256.wasm
1819
libsodium/libsodium-aead_aes256gcm.wasm

benchmarks/build.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,15 @@ print_header() {
3131
# directory and `--dereference` (i.e., follow) all symlinks provided.
3232
print_header "Create build context"
3333
TMP_TAR=$(mktemp /tmp/sightglass-benchmark-dir-XXXXXX.tar)
34-
(set -x; cd $BENCHMARK_DIR && tar --create --file $TMP_TAR --dereference --verbose .)
34+
# macOS's bsdtar bundles extended attributes (notably `com.apple.provenance`) that a Linux Docker
35+
# daemon rejects when unpacking the build context (`lsetxattr ... operation not supported`); exclude
36+
# them. GNU tar (used on CI) omits xattrs by default and lacks `--no-mac-metadata`, so only pass
37+
# these flags when the local `tar` is bsdtar.
38+
TAR_XATTR_FLAGS=()
39+
if tar --version 2>&1 | grep -qi bsdtar; then
40+
TAR_XATTR_FLAGS=(--no-xattrs --no-mac-metadata)
41+
fi
42+
(set -x; cd $BENCHMARK_DIR && tar "${TAR_XATTR_FLAGS[@]}" --create --file $TMP_TAR --dereference --verbose .)
3543

3644
# Build the benchmark image and extract the generated `benchmark.wasm` file from its container.
3745
print_header "Build benchmarks"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Reproducible build of the kotlin-richards benchmark.
2+
#
3+
# Stage 1 compiles the Kotlin sources to an optimized WasmGC core module via the
4+
# Kotlin/Wasm `wasmWasi` target. Stage 2 turns that core module into a WASI
5+
# *component* with wasm-tools and the WASI preview1 command adapter.
6+
7+
# ---------------------------------------------------------------------------
8+
# Stage 1: Kotlin -> optimized WasmGC core module.
9+
# ---------------------------------------------------------------------------
10+
FROM gradle:8.13-jdk21 AS kotlin-build
11+
WORKDIR /src
12+
13+
# Warm the Kotlin/Native + Binaryen toolchain and dependency caches in a layer
14+
# that does not depend on our sources, so editing the Kotlin only re-runs the
15+
# (fast) compile below.
16+
COPY settings.gradle.kts gradle.properties build.gradle.kts ./
17+
RUN mkdir -p src/wasmWasiMain/kotlin \
18+
&& printf 'fun main() {}\n' > src/wasmWasiMain/kotlin/Stub.kt \
19+
&& gradle --no-daemon compileProductionExecutableKotlinWasmWasiOptimize \
20+
&& rm -rf src
21+
22+
# Compile the real sources. Produces, with Binaryen already applied:
23+
# build/compileSync/wasmWasi/main/productionExecutable/optimized/kotlin-richards.wasm
24+
COPY src ./src
25+
RUN gradle --no-daemon compileProductionExecutableKotlinWasmWasiOptimize
26+
27+
# ---------------------------------------------------------------------------
28+
# Stage 2: core module -> WASI component.
29+
# ---------------------------------------------------------------------------
30+
FROM debian:bookworm-slim AS component-build
31+
32+
# Pinned tool versions. The adapter targets WASI 0.2.6 (matches sightglass).
33+
ARG WASM_TOOLS_VERSION=1.247.0
34+
ARG ADAPTER_WASMTIME_VERSION=37.0.0
35+
WORKDIR /work
36+
37+
RUN set -eux; \
38+
apt-get update; \
39+
apt-get install -y --no-install-recommends curl xz-utils ca-certificates; \
40+
rm -rf /var/lib/apt/lists/*; \
41+
case "$(uname -m)" in \
42+
x86_64) WT_ARCH=x86_64-linux ;; \
43+
aarch64|arm64) WT_ARCH=aarch64-linux ;; \
44+
*) echo "unsupported arch: $(uname -m)" >&2; exit 1 ;; \
45+
esac; \
46+
curl -sSL -o wasm-tools.tar.gz \
47+
"https://github.com/bytecodealliance/wasm-tools/releases/download/v${WASM_TOOLS_VERSION}/wasm-tools-${WASM_TOOLS_VERSION}-${WT_ARCH}.tar.gz"; \
48+
tar -xzf wasm-tools.tar.gz; \
49+
cp "wasm-tools-${WASM_TOOLS_VERSION}-${WT_ARCH}/wasm-tools" /usr/local/bin/; \
50+
wasm-tools --version; \
51+
curl -sSL -o wasi_snapshot_preview1.command.wasm \
52+
"https://github.com/bytecodealliance/wasmtime/releases/download/v${ADAPTER_WASMTIME_VERSION}/wasi_snapshot_preview1.command.wasm"
53+
54+
COPY --from=kotlin-build \
55+
/src/build/compileSync/wasmWasi/main/productionExecutable/optimized/kotlin-richards.wasm \
56+
core.wasm
57+
COPY wit ./wit
58+
59+
# The Kotlin WASI executable exports `_initialize` (a WASI "reactor" entry that
60+
# runs `fun main()`). Rename that export to `_start` so the preview1 *command*
61+
# adapter binds it to `wasi:cli/run`'s `run`, which is how sightglass invokes a
62+
# component benchmark. Then embed the world describing the `bench` import and
63+
# create the component (the adapter supplies the WASI imports + `run` export).
64+
RUN set -eux; \
65+
wasm-tools print core.wasm \
66+
| sed -E 's/\(export "_initialize" \(func /(export "_start" (func /' \
67+
| wasm-tools parse -o command.wasm; \
68+
wasm-tools component embed wit/bench.wit --world richards command.wasm -o embedded.wasm; \
69+
wasm-tools component new embedded.wasm \
70+
--adapt wasi_snapshot_preview1=wasi_snapshot_preview1.command.wasm \
71+
-o kotlin-richards.wasm; \
72+
wasm-tools validate --features all kotlin-richards.wasm; \
73+
mkdir -p /benchmark; \
74+
cp kotlin-richards.wasm /benchmark/
75+
# We output the Wasm file to the `/benchmark` directory, where the client
76+
# expects it.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# kotlin-richards
2+
3+
A Kotlin port of the classic Richards benchmark: a simulation of an operating
4+
system's scheduler. This version is a Wasm component produced via Kotlin/Wasm's
5+
`wasmWasi` target and `wasm-tools component new`.
6+
7+
Richards is an integer/pointer-heavy workload built around linked lists of
8+
"packets" routed between cooperating tasks (idle, worker, handler, device). It
9+
exercises object allocation, virtual dispatch, and pointer chasing, and here it
10+
also exercises the WasmGC, typed-function-references, and exception-handling
11+
proposals that Kotlin/Wasm relies on.
12+
13+
## Origin
14+
15+
The port follows the JavaScript implementation distributed with JetStream 2:
16+
17+
* Source: <https://browserbench.org/JetStream2.0/Octane/richards.js>
18+
(also published in Google's Octane benchmark suite as `richards.js`).
19+
20+
That JavaScript is itself a port of Martin Richards' original BCPL benchmark
21+
(<https://www.cl.cam.ac.uk/~mr10/Bench.html>). `Richards.kt` is a faithful,
22+
class-for-class translation of the JavaScript.
23+
24+
### License
25+
26+
The original JavaScript `richards.js` is copyright 2006-2008 the V8 project
27+
authors and is distributed under a BSD 3-clause license (see the header of the
28+
source linked above). This Kotlin port is made available under the same licenses
29+
as the rest of sightglass (Apache-2.0 WITH LLVM-exception, or MIT).
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
2+
3+
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
4+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
5+
6+
plugins {
7+
kotlin("multiplatform") version "2.3.0"
8+
}
9+
10+
repositories {
11+
mavenCentral()
12+
}
13+
14+
kotlin {
15+
wasmWasi {
16+
// A WASI "command": emits a core module exporting `_start` (whose body is
17+
// `fun main()`) plus linear `memory`, ready for the preview1->component
18+
// command adapter.
19+
nodejs()
20+
binaries.executable()
21+
}
22+
}
23+
24+
tasks.withType<KotlinCompilationTask<*>>().configureEach {
25+
compilerOptions.freeCompilerArgs.addAll(
26+
// Opt in to the experimental host-import and unsafe-linear-memory APIs we
27+
// use for the `bench` hooks and WASI file reading.
28+
"-opt-in=kotlin.wasm.ExperimentalWasmInterop",
29+
"-opt-in=kotlin.wasm.unsafe.UnsafeWasmMemoryApi",
30+
)
31+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
120
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
kotlin.code.style=official
2+
org.gradle.jvmargs=-Xmx2g

benchmarks/kotlin-richards/kotlin-richards.stderr.expected

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[kotlin-richards] iterations: 120
2+
[kotlin-richards] queue count: 278640
3+
[kotlin-richards] hold count: 111360
4+
[kotlin-richards] verified

0 commit comments

Comments
 (0)