Skip to content

Commit 04d438d

Browse files
committed
[GR-67830] Add distance function SIMD benchmarks to GraalWasm CI.
PullRequest: graal/21539
2 parents f282ecd + 38d567b commit 04d438d

File tree

15 files changed

+106
-42
lines changed

15 files changed

+106
-42
lines changed

ci/common.jsonnet

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,24 @@ local common_json = import "../common.json";
323323
},
324324
},
325325

326+
wasm_ol8:: {
327+
downloads+: {
328+
WABT_DIR: {name: 'wabt', version: '1.0.36-ol8', platformspecific: true},
329+
},
330+
environment+: {
331+
WABT_DIR: '$WABT_DIR/bin',
332+
},
333+
},
334+
335+
emsdk_ol8:: {
336+
downloads+: {
337+
EMSDK_DIR: {name: 'emsdk', version: '4.0.10', platformspecific: true},
338+
},
339+
environment+: {
340+
EMCC_DIR: '$EMSDK_DIR/upstream/emscripten/'
341+
}
342+
},
343+
326344
fastr:: {
327345
# Note: On both Linux and MacOS, FastR depends on the gnur module and on gfortran
328346
# of a specific version (4.8.5 on Linux, 10.2.0 on MacOS)

wasm/ci/ci.jsonnet

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ jdks + wasm_common +
2828
$.jdkLatest + platform + $.tier3 + $.gate_graalwasm_full + {environment+: {GATE_TAGS: 'build,wasmtest'}} + {name: 'gate-graalwasm-unittest' + self.name_suffix}
2929
for platform in [$.linux_aarch64, $.windows_amd64, $.darwin_aarch64]
3030
] + [
31-
$.jdkLatest + $.linux_amd64 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmextratest'}} + {name: 'gate-graalwasm-extra-unittest' + self.name_suffix},
32-
$.jdkLatest + $.linux_amd64 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmbenchtest'}} + {name: 'gate-graalwasm-benchtest' + self.name_suffix},
31+
$.jdkLatest + $.linux_amd64_ol8 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmextratest'}} + {name: 'gate-graalwasm-extra-unittest' + self.name_suffix},
32+
$.jdkLatest + $.linux_amd64_ol8 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmbenchtest'}} + {name: 'gate-graalwasm-benchtest' + self.name_suffix},
3333

34-
$.jdkLatest + $.linux_amd64 + $.weekly + $.gate_graalwasm_coverage + tools_java_home + {name: 'weekly-graalwasm-coverage' + self.name_suffix},
34+
$.jdkLatest + $.linux_amd64_ol8 + $.weekly + $.gate_graalwasm_coverage + tools_java_home + {name: 'weekly-graalwasm-coverage' + self.name_suffix},
3535

3636
# Benchmark jobs.
37-
$.jdkLatest + $.linux_amd64 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
37+
$.jdkLatest + $.linux_amd64_ol8 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
3838
name: 'bench-graalwasm-c-micro' + self.name_suffix,
3939
environment+: {
4040
BENCH_RUNNER: 'run-c-micro-benchmarks',
@@ -43,7 +43,7 @@ jdks + wasm_common +
4343
},
4444
},
4545

46-
$.jdkLatest + $.linux_amd64 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
46+
$.jdkLatest + $.linux_amd64_ol8 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
4747
name: 'bench-graalwasm-wat-micro' + self.name_suffix,
4848
environment+: {
4949
BENCH_RUNNER: 'run-wat-micro-benchmarks',

wasm/ci/ci_common/common.jsonnet

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ local graal_suite_root = root_ci.graal_suite_root;
6767
},
6868

6969
linux_amd64:: common.linux_amd64 + self.linux_common,
70+
linux_amd64_ol8:: common.linux_amd64_ol8 + self.linux_common,
7071
linux_aarch64:: common.linux_aarch64 + self.linux_common,
7172

