json-as 1.1.26 → 1.1.27
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 +64 -0
- package/.prettierrc.json +1 -0
- package/README.md +40 -63
- 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/swar/number.ts +0 -0
- package/assembly/serialize/swar/string.ts +72 -70
- package/assembly/test.tmp.ts +5 -9
- package/assembly/test.ts +3 -6
- 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/data/chart01.svg +258 -0
- package/data/chart02.svg +246 -0
- package/data/chart03.svg +193 -0
- package/data/chart05.svg +142 -0
- package/dump.txt +41590 -0
- package/package.json +4 -2
- 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/{bench → ci/bench}/lib/bench.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-as",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.27",
|
|
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"
|
|
@@ -57,7 +59,7 @@
|
|
|
57
59
|
"test": "bash ./run-tests.sh",
|
|
58
60
|
"bench:as": "bash ./run-bench.as.sh",
|
|
59
61
|
"bench:js": "bash ./run-bench.js.sh",
|
|
60
|
-
"build:test": "rm -rf ./build/ && JSON_DEBUG=2 JSON_WRITE=assembly/test.ts asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --
|
|
62
|
+
"build:test": "rm -rf ./build/ && JSON_DEBUG=2 JSON_WRITE=assembly/test.ts asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
61
63
|
"build:tmp:test": "rm -rf ./build/ && JSON_DEBUG=1 asc assembly/test.tmp.ts -o ./build/test.wasm --textFile ./build/test.wat --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
62
64
|
"build:test:wine": "JSON_DEBUG=1 JSON_WRITE=assembly/test.ts NODE_SKIP_PLATFORM_CHECK=1 wine ~/.win-bin/node/node.exe ./node_modules/assemblyscript/bin/asc.js assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
|
|
63
65
|
"test:wasmtime": "wasmtime ./build/test.wasm",
|
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);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { ChartJSNodeCanvas } from "chartjs-node-canvas";
|
|
4
|
+
import ChartDataLabels from "chartjs-plugin-datalabels";
|
|
5
|
+
import type { ChartConfiguration } from "chart.js";
|
|
6
|
+
|
|
7
|
+
const LOGS_DIR = "./build/logs";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Load a bench log JSON by file path
|
|
11
|
+
*/
|
|
12
|
+
function loadJSON(file: string) {
|
|
13
|
+
const text = fs.readFileSync(file, "utf-8");
|
|
14
|
+
return JSON.parse(text);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get throughput (mbps) and size (bytes) from a bench log
|
|
19
|
+
*/
|
|
20
|
+
function getBenchData(filePath: string) {
|
|
21
|
+
const data = loadJSON(filePath);
|
|
22
|
+
return {
|
|
23
|
+
bytes: typeof data.bytes === "number" ? data.bytes : 0,
|
|
24
|
+
mbps: typeof data.mbps === "number" ? data.mbps : 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* ================================
|
|
29
|
+
* Payload Types — only strings
|
|
30
|
+
* ================================ */
|
|
31
|
+
const payloads = ["small-str", "medium-str", "large-str"];
|
|
32
|
+
const engines = ["swar", "simd"];
|
|
33
|
+
const modes = ["serialize", "deserialize"];
|
|
34
|
+
|
|
35
|
+
// Helper to build log file path
|
|
36
|
+
function logPath(payload: string, engine: string, mode: string) {
|
|
37
|
+
return path.join(LOGS_DIR, "as", engine, `${payload}.${mode}.as.json`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* ================================
|
|
41
|
+
* Prepare Chart Data
|
|
42
|
+
* ================================ */
|
|
43
|
+
interface ChartPoint { x: number; y: number; }
|
|
44
|
+
const chartData: Record<string, ChartPoint[]> = {};
|
|
45
|
+
|
|
46
|
+
for (const payload of payloads) {
|
|
47
|
+
for (const engine of engines) {
|
|
48
|
+
for (const mode of modes) {
|
|
49
|
+
const key = `${payload}-${engine}-${mode}`;
|
|
50
|
+
const data = getBenchData(logPath(payload, engine, mode));
|
|
51
|
+
const sizeKB = data.bytes / 1024;
|
|
52
|
+
|
|
53
|
+
if (!chartData[key]) chartData[key] = [];
|
|
54
|
+
chartData[key].push({ x: sizeKB, y: data.mbps });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ================================
|
|
60
|
+
* Configure Chart
|
|
61
|
+
* ================================ */
|
|
62
|
+
const canvas = new ChartJSNodeCanvas({
|
|
63
|
+
width: 1200,
|
|
64
|
+
height: 700,
|
|
65
|
+
chartCallback: ChartJS => ChartJS.register(ChartDataLabels),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const colors: Record<string, string> = {
|
|
69
|
+
"swar-serialize": "34,197,94", // green
|
|
70
|
+
"swar-deserialize": "59,130,246", // blue
|
|
71
|
+
"simd-serialize": "234,179,8", // yellow
|
|
72
|
+
"simd-deserialize": "220,38,38", // red
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
const datasets = [];
|
|
77
|
+
|
|
78
|
+
for (const mode of modes) {
|
|
79
|
+
for (const engine of engines) {
|
|
80
|
+
const data: ChartPoint[] = payloads.map(p => chartData[`${p}-${engine}-${mode}`][0]);
|
|
81
|
+
datasets.push({
|
|
82
|
+
label: `${engine} ${mode}`,
|
|
83
|
+
data,
|
|
84
|
+
borderColor: `rgba(${colors[engine + "-" + mode]},0.9)`,
|
|
85
|
+
backgroundColor: `rgba(${colors[engine+"-"+mode]},0.3)`,
|
|
86
|
+
fill: false,
|
|
87
|
+
tension: 0.2,
|
|
88
|
+
pointStyle: mode === "serialize" ? "circle" : "rect",
|
|
89
|
+
pointRadius: 6,
|
|
90
|
+
borderDash: engine === "simd" ? [5, 5] : undefined,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
/* ================================
|
|
97
|
+
* Chart Configuration
|
|
98
|
+
* ================================ */
|
|
99
|
+
const config: ChartConfiguration<"line"> = {
|
|
100
|
+
type: "line",
|
|
101
|
+
data: { datasets },
|
|
102
|
+
options: {
|
|
103
|
+
responsive: true,
|
|
104
|
+
plugins: {
|
|
105
|
+
title: {
|
|
106
|
+
display: true,
|
|
107
|
+
text: "String Serialization & Deserialization Throughput vs Payload Size (KB)",
|
|
108
|
+
font: { size: 20, weight: "bold" },
|
|
109
|
+
},
|
|
110
|
+
legend: { position: "top", labels: { font: { size: 14, weight: "bold" } } },
|
|
111
|
+
datalabels: {
|
|
112
|
+
anchor: "end",
|
|
113
|
+
align: "top",
|
|
114
|
+
font: { size: 10, weight: "bold" },
|
|
115
|
+
formatter: (value: any) => `${value.y.toFixed(0)} MB/s`,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
scales: {
|
|
119
|
+
x: {
|
|
120
|
+
title: { display: true, text: "Payload Size (KB)", font: { size: 16, weight: "bold" } },
|
|
121
|
+
type: "linear",
|
|
122
|
+
},
|
|
123
|
+
y: {
|
|
124
|
+
title: { display: true, text: "Throughput (MB/s)", font: { size: 16, weight: "bold" } },
|
|
125
|
+
beginAtZero: true,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
plugins: [ChartDataLabels],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/* ================================
|
|
133
|
+
* Render Chart to PNG
|
|
134
|
+
* ================================ */
|
|
135
|
+
console.log("Rendering chart03 for strings (serialize + deserialize)...");
|
|
136
|
+
const buffer = canvas.renderToBufferSync(config, "image/png");
|
|
137
|
+
const outFile = path.join(LOGS_DIR, "chart03.png");
|
|
138
|
+
fs.writeFileSync(outFile, buffer);
|
|
139
|
+
console.log(`chart03.png written → ${outFile}`);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getBenchResults, createLineChart, generateChart, BenchResults } from './lib/bench-utils';
|
|
2
|
+
|
|
3
|
+
const PAYLOADS_BY_TYPE: Record<string, string[]> = {
|
|
4
|
+
object: ['smallObj', 'mediumObj', 'largeObj'],
|
|
5
|
+
array: ['smallArr', 'mediumArr', 'largeArr'],
|
|
6
|
+
string: ['smallStr', 'mediumStr', 'largeStr']
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const payloadLabels: Record<string, string> = {
|
|
10
|
+
smallObj: 'Small Object',
|
|
11
|
+
mediumObj: 'Medium Object',
|
|
12
|
+
largeObj: 'Large Object',
|
|
13
|
+
smallArr: 'Small Array',
|
|
14
|
+
mediumArr: 'Medium Array',
|
|
15
|
+
largeArr: 'Large Array',
|
|
16
|
+
smallStr: 'Small String',
|
|
17
|
+
mediumStr: 'Medium String',
|
|
18
|
+
largeStr: 'Large String'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Load all payloads
|
|
22
|
+
const allPayloads = Object.values(PAYLOADS_BY_TYPE).flat();
|
|
23
|
+
const results: BenchResults = getBenchResults(allPayloads);
|
|
24
|
+
|
|
25
|
+
// Generate datasets per type
|
|
26
|
+
const series = Object.entries(PAYLOADS_BY_TYPE).flatMap(([type, keys]) => {
|
|
27
|
+
const engines = ['JS', 'SWAR', 'SIMD'] as const;
|
|
28
|
+
|
|
29
|
+
return engines.map((engine, idx) => ({
|
|
30
|
+
label: `${type} (${engine})`,
|
|
31
|
+
data: keys.map(k => results[k].serialize[idx].mbps),
|
|
32
|
+
borderColor: engine === 'JS' ? '#6366f1' : engine === 'SWAR' ? '#22c55e' : '#ef4444'
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Create chart
|
|
37
|
+
const chartConfig = createLineChart(
|
|
38
|
+
['small', 'medium', 'large'],
|
|
39
|
+
series,
|
|
40
|
+
{
|
|
41
|
+
title: 'Serialization Throughput by Type',
|
|
42
|
+
xLabel: 'Payload Size',
|
|
43
|
+
yLabel: 'Throughput (MB/s)'
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
generateChart(chartConfig, './data/chart03.svg');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// gen-obj-properties.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generates AssemblyScript class properties to reach a target byte size.
|
|
7
|
+
* Each i32 property is 4 bytes.
|
|
8
|
+
*
|
|
9
|
+
* @param targetBytes Total desired size in bytes
|
|
10
|
+
* @param prefix Property name prefix
|
|
11
|
+
*/
|
|
12
|
+
function generateProperties(targetBytes: number, prefix = "key"): string {
|
|
13
|
+
const bytesPerProp = 4; // i32
|
|
14
|
+
const numProps = Math.ceil(targetBytes / bytesPerProp);
|
|
15
|
+
let result = "";
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < numProps; i++) {
|
|
18
|
+
result += `${prefix}${i}: i32 = ${i}; `;
|
|
19
|
+
if ((i + 1) % 10 === 0) result += "\n ";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return result.trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate AssemblyScript class source
|
|
27
|
+
*/
|
|
28
|
+
function generateClass(name: string, targetBytes: number) {
|
|
29
|
+
const props = generateProperties(targetBytes);
|
|
30
|
+
return `@json
|
|
31
|
+
class ${name} {
|
|
32
|
+
${props}
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* =================================
|
|
38
|
+
* CONFIGURATION
|
|
39
|
+
* ================================= */
|
|
40
|
+
const classes = [
|
|
41
|
+
{ name: "ObjSmall", sizeKB: 100 },
|
|
42
|
+
{ name: "ObjMedium", sizeKB: 500 },
|
|
43
|
+
{ name: "ObjLarge", sizeKB: 1024 },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const cls of classes) {
|
|
47
|
+
const source = generateClass(cls.name, cls.sizeKB * 1024);
|
|
48
|
+
console.log(`// ===== ${cls.name} =====`);
|
|
49
|
+
console.log(source);
|
|
50
|
+
}
|