Skip to content

Commit 851ba65

Browse files
committed
Use a local benchmarks directory instead of the Sightglass version
1 parent da13f7d commit 851ba65

295 files changed

Lines changed: 268786 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ WORKDIR /sightglass/engines/native/libengine
8383
RUN cargo build --release
8484
RUN cp target/release/libnative_bench_api.so ../libengine.so
8585

86+
# Replace sightglass benchmarks folder with custom version
87+
WORKDIR /
88+
RUN rm -rf /sightglass/benchmarks
89+
ADD benchmarks /sightglass/benchmarks
90+
8691
# Copy driver/helpers into the image
8792
WORKDIR /
8893
COPY wasmscore.py /sightglass/wasmscore.py

benchmarks/.clang-format

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
Language: Cpp
3+
AccessModifierOffset: -4
4+
AlignAfterOpenBracket: Align
5+
AlignConsecutiveAssignments: true
6+
AlignConsecutiveDeclarations: true
7+
AlignEscapedNewlinesLeft: true
8+
AlignOperands: true
9+
AlignTrailingComments: true
10+
AllowAllParametersOfDeclarationOnNextLine: true
11+
AllowShortBlocksOnASingleLine: false
12+
AllowShortCaseLabelsOnASingleLine: false
13+
AllowShortFunctionsOnASingleLine: Inline
14+
AllowShortIfStatementsOnASingleLine: false
15+
AllowShortLoopsOnASingleLine: false
16+
AlwaysBreakAfterDefinitionReturnType: None
17+
AlwaysBreakAfterReturnType: TopLevelDefinitions
18+
AlwaysBreakBeforeMultilineStrings: true
19+
AlwaysBreakTemplateDeclarations: true
20+
BinPackArguments: true
21+
BinPackParameters: true
22+
BraceWrapping:
23+
AfterClass: false
24+
AfterControlStatement: false
25+
AfterEnum: false
26+
AfterFunction: true
27+
AfterNamespace: false
28+
AfterObjCDeclaration: false
29+
AfterStruct: false
30+
AfterUnion: false
31+
BeforeCatch: false
32+
BeforeElse: false
33+
IndentBraces: false
34+
BreakBeforeBinaryOperators: None
35+
BreakBeforeBraces: WebKit
36+
BreakBeforeTernaryOperators: true
37+
BreakConstructorInitializersBeforeComma: true
38+
BreakAfterJavaFieldAnnotations: false
39+
BreakStringLiterals: true
40+
ColumnLimit: 100
41+
CommentPragmas: '^ IWYU pragma:'
42+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
43+
ConstructorInitializerIndentWidth: 4
44+
ContinuationIndentWidth: 4
45+
Cpp11BracedListStyle: false
46+
DerivePointerAlignment: true
47+
DisableFormat: false
48+
ExperimentalAutoDetectBinPacking: false
49+
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
50+
IncludeCategories:
51+
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
52+
Priority: 2
53+
- Regex: '^(<|"(gtest|isl|json)/)'
54+
Priority: 3
55+
- Regex: '.*'
56+
Priority: 1
57+
IncludeIsMainRegex: '$'
58+
IndentCaseLabels: false
59+
IndentWidth: 4
60+
IndentWrappedFunctionNames: false
61+
JavaScriptQuotes: Leave
62+
JavaScriptWrapImports: true
63+
KeepEmptyLinesAtTheStartOfBlocks: false
64+
MacroBlockBegin: ''
65+
MacroBlockEnd: ''
66+
MaxEmptyLinesToKeep: 1
67+
NamespaceIndentation: Inner
68+
ObjCBlockIndentWidth: 4
69+
ObjCSpaceAfterProperty: true
70+
ObjCSpaceBeforeProtocolList: true
71+
PenaltyBreakBeforeFirstCallParameter: 19
72+
PenaltyBreakComment: 300
73+
PenaltyBreakFirstLessLess: 120
74+
PenaltyBreakString: 1000
75+
PenaltyExcessCharacter: 1000000
76+
PenaltyReturnTypeOnItsOwnLine: 60
77+
PointerAlignment: Right
78+
ReflowComments: true
79+
SortIncludes: true
80+
SpaceAfterCStyleCast: true
81+
SpaceAfterTemplateKeyword: true
82+
SpaceBeforeAssignmentOperators: true
83+
SpaceBeforeParens: ControlStatements
84+
SpaceInEmptyParentheses: false
85+
SpacesBeforeTrailingComments: 1
86+
SpacesInAngles: false
87+
SpacesInContainerLiterals: true
88+
SpacesInCStyleCastParentheses: false
89+
SpacesInParentheses: false
90+
SpacesInSquareBrackets: false
91+
Standard: Cpp11
92+
TabWidth: 8
93+
UseTab: Never
94+
...
95+

benchmarks/.gitignore

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