7273
darwin_aarch64:: common.darwin_aarch64,
@@ -78,15 +79,6 @@ local graal_suite_root = root_ci.graal_suite_root;
7879

7980
windows_amd64:: common.windows_amd64 + self.windows_common,
8081

81-
emsdk:: {
82-
downloads+: {
83-
EMSDK_DIR: {name: 'emsdk', version: '1.39.13', platformspecific: true},
84-
},
85-
environment+: {
86-
EMCC_DIR: '$EMSDK_DIR/emscripten/master/'
87-
}
88-
},
89-
9082
ocaml_dune:: {
9183
downloads+: {
9284
OCAML_DIR: {name: 'ocaml-dune', version: '3.16.1', platformspecific: true},
@@ -193,7 +185,7 @@ local graal_suite_root = root_ci.graal_suite_root;
193185
},
194186

195187
eclipse_jdt :: common.deps.pylint + common.deps.eclipse + common.deps.jdt,
196-
wabt_emsdk :: common.deps.wasm + self.emsdk,
197-
wabt_emsdk_ocamlbuild :: common.deps.wasm + self.emsdk + self.ocaml_dune,
188+
wabt_emsdk :: common.deps.wasm_ol8 + common.deps.emsdk_ol8,
189+
wabt_emsdk_ocamlbuild :: common.deps.wasm_ol8 + common.deps.emsdk_ol8 + self.ocaml_dune,
198190

199191
}

