json-as 1.1.26 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/benchmark.yml +72 -0
- package/.prettierrc.json +1 -0
- package/CHANGELOG.md +4 -0
- package/README.md +44 -59
- package/assembly/__benches__/abc.bench.ts +5 -9
- package/assembly/__benches__/large.bench.ts +114 -120
- package/assembly/__benches__/lib/bench.ts +44 -1
- package/assembly/__benches__/medium.bench.ts +108 -29
- package/assembly/__benches__/small.bench.ts +28 -18
- package/assembly/__benches__/throughput.ts +172 -0
- package/assembly/__benches__/vec3.bench.ts +8 -3
- package/assembly/__tests__/string.spec.ts +4 -0
- package/assembly/deserialize/simple/arbitrary.ts +5 -2
- package/assembly/deserialize/simple/object.ts +3 -1
- package/assembly/deserialize/swar/string.ts +62 -62
- package/assembly/index.ts +6 -2
- package/assembly/serialize/simd/string.ts +1 -1
- package/assembly/serialize/swar/number.ts +0 -0
- package/assembly/serialize/swar/string.ts +25 -25
- package/assembly/test.tmp.ts +124 -2
- package/assembly/test.ts +0 -7
- package/bench/abc.bench.ts +6 -8
- package/bench/large.bench.ts +119 -118
- package/bench/lib/bench.d.ts +27 -0
- package/bench/lib/bench.js +53 -0
- package/bench/lib/chart.ts +217 -0
- package/bench/medium.bench.ts +55 -30
- package/bench/runners/assemblyscript.js +6 -1
- package/bench/small.bench.ts +7 -3
- package/bench/throughput.ts +87 -0
- package/bench/tsconfig.json +3 -2
- package/bench/vec3.bench.ts +7 -3
- package/ci/bench/runners/assemblyscript.js +29 -0
- package/ci/run-bench.as.sh +63 -0
- package/lib/as-bs.ts +13 -0
- package/package.json +3 -1
- package/run-bench.as.sh +21 -13
- package/run-bench.js.sh +9 -7
- package/run-tests.sh +34 -14
- package/scripts/build-chart01.ts +38 -0
- package/scripts/build-chart02.ts +38 -0
- package/scripts/build-chart03.ts +139 -0
- package/scripts/build-chart05.ts +47 -0
- package/scripts/generate-as-class.ts +50 -0
- package/scripts/lib/bench-utils.ts +308 -0
- package/transform/lib/index.js +2 -2
- package/transform/lib/index.js.map +1 -1
- package/transform/src/index.ts +2 -2
- package/assembly/__tests__/simd/string.spec.ts +0 -32
- /package/{bench → ci/bench}/lib/bench.ts +0 -0
package/bench/medium.bench.ts
CHANGED
|
@@ -1,43 +1,68 @@
|
|
|
1
|
-
import { bench } from "./lib/bench.js";
|
|
2
|
-
|
|
3
|
-
class
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { bench, blackbox, dumpToFile } from "./lib/bench.js";
|
|
2
|
+
|
|
3
|
+
class UserPreferences {
|
|
4
|
+
theme: string = "dark";
|
|
5
|
+
notifications: boolean = true;
|
|
6
|
+
language: string = "en-US";
|
|
7
|
+
timezone: string = "America/Los_Angeles";
|
|
8
|
+
privacy_level: string = "friends_only";
|
|
9
|
+
two_factor_enabled: boolean = false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class RecentActivity {
|
|
13
|
+
action: string = "";
|
|
14
|
+
timestamp: string = "";
|
|
15
|
+
target: string = "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class MediumAPIResponse {
|
|
19
|
+
id: number = 42;
|
|
20
|
+
username: string = "jairus";
|
|
21
|
+
full_name: string = "Jairus Tanaka";
|
|
22
|
+
email: string = "me@jairus.dev";
|
|
23
|
+
avatar_url: string = "https://avatars.githubusercontent.com/u/123456?v=4";
|
|
24
|
+
bio: string = "I like compilers, elegant algorithms, bare metal, simd, and wasm.";
|
|
25
|
+
website: string = "https://jairus.dev/";
|
|
26
|
+
location: string = "Seattle, WA";
|
|
27
|
+
joined_at: string = "2020-01-15T08:30:00Z";
|
|
28
|
+
is_verified: boolean = true;
|
|
29
|
+
is_premium: boolean = true;
|
|
30
|
+
follower_count: number = 61;
|
|
31
|
+
following_count: number = 39;
|
|
32
|
+
|
|
33
|
+
preferences: UserPreferences = new UserPreferences();
|
|
34
|
+
|
|
35
|
+
tags: string[] = ["typescript", "webassembly", "performance", "rust", "assemblyscript", "json"];
|
|
36
|
+
|
|
37
|
+
recent_activity: RecentActivity[] = [
|
|
38
|
+
{ action: "starred", timestamp: "2025-12-22T10:15:00Z", target: "assemblyscript/json-as" },
|
|
39
|
+
{ action: "commented", timestamp: "2025-12-22T09:42:00Z", target: "issue #142" },
|
|
40
|
+
{ action: "pushed", timestamp: "2025-12-21T23:58:00Z", target: "main branch" },
|
|
41
|
+
{ action: "forked", timestamp: "2025-12-21T18:20:00Z", target: "fast-json-wasm" },
|
|
42
|
+
{ action: "created", timestamp: "2025-12-21T14:10:00Z", target: "new benchmark suite" },
|
|
43
|
+
];
|
|
13
44
|
}
|
|
14
45
|
|
|
15
|
-
const v1
|
|
16
|
-
id: 2,
|
|
17
|
-
name: "Medium Object",
|
|
18
|
-
age: 18,
|
|
19
|
-
email: "me@jairus.dev",
|
|
20
|
-
street: "I don't want to say my street",
|
|
21
|
-
city: "I don't want to say this either",
|
|
22
|
-
state: "It really depends",
|
|
23
|
-
zip: "I forget what it is",
|
|
24
|
-
tags: ["me", "dogs", "mountains", "bar", "foo"],
|
|
25
|
-
};
|
|
46
|
+
const v1 = new MediumAPIResponse();
|
|
26
47
|
|
|
27
|
-
const v2 =
|
|
48
|
+
const v2 = JSON.stringify(v1);
|
|
28
49
|
|
|
29
50
|
bench(
|
|
30
|
-
"Serialize Medium
|
|
51
|
+
"Serialize Medium API Response",
|
|
31
52
|
() => {
|
|
32
|
-
JSON.stringify(v1);
|
|
53
|
+
blackbox(JSON.stringify(v1));
|
|
33
54
|
},
|
|
34
|
-
|
|
55
|
+
500_000,
|
|
56
|
+
v2.length << 1
|
|
35
57
|
);
|
|
58
|
+
dumpToFile("medium", "serialize")
|
|
36
59
|
|
|
37
60
|
bench(
|
|
38
|
-
"Deserialize Medium
|
|
61
|
+
"Deserialize Medium API Response",
|
|
39
62
|
() => {
|
|
40
|
-
JSON.parse(v2);
|
|
63
|
+
blackbox(JSON.parse(v2));
|
|
41
64
|
},
|
|
42
|
-
|
|
65
|
+
500_000,
|
|
66
|
+
v2.length << 1
|
|
43
67
|
);
|
|
68
|
+
dumpToFile("medium", "deserialize")
|
|
@@ -11,6 +11,11 @@ const { exports } = new WebAssembly.Instance(module, {
|
|
|
11
11
|
},
|
|
12
12
|
"Date.now": () => Date.now(),
|
|
13
13
|
"performance.now": () => performance.now(),
|
|
14
|
+
"writeFile": (fileName, data) => {
|
|
15
|
+
fileName = __liftString(fileName)
|
|
16
|
+
data = __liftString(data);
|
|
17
|
+
writeFile(fileName, data);
|
|
18
|
+
}
|
|
14
19
|
},
|
|
15
20
|
});
|
|
16
21
|
|
|
@@ -26,4 +31,4 @@ function __liftString(pointer) {
|
|
|
26
31
|
return string + String.fromCharCode(...memoryU16.subarray(start, end));
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
exports.start();
|
|
34
|
+
exports.start();
|
package/bench/small.bench.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bench } from "./lib/bench.js";
|
|
1
|
+
import { bench, blackbox, dumpToFile } from "./lib/bench.js";
|
|
2
2
|
|
|
3
3
|
class SmallJSON {
|
|
4
4
|
public id!: number;
|
|
@@ -16,15 +16,19 @@ const v2 = '{"id":1,"name":"Small Object","active":true}';
|
|
|
16
16
|
bench(
|
|
17
17
|
"Serialize Small Object",
|
|
18
18
|
() => {
|
|
19
|
-
JSON.stringify(v1);
|
|
19
|
+
blackbox(JSON.stringify(v1));
|
|
20
20
|
},
|
|
21
21
|
16_000_00,
|
|
22
|
+
v2.length << 1
|
|
22
23
|
);
|
|
24
|
+
dumpToFile("small", "serialize")
|
|
23
25
|
|
|
24
26
|
bench(
|
|
25
27
|
"Deserialize Small Object",
|
|
26
28
|
() => {
|
|
27
|
-
JSON.parse(v2);
|
|
29
|
+
blackbox(JSON.parse(v2));
|
|
28
30
|
},
|
|
29
31
|
16_000_00,
|
|
32
|
+
v2.length << 1
|
|
30
33
|
);
|
|
34
|
+
dumpToFile("small", "deserialize")
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { bench, blackbox, dumpToFile } from "./lib/bench";
|
|
2
|
+
|
|
3
|
+
const objSmall = { a: 1 };
|
|
4
|
+
const objMedium = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 };
|
|
5
|
+
const objLarge = Object.fromEntries(Array.from({ length: 100 }, (_, i) => [`key${i}`, i]));
|
|
6
|
+
|
|
7
|
+
const arrSmall = [1, 2, 3];
|
|
8
|
+
const arrMedium = Array.from({ length: 100 }, (_, i) => i);
|
|
9
|
+
const arrLarge = Array.from({ length: 1000 }, (_, i) => i);
|
|
10
|
+
|
|
11
|
+
const strSmall = 'abc';
|
|
12
|
+
const strMedium = 'abcdefghijklmnopqrstuvwxyz'.repeat(10);
|
|
13
|
+
const strLarge = 'abcdefghijklmnopqrstuvwxyz'.repeat(100);
|
|
14
|
+
|
|
15
|
+
const ITERATIONS = 1_000_000;
|
|
16
|
+
|
|
17
|
+
const objSmallStr = JSON.stringify(objSmall);
|
|
18
|
+
const objMediumStr = JSON.stringify(objMedium);
|
|
19
|
+
const objLargeStr = JSON.stringify(objLarge);
|
|
20
|
+
|
|
21
|
+
const arrSmallStr = JSON.stringify(arrSmall);
|
|
22
|
+
const arrMediumStr = JSON.stringify(arrMedium);
|
|
23
|
+
const arrLargeStr = JSON.stringify(arrLarge);
|
|
24
|
+
|
|
25
|
+
const strSmallStr = JSON.stringify(strSmall);
|
|
26
|
+
const strMediumStr = JSON.stringify(strMedium);
|
|
27
|
+
const strLargeStr = JSON.stringify(strLarge);
|
|
28
|
+
|
|
29
|
+
// Objects
|
|
30
|
+
bench('Serialize Small Object', () => blackbox(JSON.stringify(objSmall)), ITERATIONS, objSmallStr.length << 1);
|
|
31
|
+
dumpToFile('small-obj', 'serialize');
|
|
32
|
+
|
|
33
|
+
bench('Serialize Medium Object', () => blackbox(JSON.stringify(objMedium)), ITERATIONS, objMediumStr.length << 1);
|
|
34
|
+
dumpToFile('medium-obj', 'serialize');
|
|
35
|
+
|
|
36
|
+
bench('Serialize Large Object', () => blackbox(JSON.stringify(objLarge)), ITERATIONS, objLargeStr.length << 1);
|
|
37
|
+
dumpToFile('large-obj', 'serialize');
|
|
38
|
+
|
|
39
|
+
// Arrays
|
|
40
|
+
bench('Serialize Small Array', () => blackbox(JSON.stringify(arrSmall)), ITERATIONS, arrSmallStr.length << 1);
|
|
41
|
+
dumpToFile('small-arr', 'serialize');
|
|
42
|
+
|
|
43
|
+
bench('Serialize Medium Array', () => blackbox(JSON.stringify(arrMedium)), ITERATIONS, arrMediumStr.length << 1);
|
|
44
|
+
dumpToFile('medium-arr', 'serialize');
|
|
45
|
+
|
|
46
|
+
bench('Serialize Large Array', () => blackbox(JSON.stringify(arrLarge)), ITERATIONS, arrLargeStr.length << 1);
|
|
47
|
+
dumpToFile('large-arr', 'serialize');
|
|
48
|
+
|
|
49
|
+
// Strings
|
|
50
|
+
bench('Serialize Small String', () => blackbox(JSON.stringify(strSmall)), ITERATIONS, strSmallStr.length << 1);
|
|
51
|
+
dumpToFile('small-str', 'serialize');
|
|
52
|
+
|
|
53
|
+
bench('Serialize Medium String', () => blackbox(JSON.stringify(strMedium)), ITERATIONS, strMediumStr.length << 1);
|
|
54
|
+
dumpToFile('medium-str', 'serialize');
|
|
55
|
+
|
|
56
|
+
bench('Serialize Large String', () => blackbox(JSON.stringify(strLarge)), ITERATIONS, strLargeStr.length << 1);
|
|
57
|
+
dumpToFile('large-str', 'serialize');
|
|
58
|
+
|
|
59
|
+
// Objects
|
|
60
|
+
bench('Deserialize Small Object', () => blackbox(JSON.parse(objSmallStr)), ITERATIONS, objSmallStr.length << 1);
|
|
61
|
+
dumpToFile('small-obj', 'deserialize');
|
|
62
|
+
|
|
63
|
+
bench('Deserialize Medium Object', () => blackbox(JSON.parse(objMediumStr)), ITERATIONS, objMediumStr.length << 1);
|
|
64
|
+
dumpToFile('medium-obj', 'deserialize');
|
|
65
|
+
|
|
66
|
+
bench('Deserialize Large Object', () => blackbox(JSON.parse(objLargeStr)), ITERATIONS, objLargeStr.length << 1);
|
|
67
|
+
dumpToFile('large-obj', 'deserialize');
|
|
68
|
+
|
|
69
|
+
// Arrays
|
|
70
|
+
bench('Deserialize Small Array', () => blackbox(JSON.parse(arrSmallStr)), ITERATIONS, arrSmallStr.length << 1);
|
|
71
|
+
dumpToFile('small-arr', 'deserialize');
|
|
72
|
+
|
|
73
|
+
bench('Deserialize Medium Array', () => blackbox(JSON.parse(arrMediumStr)), ITERATIONS, arrMediumStr.length << 1);
|
|
74
|
+
dumpToFile('medium-arr', 'deserialize');
|
|
75
|
+
|
|
76
|
+
bench('Deserialize Large Array', () => blackbox(JSON.parse(arrLargeStr)), ITERATIONS, arrLargeStr.length << 1);
|
|
77
|
+
dumpToFile('large-arr', 'deserialize');
|
|
78
|
+
|
|
79
|
+
// Strings
|
|
80
|
+
bench('Deserialize Small String', () => blackbox(JSON.parse(strSmallStr)), ITERATIONS, strSmallStr.length << 1);
|
|
81
|
+
dumpToFile('small-str', 'deserialize');
|
|
82
|
+
|
|
83
|
+
bench('Deserialize Medium String', () => blackbox(JSON.parse(strMediumStr)), ITERATIONS, strMediumStr.length << 1);
|
|
84
|
+
dumpToFile('medium-str', 'deserialize');
|
|
85
|
+
|
|
86
|
+
bench('Deserialize Large String', () => blackbox(JSON.parse(strLargeStr)), ITERATIONS, strLargeStr.length << 1);
|
|
87
|
+
dumpToFile('large-str', 'deserialize');
|
package/bench/tsconfig.json
CHANGED
package/bench/vec3.bench.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bench } from "./lib/bench.js";
|
|
1
|
+
import { bench, blackbox, dumpToFile } from "./lib/bench.js";
|
|
2
2
|
|
|
3
3
|
class Vec3 {
|
|
4
4
|
public x!: number;
|
|
@@ -12,15 +12,19 @@ const v2 = '{"x":1,"y":2,"z":3}';
|
|
|
12
12
|
bench(
|
|
13
13
|
"Serialize Vec3",
|
|
14
14
|
() => {
|
|
15
|
-
JSON.stringify(v1);
|
|
15
|
+
blackbox(JSON.stringify(v1));
|
|
16
16
|
},
|
|
17
17
|
16_000_00,
|
|
18
|
+
v2.length << 1
|
|
18
19
|
);
|
|
20
|
+
dumpToFile("vec3", "serialize")
|
|
19
21
|
|
|
20
22
|
bench(
|
|
21
23
|
"Deserialize Vec3",
|
|
22
24
|
() => {
|
|
23
|
-
JSON.parse(v2);
|
|
25
|
+
blackbox(JSON.parse(v2));
|
|
24
26
|
},
|
|
25
27
|
16_000_00,
|
|
28
|
+
v2.length << 1
|
|
26
29
|
);
|
|
30
|
+
dumpToFile("vec3", "deserialize")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const bytes = readbuffer("./build/" + arguments[0]);
|
|
2
|
+
const module = new WebAssembly.Module(bytes);
|
|
3
|
+
let memory = null;
|
|
4
|
+
const { exports } = new WebAssembly.Instance(module, {
|
|
5
|
+
env: {
|
|
6
|
+
abort: (msg, file, line) => {
|
|
7
|
+
console.log("abort: " + __liftString(msg) + " in " + __liftString(file) + ":" + __liftString(line));
|
|
8
|
+
},
|
|
9
|
+
"console.log": (ptr) => {
|
|
10
|
+
console.log(__liftString(ptr));
|
|
11
|
+
},
|
|
12
|
+
"Date.now": () => Date.now(),
|
|
13
|
+
"performance.now": () => performance.now(),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
memory = exports.memory;
|
|
18
|
+
|
|
19
|
+
function __liftString(pointer) {
|
|
20
|
+
if (!pointer) return null;
|
|
21
|
+
const end = (pointer + new Uint32Array(memory.buffer)[(pointer - 4) >>> 2]) >>> 1,
|
|
22
|
+
memoryU16 = new Uint16Array(memory.buffer);
|
|
23
|
+
let start = pointer >>> 1,
|
|
24
|
+
string = "";
|
|
25
|
+
while (end - start > 1024) string += String.fromCharCode(...memoryU16.subarray(start, (start += 1024)));
|
|
26
|
+
return string + String.fromCharCode(...memoryU16.subarray(start, end));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.start();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
RUNTIMES=${RUNTIMES:-"incremental"}
|
|
3
|
+
ENGINES=${ENGINES:-"turbofan"}
|
|
4
|
+
for file in ../assembly/__benches__/*.bench.ts; do
|
|
5
|
+
filename=$(basename -- "$file")
|
|
6
|
+
for runtime in $RUNTIMES; do
|
|
7
|
+
output="./build/${filename%.ts}.${runtime}"
|
|
8
|
+
|
|
9
|
+
npx asc "$file" --transform ../transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --exportStart start || {
|
|
10
|
+
echo "Build failed"
|
|
11
|
+
exit 1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
|
|
15
|
+
rm "${output}.1"
|
|
16
|
+
|
|
17
|
+
npx asc "$file" --transform ../transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --enable simd --exportStart start || {
|
|
18
|
+
echo "Build failed"
|
|
19
|
+
exit 1
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.simd.wasm"
|
|
23
|
+
rm "${output}.1"
|
|
24
|
+
|
|
25
|
+
for engine in $ENGINES; do
|
|
26
|
+
echo -e "$filename (asc/$runtime/$engine)\n"
|
|
27
|
+
|
|
28
|
+
arg="${filename%.ts}.${runtime}.wasm"
|
|
29
|
+
argSimd="${filename%.ts}.${runtime}.simd.wasm"
|
|
30
|
+
if [[ "$engine" == "ignition" ]]; then
|
|
31
|
+
v8 --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
32
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
33
|
+
v8 --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [[ "$engine" == "liftoff" ]]; then
|
|
37
|
+
v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
38
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
39
|
+
v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
if [[ "$engine" == "sparkplug" ]]; then
|
|
43
|
+
v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
44
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
45
|
+
v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
if [[ "$engine" == "turbofan" ]]; then
|
|
49
|
+
v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $arg
|
|
50
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
51
|
+
v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [[ "$engine" == "llvm" ]]; then
|
|
55
|
+
wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.wasm"
|
|
56
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
57
|
+
wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.simd.wasm"
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
done
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
echo "Finished benchmarks"
|
package/lib/as-bs.ts
CHANGED
|
@@ -167,6 +167,19 @@ export namespace bs {
|
|
|
167
167
|
return changetype<T>(_out);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Copies the buffer's content to a new object of a specified type.
|
|
172
|
+
* @returns The new object containing the buffer's content.
|
|
173
|
+
*/
|
|
174
|
+
// @ts-ignore: Decorator valid here
|
|
175
|
+
@inline export function view<T>(): T {
|
|
176
|
+
const len = offset - changetype<usize>(buffer);
|
|
177
|
+
// @ts-ignore: exists
|
|
178
|
+
const _out = __new(len, idof<T>());
|
|
179
|
+
memory.copy(_out, changetype<usize>(buffer), len);
|
|
180
|
+
return changetype<T>(_out);
|
|
181
|
+
}
|
|
182
|
+
|
|
170
183
|
/**
|
|
171
184
|
* Copies the buffer's content to a given destination pointer.
|
|
172
185
|
* Optionally shrinks the buffer after copying.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"author": "Jairus Tanaka",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"@types/node": "^25.0.3",
|
|
13
13
|
"assemblyscript": "^0.28.9",
|
|
14
14
|
"assemblyscript-prettier": "^3.0.1",
|
|
15
|
+
"chartjs-node-canvas": "^5.0.0",
|
|
16
|
+
"chartjs-plugin-datalabels": "^2.2.0",
|
|
15
17
|
"prettier": "^3.7.4",
|
|
16
18
|
"tinybench": "^6.0.0",
|
|
17
19
|
"typescript": "^5.9.3"
|
package/run-bench.as.sh
CHANGED
|
@@ -1,49 +1,57 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
RUNTIMES=${RUNTIMES:-"minimal stub
|
|
3
|
-
ENGINES=${ENGINES:-"liftoff ignition sparkplug turbofan
|
|
4
|
-
|
|
2
|
+
RUNTIMES=${RUNTIMES:-"incremental"} # incremental minimal stub
|
|
3
|
+
ENGINES=${ENGINES:-"turbofan"} # liftoff ignition sparkplug turbofan
|
|
4
|
+
mkdir -p ./build/logs/as/simd
|
|
5
|
+
mkdir -p ./build/logs/as/swar
|
|
6
|
+
for file in ./assembly/__benches__/*.bench.ts; do
|
|
5
7
|
filename=$(basename -- "$file")
|
|
6
8
|
for runtime in $RUNTIMES; do
|
|
7
9
|
output="./build/${filename%.ts}.${runtime}"
|
|
8
10
|
|
|
9
|
-
npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable
|
|
11
|
+
npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --exportStart start || {
|
|
10
12
|
echo "Build failed"
|
|
11
13
|
exit 1
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
wasm-opt --enable-bulk-memory --enable-
|
|
16
|
+
wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
|
|
15
17
|
rm "${output}.1"
|
|
16
18
|
|
|
17
|
-
npx asc "$file" --transform ./transform -o "${output}.
|
|
19
|
+
npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --enable simd --exportStart start || {
|
|
18
20
|
echo "Build failed"
|
|
19
21
|
exit 1
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.
|
|
23
|
-
rm "${output}.
|
|
24
|
+
wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.simd.wasm"
|
|
25
|
+
rm "${output}.1"
|
|
24
26
|
|
|
25
27
|
for engine in $ENGINES; do
|
|
26
|
-
echo -e "$filename (asc/$runtime/$engine)\n"
|
|
28
|
+
echo -e "$filename (asc/$runtime/$engine/swar)\n"
|
|
27
29
|
|
|
28
30
|
arg="${filename%.ts}.${runtime}.wasm"
|
|
31
|
+
|
|
32
|
+
argSimd="${filename%.ts}.${runtime}.simd.wasm"
|
|
29
33
|
if [[ "$engine" == "ignition" ]]; then
|
|
30
34
|
v8 --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
35
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
36
|
+
v8 --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
31
37
|
fi
|
|
32
38
|
|
|
33
39
|
if [[ "$engine" == "liftoff" ]]; then
|
|
34
40
|
v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
41
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
42
|
+
v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
35
43
|
fi
|
|
36
44
|
|
|
37
45
|
if [[ "$engine" == "sparkplug" ]]; then
|
|
38
46
|
v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $arg
|
|
47
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
48
|
+
v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
39
49
|
fi
|
|
40
50
|
|
|
41
51
|
if [[ "$engine" == "turbofan" ]]; then
|
|
42
52
|
v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $arg
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if [[ "$engine" == "llvm" ]]; then
|
|
46
|
-
wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.wasm"
|
|
53
|
+
echo -e "$filename (asc/$runtime/$engine/simd)\n"
|
|
54
|
+
v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $argSimd
|
|
47
55
|
fi
|
|
48
56
|
done
|
|
49
57
|
done
|
package/run-bench.js.sh
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
RUNTIMES=${RUNTIMES:-"
|
|
2
|
+
RUNTIMES=${RUNTIMES:-"turbofan"}
|
|
3
3
|
npx tsc -p ./bench > /dev/null 2>&1
|
|
4
|
-
|
|
4
|
+
cp ./bench/lib/bench.js ./build/lib/bench.js
|
|
5
|
+
mkdir -p ./build/logs/js
|
|
6
|
+
for file in ./bench/*.bench.ts; do
|
|
5
7
|
filename=$(basename -- "$file")
|
|
6
8
|
file_js="${filename%.ts}.js"
|
|
7
9
|
|
|
@@ -12,21 +14,21 @@ for file in ./bench/vec3.bench.ts; do
|
|
|
12
14
|
engine=$(echo $rt | cut -d'-' -f2-)
|
|
13
15
|
echo -e "$filename (js/$runtime/$engine)\n"
|
|
14
16
|
|
|
15
|
-
arg="${filename%.ts}.${runtime}.
|
|
17
|
+
arg="${filename%.ts}.${runtime}.ts"
|
|
16
18
|
if [[ "$engine" == "ignition" ]]; then
|
|
17
|
-
v8 --no-opt --module ./build/$file_js
|
|
19
|
+
v8 --no-opt --allow-natives-syntax --module ./build/$file_js -- $arg
|
|
18
20
|
fi
|
|
19
21
|
|
|
20
22
|
if [[ "$engine" == "liftoff" ]]; then
|
|
21
|
-
v8 --liftoff-only --no-opt --module ./build/$file_js
|
|
23
|
+
v8 --liftoff-only --no-opt --allow-natives-syntax --module ./build/$file_js -- $arg
|
|
22
24
|
fi
|
|
23
25
|
|
|
24
26
|
if [[ "$engine" == "sparkplug" ]]; then
|
|
25
|
-
v8 --sparkplug --always-sparkplug --no-opt --module ./build/$file_js
|
|
27
|
+
v8 --sparkplug --always-sparkplug --allow-natives-syntax --no-opt --module ./build/$file_js -- $arg
|
|
26
28
|
fi
|
|
27
29
|
|
|
28
30
|
if [[ "$engine" == "turbofan" ]]; then
|
|
29
|
-
v8 --no-liftoff --no-wasm-tier-up --module ./build/$file_js
|
|
31
|
+
v8 --no-liftoff --no-wasm-tier-up --allow-natives-syntax --module ./build/$file_js -- $arg
|
|
30
32
|
fi
|
|
31
33
|
done
|
|
32
34
|
done
|
package/run-tests.sh
CHANGED
|
@@ -5,24 +5,44 @@ mkdir -p ./build
|
|
|
5
5
|
for file in ./assembly/__tests__/*.spec.ts; do
|
|
6
6
|
filename=$(basename -- "$file")
|
|
7
7
|
if [ -z "$1" ] || [ "$1" = "$filename" ]; then
|
|
8
|
-
|
|
8
|
+
for mode in swar simd; do
|
|
9
|
+
output="./build/${filename%.ts}.${mode}.wasm"
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
npx asc "$file" --transform ./transform -o "$output" --runtime incremental --enable simd --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --debug --disableWarning 226 || { echo "Tests failed"; exit 1; }
|
|
12
|
-
end_time=$(date +%s%3N)
|
|
11
|
+
start_time=$(date +%s%3N)
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
if [ "$mode" = "simd" ]; then
|
|
14
|
+
npx asc "$file" \
|
|
15
|
+
--transform ./transform \
|
|
16
|
+
-o "$output" \
|
|
17
|
+
--runtime incremental \
|
|
18
|
+
--enable simd \
|
|
19
|
+
--config ./node_modules/@assemblyscript/wasi-shim/asconfig.json \
|
|
20
|
+
--debug \
|
|
21
|
+
--disableWarning 226 || { echo "Tests failed ($mode)"; exit 1; }
|
|
22
|
+
else
|
|
23
|
+
npx asc "$file" \
|
|
24
|
+
--transform ./transform \
|
|
25
|
+
-o "$output" \
|
|
26
|
+
--runtime incremental \
|
|
27
|
+
--config ./node_modules/@assemblyscript/wasi-shim/asconfig.json \
|
|
28
|
+
--debug \
|
|
29
|
+
--disableWarning 226 || { echo "Tests failed ($mode)"; exit 1; }
|
|
30
|
+
fi
|
|
15
31
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
elif [ "$build_time" -ge 1000 ]; then
|
|
19
|
-
formatted_time="$(bc <<< "scale=2; $build_time/1000")s"
|
|
20
|
-
else
|
|
21
|
-
formatted_time="${build_time}ms"
|
|
22
|
-
fi
|
|
32
|
+
end_time=$(date +%s%3N)
|
|
33
|
+
build_time=$((end_time - start_time))
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
if [ "$build_time" -ge 60000 ]; then
|
|
36
|
+
formatted_time="$(bc <<< "scale=2; $build_time/60000")m"
|
|
37
|
+
elif [ "$build_time" -ge 1000 ]; then
|
|
38
|
+
formatted_time="$(bc <<< "scale=2; $build_time/1000")s"
|
|
39
|
+
else
|
|
40
|
+
formatted_time="${build_time}ms"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo " -> $filename ($mode build in $formatted_time)"
|
|
44
|
+
wasmtime "$output" || { echo "Tests failed ($mode)"; exit 1; }
|
|
45
|
+
done
|
|
26
46
|
else
|
|
27
47
|
echo " -> $filename (skipped)"
|
|
28
48
|
fi
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBenchResults,
|
|
3
|
+
createBarChart,
|
|
4
|
+
generateChart,
|
|
5
|
+
type BenchKind
|
|
6
|
+
} from "./lib/bench-utils";
|
|
7
|
+
|
|
8
|
+
const PAYLOADS: Record<string, string> = {
|
|
9
|
+
abc: "Alphabet (104b)",
|
|
10
|
+
vec3: "3D Vector (38b)",
|
|
11
|
+
small: "Small Payload (88b)",
|
|
12
|
+
medium: "Medium Payload (2.1kb)",
|
|
13
|
+
large: "Large Payload (10.5kb)"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const KIND: BenchKind = "serialize";
|
|
17
|
+
const OUTPUT_FILE = "./data/chart01.svg";
|
|
18
|
+
|
|
19
|
+
const allResults = getBenchResults(Object.keys(PAYLOADS));
|
|
20
|
+
|
|
21
|
+
const chartData: Record<string, any> = {};
|
|
22
|
+
|
|
23
|
+
for (const payload of Object.keys(PAYLOADS)) {
|
|
24
|
+
chartData[payload] = allResults[payload][KIND];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const config = createBarChart(chartData, PAYLOADS, {
|
|
28
|
+
title: "Serialization Throughput by Payload Size",
|
|
29
|
+
yLabel: "Throughput (MB/s)",
|
|
30
|
+
xLabel: "Payload",
|
|
31
|
+
datasetLabels: [
|
|
32
|
+
"Built-in JSON (JS)",
|
|
33
|
+
"JSON-AS (SWAR)",
|
|
34
|
+
"JSON-AS (SIMD)"
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
generateChart(config, OUTPUT_FILE);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBenchResults,
|
|
3
|
+
createBarChart,
|
|
4
|
+
generateChart,
|
|
5
|
+
type BenchKind
|
|
6
|
+
} from "./lib/bench-utils";
|
|
7
|
+
|
|
8
|
+
const PAYLOADS: Record<string, string> = {
|
|
9
|
+
abc: "Alphabet (104b)",
|
|
10
|
+
vec3: "3D Vector (38b)",
|
|
11
|
+
small: "Small Payload (88b)",
|
|
12
|
+
medium: "Medium Payload (2.1kb)",
|
|
13
|
+
large: "Large Payload (10.5kb)"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const KIND: BenchKind = "deserialize";
|
|
17
|
+
const OUTPUT_FILE = "./data/chart02.svg";
|
|
18
|
+
|
|
19
|
+
const allResults = getBenchResults(Object.keys(PAYLOADS));
|
|
20
|
+
|
|
21
|
+
const chartData: Record<string, any> = {};
|
|
22
|
+
|
|
23
|
+
for (const payload of Object.keys(PAYLOADS)) {
|
|
24
|
+
chartData[payload] = allResults[payload][KIND];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const config = createBarChart(chartData, PAYLOADS, {
|
|
28
|
+
title: "Deserialization Throughput by Payload Size",
|
|
29
|
+
yLabel: "Throughput (MB/s)",
|
|
30
|
+
xLabel: "Payload",
|
|
31
|
+
datasetLabels: [
|
|
32
|
+
"Built-in JSON (JS)",
|
|
33
|
+
"JSON-AS (SWAR)",
|
|
34
|
+
"JSON-AS (SIMD)"
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
generateChart(config, OUTPUT_FILE);
|