Skip to content

Commit 36c672b

Browse files
Refine benchmark suite (#203)
* Add several benchmark suite to find our bottleneck * Perform benchmark with release configuration * Add primitive conversion benchmark cases
1 parent 8478665 commit 36c672b

File tree

7 files changed

+111
-23
lines changed

7 files changed

+111
-23
lines changed

IntegrationTests/TestSuites/Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ let package = Package(
3535
.product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
3636
]
3737
),
38-
.target(name: "BenchmarkTests", dependencies: ["JavaScriptKit"]),
38+
.target(name: "BenchmarkTests", dependencies: ["JavaScriptKit", "CHelpers"]),
3939
]
4040
)

IntegrationTests/TestSuites/Sources/BenchmarkTests/Benchmark.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ class Benchmark {
88
let title: String
99
let runner = JSObject.global.benchmarkRunner.function!
1010

11-
func testSuite(_ name: String, _ body: @escaping () -> Void) {
11+
func testSuite(_ name: String, _ body: @escaping (Int) -> Void) {
1212
let jsBody = JSClosure { arguments -> JSValue in
1313
let iteration = Int(arguments[0].number!)
14-
for _ in 0 ..< iteration { body() }
14+
body(iteration)
1515
return .undefined
1616
}
1717
runner("\(title)/\(name)", jsBody)
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,75 @@
11
import JavaScriptKit
2+
import CHelpers
23

34
let serialization = Benchmark("Serialization")
45

6+
let noopFunction = JSObject.global.noopFunction.function!
7+
8+
serialization.testSuite("JavaScript function call through Wasm import") { n in
9+
for _ in 0 ..< n {
10+
benchmark_helper_noop()
11+
}
12+
}
13+
14+
serialization.testSuite("JavaScript function call through Wasm import with int") { n in
15+
for _ in 0 ..< n {
16+
benchmark_helper_noop_with_int(42)
17+
}
18+
}
19+
20+
serialization.testSuite("JavaScript function call from Swift") { n in
21+
for _ in 0 ..< n {
22+
_ = noopFunction()
23+
}
24+
}
25+
526
let swiftInt: Double = 42
6-
serialization.testSuite("Swift Int to JavaScript") {
27+
serialization.testSuite("Swift Int to JavaScript with assignment") { n in
28+
let jsNumber = JSValue.number(swiftInt)
29+
let object = JSObject.global
30+
let key = JSString("numberValue")
31+
for _ in 0 ..< n {
32+
object[key] = jsNumber
33+
}
34+
}
35+
36+
serialization.testSuite("Swift Int to JavaScript with call") { n in
737
let jsNumber = JSValue.number(swiftInt)
38+
for _ in 0 ..< n {
39+
_ = noopFunction(jsNumber)
40+
}
41+
}
42+
43+
serialization.testSuite("JavaScript Number to Swift Int") { n in
844
let object = JSObject.global
9-
for i in 0 ..< 100 {
10-
object["numberValue\(i)"] = jsNumber
45+
let key = JSString("jsNumber")
46+
for _ in 0 ..< n {
47+
_ = object[key].number
1148
}
1249
}
1350

1451
let swiftString = "Hello, world"
15-
serialization.testSuite("Swift String to JavaScript") {
52+
serialization.testSuite("Swift String to JavaScript with assignment") { n in
1653
let jsString = JSValue.string(swiftString)
1754
let object = JSObject.global
18-
for i in 0 ..< 100 {
19-
object["stringValue\(i)"] = jsString
55+
let key = JSString("stringValue")
56+
for _ in 0 ..< n {
57+
object[key] = jsString
58+
}
59+
}
60+
61+
serialization.testSuite("Swift String to JavaScript with call") { n in
62+
let jsString = JSValue.string(swiftString)
63+
for _ in 0 ..< n {
64+
_ = noopFunction(jsString)
65+
}
66+
}
67+
68+
serialization.testSuite("JavaScript String to Swift String") { n in
69+
let object = JSObject.global
70+
let key = JSString("jsString")
71+
for _ in 0 ..< n {
72+
_ = object[key].string
2073
}
2174
}
2275

@@ -25,8 +78,8 @@ let objectHeap = Benchmark("Object heap")
2578
let global = JSObject.global
2679
let Object = global.Object.function!
2780
global.objectHeapDummy = .object(Object.new())
28-
objectHeap.testSuite("Increment and decrement RC") {
29-
for _ in 0 ..< 100 {
81+
objectHeap.testSuite("Increment and decrement RC") { n in
82+
for _ in 0 ..< n {
3083
_ = global.objectHeapDummy
3184
}
3285
}

IntegrationTests/TestSuites/Sources/CHelpers/include/helpers.h

+5
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@
33
/// @param pages Number of memory pages to increase memory by.
44
int growMemory(int pages);
55

6+
__attribute__((__import_module__("benchmark_helper"), __import_name__("noop")))
7+
extern void benchmark_helper_noop(void);
8+
9+
__attribute__((__import_module__("benchmark_helper"), __import_name__("noop_with_int")))
10+
extern void benchmark_helper_noop_with_int(int);

IntegrationTests/bin/benchmark-tests.js

+36-10
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,67 @@
11
const { startWasiTask } = require("../lib");
22
const { performance } = require("perf_hooks");
33

4+
const SAMPLE_ITERATION = 1000000
5+
46
global.benchmarkRunner = function (name, body) {
57
console.log(`Running '${name}' ...`);
68
const startTime = performance.now();
7-
body(5000);
9+
body(SAMPLE_ITERATION);
810
const endTime = performance.now();
911
console.log("done " + (endTime - startTime) + " ms");
1012
};
1113

14+
global.noopFunction = function () {}
15+
global.jsNumber = 42
16+
global.jsString = "myString"
17+
1218
class JSBenchmark {
1319
constructor(title) {
1420
this.title = title;
1521
}
1622
testSuite(name, body) {
1723
benchmarkRunner(`${this.title}/${name}`, (iteration) => {
18-
for (let idx = 0; idx < iteration; idx++) {
19-
body();
20-
}
24+
body(iteration);
2125
});
2226
}
2327
}
2428

2529
const serialization = new JSBenchmark("Serialization");
26-
serialization.testSuite("Write JavaScript number directly", () => {
30+
serialization.testSuite("Call JavaScript function directly", (n) => {
31+
for (let idx = 0; idx < n; idx++) {
32+
global.noopFunction()
33+
}
34+
});
35+
36+
serialization.testSuite("Assign JavaScript number directly", (n) => {
2737
const jsNumber = 42;
2838
const object = global;
29-
for (let idx = 0; idx < 100; idx++) {
30-
object["numberValue" + idx] = jsNumber;
39+
const key = "numberValue"
40+
for (let idx = 0; idx < n; idx++) {
41+
object[key] = jsNumber;
3142
}
3243
});
3344

34-
serialization.testSuite("Write JavaScript string directly", () => {
45+
serialization.testSuite("Call with JavaScript number directly", (n) => {
46+
const jsNumber = 42;
47+
for (let idx = 0; idx < n; idx++) {
48+
global.noopFunction(jsNumber)
49+
}
50+
});
51+
52+
serialization.testSuite("Write JavaScript string directly", (n) => {
3553
const jsString = "Hello, world";
3654
const object = global;
37-
for (let idx = 0; idx < 100; idx++) {
38-
object["stringValue" + idx] = jsString;
55+
const key = "stringValue"
56+
for (let idx = 0; idx < n; idx++) {
57+
object[key] = jsString;
58+
}
59+
});
60+
61+
serialization.testSuite("Call with JavaScript string directly", (n) => {
62+
const jsString = "Hello, world";
63+
for (let idx = 0; idx < n; idx++) {
64+
global.noopFunction(jsString)
3965
}
4066
});
4167

IntegrationTests/lib.js

+4
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ const startWasiTask = async (wasmPath, wasiConstructor = selectWASIBackend()) =>
9797
let { instance } = await WebAssembly.instantiate(wasmBinary, {
9898
wasi_snapshot_preview1: wasi.wasiImport,
9999
javascript_kit: swift.importObjects(),
100+
benchmark_helper: {
101+
noop: () => {},
102+
noop_with_int: (_) => {},
103+
}
100104
});
101105

102106
swift.setInstance(instance);

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ test:
2020

2121
.PHONY: benchmark_setup
2222
benchmark_setup:
23-
cd IntegrationTests && make benchmark_setup
23+
cd IntegrationTests && CONFIGURATION=release make benchmark_setup
2424

2525
.PHONY: run_benchmark
2626
run_benchmark:
27-
cd IntegrationTests && make -s run_benchmark
27+
cd IntegrationTests && CONFIGURATION=release make -s run_benchmark
2828

2929
.PHONY: perf-tester
3030
perf-tester:

0 commit comments

Comments
 (0)