wasm/docs/contributor/TestsAndBenchmarks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ To compile these programs, you will need to install additional dependencies on y
5454
To build these additional tests and benchmarks, you need to:
5555
5656
1. Install the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html).
57-
We currently test against Emscripten **1.39.13**.
57+
We currently test against Emscripten **4.0.10**.
5858
```bash
5959
$ cd [preferred emsdk install location]
6060
@@ -129,7 +129,7 @@ The benchmarks are kept in the `src/com.oracle.truffle.wasm.benchcases` MX proje
129129
For the benchmarks to run, `NODE_DIR` has to be set. You can use the node version that is part of Emscripten, for example:
130130

131131
```bash
132-
$ export NODE_DIR=[path to emsdk]/node/14.15.5_64bit/bin
132+
$ export NODE_DIR=[path to emsdk]/node/22.16.0_64bit/bin
133133
```
134134

135135
After building the additional benchmarks, as described in the last section, they can be executed as follows:

wasm/mx.wasm/mx_wasm.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ def processDeps(self, deps):
220220
"_benchmarkSetupEach",
221221
"_benchmarkTeardownEach",
222222
"_benchmarkRun",
223-
"_main"
224223
]
225224

226225

@@ -446,6 +445,17 @@ def __str__(self):
446445
def benchmark_methods(self):
447446
return benchmark_methods
448447

448+
def test_methods(self, opts_path):
449+
if not os.path.isfile(opts_path):
450+
return []
451+
with open(opts_path) as opts_file:
452+
for line in opts_file:
453+
line = line.strip()
454+
if line.startswith("entry-point"):
455+
_, value = line.split("=", 1)
456+
return ['_' + value.strip()]
457+
return []
458+
449459
def build(self):
450460
source_dir = self.subject.getSourceDir()
451461
output_dir = self.subject.getOutputDir()
@@ -469,9 +479,7 @@ def build(self):
469479
include_flags = []
470480
if hasattr(self.project, "includeset"):
471481
include_flags = ["-I", os.path.join(_suite.dir, "includes", self.project.includeset)]
472-
emcc_flags = ["-s", "EXIT_RUNTIME=1", "-s", "STANDALONE_WASM", "-s", "WASM_BIGINT"] + cc_flags
473-
if self.project.isBenchmarkProject():
474-
emcc_flags = emcc_flags + ["-s", "EXPORTED_FUNCTIONS=" + str(self.benchmark_methods()).replace("'", "\"") + ""]
482+
emcc_flags = ["-s", "STANDALONE_WASM", "-s", "WASM_BIGINT"] + cc_flags
475483
subdir_program_names = defaultdict(lambda: [])
476484
for root, filename in self.subject.getProgramSources():
477485
if filename.startswith("_"):
@@ -489,12 +497,27 @@ def build(self):
489497
timestampedOutput = mx.TimeStampFile(output_wasm_path)
490498
mustRebuild = timestampedSource.isNewerThan(timestampedOutput) or not timestampedOutput.exists()
491499

500+
source_cc_flags = []
501+
native_bench = True
502+
if filename.endswith(".c"):
503+
with open(source_path) as f:
504+
source_file = f.read()
505+
for flags in re.findall(r'//\s*CFLAGS\s*=\s*(.*)\n', source_file):
506+
source_cc_flags.extend(flags.split())
507+
native_bench_option = re.search(r'//\s*NATIVE_BENCH\s*=\s*(.*)\n', source_file)
508+
if native_bench_option:
509+
native_bench = native_bench_option.group(1).lower() == "true"
510+
492511
# Step 1: build the .wasm binary.
493512
if mustRebuild:
494513
if filename.endswith(".c"):
514+
if self.project.isBenchmarkProject():
515+
emcc_export_flags = ["-s", "EXPORTED_FUNCTIONS=" + str(self.benchmark_methods()).replace("'", "\"") + ""]
516+
else:
517+
emcc_export_flags = ["-s", "EXPORTED_FUNCTIONS=" + str(self.test_methods(os.path.join(root, basename + ".opts"))).replace("'", "\"") + ""]
495518
# This generates both a js file and a wasm file.
496519
# See https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone
497-
build_cmd_line = [emcc_cmd] + emcc_flags + [source_path, "-o", output_js_path] + include_flags
520+
build_cmd_line = [emcc_cmd] + emcc_flags + emcc_export_flags + source_cc_flags + [source_path, "-o", output_js_path] + include_flags
498521
if mx.run(build_cmd_line, nonZeroIsFatal=False) != 0:
499522
mx.abort("Could not build the wasm-only output of " + filename + " with emcc.")
500523
elif filename.endswith(".wat"):
@@ -533,11 +556,11 @@ def build(self):
533556

534557
# Step 5: if this is a benchmark project, create native binaries too.
535558
if mustRebuild:
536-
if filename.endswith(".c"):
559+
if filename.endswith(".c") and native_bench:
537560
mx_util.ensure_dir_exists(os.path.join(output_dir, subdir, NATIVE_BENCH_DIR))
538561
output_path = os.path.join(output_dir, subdir, NATIVE_BENCH_DIR, mx.exe_suffix(basename))
539562
link_flags = ["-lm"]
540-
gcc_cmd_line = [gcc_cmd] + cc_flags + [source_path, "-o", output_path] + include_flags + link_flags
563+
gcc_cmd_line = [gcc_cmd] + cc_flags + source_cc_flags + [source_path, "-o", output_path] + include_flags + link_flags
541564
if mx.run(gcc_cmd_line, nonZeroIsFatal=False) != 0:
542565
mx.abort("Could not build the native binary of " + filename + ".")
543566
os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
@@ -642,10 +665,10 @@ def emscripten_init(args):
642665
config_path = os.path.join(os.getcwd(), args.config_path)
643666
emsdk_path = args.emsdk_path
644667

645-
llvm_root = os.path.join(emsdk_path, "llvm", "git", "build_master_64", "bin")
646-
binaryen_root = os.path.join(emsdk_path, "binaryen", "master_64bit_binaryen")
647-
emscripten_root = os.path.join(emsdk_path, "emscripten", "master")
648-
node_js = os.path.join(emsdk_path, "node", "12.9.1_64bit", "bin", "node")
668+
llvm_root = os.path.join(emsdk_path, "upstream", "bin")
669+
binaryen_root = os.path.join(emsdk_path, "binaryen", "main_64bit_binaryen")
670+
emscripten_root = os.path.join(emsdk_path, "upstream", "emscripten")
671+
node_js = os.path.join(emsdk_path, "node", "22.16.0_64bit", "bin", "node")
649672

650673
def find_executable(exe_name):
651674
for root, _, files in os.walk(args.emsdk_path):
@@ -666,7 +689,7 @@ def find_executable(exe_name):
666689
llvm_root = os.path.join(emsdk_path, "upstream", "bin")
667690
binaryen_root = os.path.join(emsdk_path, "upstream", "lib")
668691
emscripten_root = os.path.join(emsdk_path, "upstream", "emscripten")
669-
node_js = os.path.join(emsdk_path, "node", "14.15.5_64bit", "bin", "node")
692+
node_js = os.path.join(emsdk_path, "node", "22.16.0_64bit", "bin", "node")
670693

671694
mx.log("Generating Emscripten configuration...")
672695
mx.log("Config file path: " + str(config_path))

wasm/mx.wasm/mx_wasm_benchmark.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def run_vm(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False):
166166
try:
167167
tmp_dir = self.extract_jar_to_tempdir(jar, suite, benchmark)
168168
node_cmd = os.path.join(node_dir, "node")
169-
node_cmd_line = [node_cmd, "--experimental-wasm-bigint", os.path.join(tmp_dir, "bench", suite, benchmark + ".js")]
169+
node_cmd_line = [node_cmd, os.path.join(tmp_dir, "bench", suite, benchmark + ".js")]
170170
mx.log("Running benchmark " + benchmark + " with node.")
171171
mx.run(node_cmd_line, cwd=tmp_dir, out=out, err=err, nonZeroIsFatal=nonZeroIsFatal)
172172
finally:

wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,21 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
216216
}
217217

218218
final WasmContext wasmContext = WasmContext.get(null);
219-
final Value mainFunction = findMain(moduleInstances);
220219
final List<WasmInstance> instanceList = moduleInstances.stream().map(i -> toWasmInstance(i)).toList();
221220

221+
final Value testFunction;
222+
final String entryPoint = testCase.options().getProperty("entry-point");
223+
if (entryPoint != null) {
224+
String testModuleName = testCase.name();
225+
Value testModule = context.getBindings(WasmLanguage.ID).getMember(testModuleName).getMember("exports");
226+
testFunction = testModule.getMember(entryPoint);
227+
if (testFunction == null) {
228+
throw new RuntimeException(String.format("Entry point %s not found in test module %s.", entryPoint, testCase.name()));
229+
}
230+
} else {
231+
testFunction = findMain(moduleInstances);
232+
}
233+
222234
resetStatus(System.out, phaseIcon, phaseLabel);
223235

224236
final String argString = testCase.options().getProperty("argument");
@@ -228,7 +240,7 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
228240
for (int i = 0; i != iterations; ++i) {
229241
try {
230242
testOut.reset();
231-
final Value result = arg == null ? mainFunction.execute() : mainFunction.execute(arg);
243+
final Value result = arg == null ? testFunction.execute() : testFunction.execute(arg);
232244
WasmCase.validateResult(testCase.data().resultValidator(), result, testOut);
233245
} catch (PolyglotException e) {
234246
// If no exception is expected and the program returns with success exit status,
@@ -341,6 +353,7 @@ private WasmTestStatus runTestCase(WasmCase testCase, Engine sharedEngine) {
341353

342354
contextBuilder.option("wasm.Builtins", includedExternalModules());
343355
contextBuilder.option("wasm.WasiConstantRandomGet", "true");
356+
contextBuilder.option("wasm.EvalReturnsInstance", "true");
344357
final String commandLineArgs = testCase.options().getProperty("command-line-args");
345358
if (commandLineArgs != null) {
346359
// The first argument is the program name. We set it to the empty string in tests.
@@ -415,7 +428,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
415428
interpreterIterations = Math.min(interpreterIterations, 1);
416429
}
417430

418-
context = contextBuilder.options(getInterpreted()).option("wasm.EvalReturnsInstance", "true").build();
431+
context = contextBuilder.options(getInterpreted()).build();
419432
runInContext(testCase, context, sources, interpreterIterations, PHASE_INTERPRETER_ICON, "interpreter", testOut);
420433

421434
if (isFallbackRuntime()) {
@@ -429,7 +442,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
429442
if (WasmTestOptions.COVERAGE_MODE) {
430443
syncNoinlineIterations = Math.min(syncNoinlineIterations, 1);
431444
}
432-
context = contextBuilder.options(getSyncCompiledNoInline()).option("wasm.EvalReturnsInstance", "true").build();
445+
context = contextBuilder.options(getSyncCompiledNoInline()).build();
433446
runInContext(testCase, context, sources, syncNoinlineIterations, PHASE_SYNC_NO_INLINE_ICON, "sync,no-inl", testOut);
434447

435448
// Run in synchronous compiled mode, with inlining turned on.
@@ -439,15 +452,15 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
439452
if (WasmTestOptions.COVERAGE_MODE) {
440453
syncInlineIterations = Math.min(syncInlineIterations, 1);
441454
}
442-
context = contextBuilder.options(getSyncCompiledWithInline()).option("wasm.EvalReturnsInstance", "true").build();
455+
context = contextBuilder.options(getSyncCompiledWithInline()).build();
443456
runInContext(testCase, context, sources, syncInlineIterations, PHASE_SYNC_INLINE_ICON, "sync,inl", testOut);
444457

445458
// Run with normal, asynchronous compilation.
446459
int asyncIterations = Integer.parseInt(testCase.options().getProperty("async-iterations", String.valueOf(DEFAULT_ASYNC_ITERATIONS)));
447460
if (WasmTestOptions.COVERAGE_MODE) {
448461
asyncIterations = Math.min(asyncIterations, 1);
449462
}
450-
context = contextBuilder.options(getAsyncCompiled()).option("wasm.EvalReturnsInstance", "true").build();
463+
context = contextBuilder.options(getAsyncCompiled()).build();
451464
runInContext(testCase, context, sources, asyncIterations, PHASE_ASYNC_ICON, "async,multi", testOut);
452465
} else {
453466
int asyncSharedIterations = testCase.options().containsKey("async-iterations") && !testCase.options().containsKey("async-shared-iterations")
@@ -456,7 +469,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
456469
if (WasmTestOptions.COVERAGE_MODE) {
457470
asyncSharedIterations = Math.min(asyncSharedIterations, 1);
458471
}
459-
context = contextBuilder.option("wasm.EvalReturnsInstance", "true").build();
472+
context = contextBuilder.build();
460473
runInContext(testCase, context, sources, asyncSharedIterations, PHASE_SHARED_ENGINE_ICON, "async,shared", testOut);
461474
}
462475
}

wasm/src/org.graalvm.wasm.testcases/src/test/c/allocate-string.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#include <stdlib.h>
4343
#include <string.h>
4444

45-
int main() {
45+
int test() {
4646
char staticMemory[100];
4747
char *dynamicMemory;
4848

@@ -59,3 +59,7 @@ int main() {
5959
printf("2nd: %s\n", dynamicMemory);
6060
return 0;
6161
}
62+
63+
int main() {
64+
return test();
65+
}

wasm/src/org.graalvm.wasm.testcases/src/test/c/allocate-string.opts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ interpreter-iterations = 2
33
sync-noinline-iterations = 0
44
sync-inline-iterations = 0
55
async-iterations = 2000
6+
entry-point = test

wasm/src/org.graalvm.wasm.testcases/src/test/c/collatz.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ int collatz(int n) {
5656

5757
int number = 127;
5858

59-
int main() {
59+
int test() {
6060
printf("%d\n", collatz(number));
6161
return 0;
6262
}
6363

64+
int main() {
65+
return test();
66+
}

0 commit comments

Comments
 (0)