benchmarks/Dockerfile.emscripten

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM emscripten/emsdk:2.0.8
2+
3+
WORKDIR /
4+
COPY benchmark.c .
5+
COPY sightglass.h .
6+
WORKDIR /benchmark
7+
RUN emcc ../benchmark.c -O3 -g -DNDEBUG -I.. -o benchmark.wasm
8+
# We output the Wasm file to the `/benchmark` directory, where the client
9+
# expects it.

benchmarks/Dockerfile.rust

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM rust:1.70
2+
RUN rustup target add wasm32-wasi
3+
WORKDIR /usr/src
4+
ADD rust-benchmark rust-benchmark
5+
WORKDIR /usr/src/rust-benchmark
6+
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
7+
RUN cargo build --release --target wasm32-wasi
8+
RUN mkdir /benchmark
9+
RUN cp target/wasm32-wasi/release/*benchmark.wasm /benchmark/
10+
# We output the Wasm file to the `/benchmark` directory, where the client
11+
# expects it.

benchmarks/Dockerfile.wasi-sdk

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This two-phase Dockerfile allows us to avoid re-downloading APT packages and wasi-sdk with every
2+
# build.
3+
4+
# First, retrieve wasi-sdk:
5+
6+
FROM ubuntu:18.04 AS builder
7+
WORKDIR /
8+
RUN apt update && apt install -y wget
9+
10+
# Download and extract wasi-sdk.
11+
RUN wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
12+
RUN tar xvf wasi-sdk-19.0-linux.tar.gz
13+
14+
# Second, compile the benchmark to Wasm.
15+
16+
FROM ubuntu:18.04
17+
WORKDIR /
18+
COPY --from=builder /wasi-sdk-19.0 /wasi-sdk-19.0/
19+
20+
# Set common env vars.
21+
ENV CC=/wasi-sdk-19.0/bin/clang
22+
ENV CXX=/wasi-sdk-19.0/bin/clang++
23+
ENV LD=/wasi-sdk-19.0/bin/lld
24+
ENV CFLAGS=--sysroot=/wasi-sdk-19.0/share/wasi-sysroot
25+
ENV CXXFLAGS=--sysroot=/wasi-sdk-19.0/share/wasi-sysroot
26+
ENV PATH /wasi-sdk-19.0
27+
28+
# Compile `benchmark.c` to `./benchmark.wasm`.
29+
COPY benchmark.c .
30+
COPY sightglass.h .
31+
WORKDIR /benchmark
32+
RUN $CC $CFLAGS ../benchmark.c -O3 -g -I.. -o benchmark.wasm
33+
# We output the Wasm file to the `/benchmark` directory, where the client
34+
# expects it.

benchmarks/README.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Candidate Benchmark Programs
2+
3+
This directory contains the candidate programs for the benchmark suite. They are
4+
candidates, not officially part of the suite yet, because we [intend][rfc] to
5+
record various metrics about the programs and then run a principal component
6+
analysis to find a representative subset of candidates that doesn't contain
7+
effectively duplicate workloads.
8+
9+
[rfc]: https://github.com/bytecodealliance/rfcs/pull/4
10+
11+
## Building
12+
13+
Build an individual benchmark program via:
14+
15+
```
16+
$ ./build.sh path/to/benchmark/dir/
17+
```
18+
19+
Build all benchmark programs by running:
20+
21+
```
22+
$ ./build-all.sh
23+
```
24+
25+
## Minimal Technical Requirements
26+
27+
In order for the benchmark runner to successfully execute a Wasm program and
28+
record its execution, it must:
29+
30+
* Export a `_start` function of type `[] -> []`.
31+
32+
* Import `bench.start` and `bench.end` functions, both of type `[] -> []`.
33+
34+
* Call `bench.start` exactly once during the execution of its `_start`
35+
function. This is when the benchmark runner will start recording execution
36+
time and performance counters.
37+
38+
* Call `bench.end` exactly once during execution of its `_start` function, after
39+
`bench.start` has already been called. This is when the benchmark runner will
40+
stop recording execution time and performance counters.
41+
42+
* Provide reproducible builds via Docker (see [`build.sh`](./build.sh)).
43+
44+
* Be located in a `sightglass/benchmarks/$BENCHMARK_NAME` directory. Typically
45+
the benchmark is named `benchmark.wasm`, but benchmarks with multiple files
46+
should use names like `<benchmark name>-<subtest name>.wasm` (e.g.,
47+
`libsodium-chacha20.wasm`).
48+
49+
* Input workloads must be files that live in the same directory as the `.wasm`
50+
benchmark program. The benchmark program is run within the directory where it
51+
lives on the filesystem, with that directory pre-opened in WASI. The workload
52+
must be read via a relative file path.
53+
54+
If, for example, the benchmark processes JSON input, then its input workload
55+
should live at `sightglass/benchmarks/$BENCHMARK_NAME/input.json`, and it
56+
should open that file as `"./input.json"`.
57+
58+
* Define the expected `stdout` output in a `./<benchmark name>.stdout.expected`
59+
sibling file located next to the `benchmark.wasm` file (e.g.,
60+
`benchmark.stdout.expected`). The runner will assert that the actual
61+
execution's output matches the expectation.
62+
63+
* Define the expected `stderr` output in a `./<benchmark name>.stderr.expected`
64+
sibling file located next to the `benchmark.wasm` file. The runner will assert
65+
that the actual execution's output matches the expectation.
66+
67+
Many of the above requirements can be checked by running the `.wasm` file
68+
through the `validate` command:
69+
70+
```
71+
$ cargo run -- validate path/to/benchmark.wasm
72+
```
73+
74+
## Compatibility Requirements for Native Execution
75+
76+
Sightglass can also measure the performance of a subset of benchmarks compiled
77+
to native code (i.e., not WebAssembly). To compile these benchmarks without
78+
changing their source code, this involves a delicate interface with the [native
79+
engine] with some additional requirements beyond the [Minimal Technical
80+
Requirements] noted above:
81+
82+
[native engine]: ../engines/native
83+
[Minimal Technical Requirements]: #minimal-technical-requirements
84+
85+
* Generate an ELF shared library linked to the [native engine] shared library to
86+
provide definitions for `bench_start` and `bench_end`.
87+
88+
* Rename the `main` function to `native_entry`. For C- and C++-based source this
89+
can be done with a simple define directive passed to `cc` (e.g.,
90+
`-Dmain=native_entry`).
91+
92+
* Provide reproducible builds via a `Dockerfile.native` file (see
93+
[`build-native.sh`](./build-native.sh)).
94+
95+
Note that support for native execution is optional: adding a WebAssembly
96+
benchmark does not imply the need to support its native equivalent &mdash; CI
97+
will not fail if it is not included.
98+
99+
## Additional Requirements
100+
101+
> Note: these requirements are lifted directly from the [the benchmarking
102+
> RFC][rfc].
103+
104+
In addition to the minimal technical requirements, for a benchmark program to be
105+
useful to Wasmtime and Cranelift developers, it should additionally meet the
106+
following requirements:
107+
108+
* Candidates should be real, widely used programs, or at least extracted kernels
109+
of such programs. These programs are ideally taken from domains where Wasmtime
110+
and Cranelift are currently used, or domains where they are intended to be a
111+
good fit (e.g. serverless compute, game plugins, client Web applications,
112+
server Web applications, audio plugins, etc.).
113+
114+
* A candidate program must be deterministic (modulo Wasm nondeterminism like
115+
`memory.grow` failure).
116+
117+
* A candidate program must have two associated input workloads: one small and
118+
one large. The small workload may be used by developers locally to get quick,
119+
ballpark numbers for whether further investment in an optimization is worth
120+
it, without waiting for the full, thorough benchmark suite to complete.
121+
122+
* Each workload must have an expected result, so that we can validate executions
123+
and avoid accepting "fast" but incorrect results.
124+
125+
* Compiling and instantiating the candidate program and then executing its
126+
workload should take *roughly* one to six seconds total.
127+
128+
> Napkin math: We want the full benchmark to run in a reasonable amount of
129+
> time, say twenty to thirty minutes, and we want somewhere around ten to
130+
> twenty programs altogether in the benchmark suite to balance diversity,
131+
> simplicity, and time spent in execution versus compilation and
132+
> instantiation. Additionally, for good statistical analyses, we need *at
133+
> least* 30 samples (ideally more like 100) from each benchmark program. That
134+
> leaves an average of about one to six seconds for each benchmark program to
135+
> compile, instantiate, and execute the workload.
136+
137+
* Inputs should be given through I/O and results reported through I/O. This
138+
ensures that the compiler cannot optimize the benchmark program away.
139+
140+
* Candidate programs should only import WASI functions. They should not depend
141+
on any other non-standard imports, hooks, or runtime environment.
142+
143+
* Candidate programs must be open source under a license that allows
144+
redistributing, modifying and redistributing modified versions. This makes
145+
distributing the benchmark easy, allows us to rebuild Wasm binaries as new
146+
versions are released, and lets us do source-level analysis of benchmark
147+
programs when necessary.
148+
149+
* Repeated executions of a candidate program must yield independent samples
150+
(ignoring priming Wasmtime's code cache). If the execution times keep taking
151+
longer and longer, or exhibit harmonics, they are not independent and this can
152+
invalidate any statistical analyses of the results we perform. We can easily
153+
check for this property with either [the chi-squared
154+
test](https://en.wikipedia.org/wiki/Chi-squared_test) or [Fisher's exact
155+
test](https://en.wikipedia.org/wiki/Fisher%27s_exact_test).
156+
157+
* The corpus of candidates should include programs that use a variety of
158+
languages, compilers, and toolchains.

0 commit comments

Comments
 (0)