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.
Files changed (51) hide show
  1. package/.github/workflows/benchmark.yml +64 -0
  2. package/.prettierrc.json +1 -0
  3. package/README.md +40 -63
  4. package/assembly/__benches__/abc.bench.ts +5 -9
  5. package/assembly/__benches__/large.bench.ts +114 -120
  6. package/assembly/__benches__/lib/bench.ts +44 -1
  7. package/assembly/__benches__/medium.bench.ts +108 -29
  8. package/assembly/__benches__/small.bench.ts +28 -18
  9. package/assembly/__benches__/throughput.ts +172 -0
  10. package/assembly/__benches__/vec3.bench.ts +8 -3
  11. package/assembly/__tests__/string.spec.ts +4 -0
  12. package/assembly/deserialize/simple/arbitrary.ts +5 -2
  13. package/assembly/deserialize/simple/object.ts +3 -1
  14. package/assembly/deserialize/swar/string.ts +62 -62
  15. package/assembly/index.ts +6 -2
  16. package/assembly/serialize/swar/number.ts +0 -0
  17. package/assembly/serialize/swar/string.ts +72 -70
  18. package/assembly/test.tmp.ts +5 -9
  19. package/assembly/test.ts +3 -6
  20. package/bench/abc.bench.ts +6 -8
  21. package/bench/large.bench.ts +119 -118
  22. package/bench/lib/bench.d.ts +27 -0
  23. package/bench/lib/bench.js +53 -0
  24. package/bench/lib/chart.ts +217 -0
  25. package/bench/medium.bench.ts +55 -30
  26. package/bench/runners/assemblyscript.js +6 -1
  27. package/bench/small.bench.ts +7 -3
  28. package/bench/throughput.ts +87 -0
  29. package/bench/tsconfig.json +3 -2
  30. package/bench/vec3.bench.ts +7 -3
  31. package/ci/bench/runners/assemblyscript.js +29 -0
  32. package/ci/run-bench.as.sh +63 -0
  33. package/data/chart01.svg +258 -0
  34. package/data/chart02.svg +246 -0
  35. package/data/chart03.svg +193 -0
  36. package/data/chart05.svg +142 -0
  37. package/dump.txt +41590 -0
  38. package/package.json +4 -2
  39. package/run-bench.as.sh +21 -13
  40. package/run-bench.js.sh +9 -7
  41. package/run-tests.sh +34 -14
  42. package/scripts/build-chart01.ts +38 -0
  43. package/scripts/build-chart02.ts +38 -0
  44. package/scripts/build-chart03.ts +139 -0
  45. package/scripts/build-chart05.ts +47 -0
  46. package/scripts/generate-as-class.ts +50 -0
  47. package/scripts/lib/bench-utils.ts +308 -0
  48. package/transform/lib/index.js +2 -2
  49. package/transform/lib/index.js.map +1 -1
  50. package/transform/src/index.ts +2 -2
  51. /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.26",
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 --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
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 llvm"}
4
- for file in ./assembly/__benches__/abc.bench.ts; do
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 simd --enable bulk-memory --exportStart start || {
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-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
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}.2" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable simd --enable bulk-memory --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json || {
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}.2" -o "${output%.wasm}.wasi.wasm"
23
- rm "${output}.2"
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
- fi
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:-"liftoff ignition sparkplug turbofan"}
2
+ RUNTIMES=${RUNTIMES:-"turbofan"}
3
3
  npx tsc -p ./bench > /dev/null 2>&1
4
- for file in ./bench/vec3.bench.ts; do
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}.wasm"
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
- output="./build/${filename%.ts}.wasm"
8
+ for mode in swar simd; do
9
+ output="./build/${filename%.ts}.${mode}.wasm"
9
10
 
10
- start_time=$(date +%s%3N)
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
- build_time=$((end_time - start_time))
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
- if [ "$build_time" -ge 60000 ]; then
17
- formatted_time="$(bc <<< "scale=2; $build_time/60000")m"
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
- echo " -> $filename (built in $formatted_time)"
25
- wasmtime "$output" || { echo "Tests failed"; exit 1; }
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
+ }