diff --git a/README.md b/README.md index 252af2e..d74dd36 100644 --- a/README.md +++ b/README.md @@ -84,53 +84,49 @@ If you use this project in your codebase, consider dropping a [star](https://git Run or view the benchmarks [here](https://github.com/JairusSW/as-json/tree/master/bench) -Below are benchmark results comparing JavaScript, WAVM (WebAssembly Virtual Machine), and Wasmtime environments. +Below are benchmark results comparing JavaScript's built-in JSON implementation and `JSON-AS` -JavaScript Results +My library beats JSON (written in C++) on all counts *and*, I see many places where I can pull at least a 60% uplift in performance if I implement it. -NodeJS v20.5.1 - TinyBench v2.5.0 (V8) -``` -┌───────────────────────────┬───────────────┐ -│ Task Name │ ops / sec │ -├───────────────────────────┼───────────────┤ -│ 'Stringify Object (Vec3)' │ '1,191,221' │ -│ 'Parse Object (Vec3)' │ '897,759' │ -│ 'Stringify Number Array' │ '1,552,255' │ -│ 'Parse Number Array' │ '1,225,325' │ -│ 'Stringify String' │ '1,761,011' │ -│ 'Parse String' │ '80,845' │ -└───────────────────────────┴───────────────┘ -``` +**Serialize String** -AssemblyScript Results +- Value: "hello world" -WAVM v0.0.0-prerelease - as-bench v0.0.0-alpha (LLVM) -``` -┌───────────────────────────┬───────────────┐ -│ Task Name │ ops / sec │ -├───────────────────────────┼───────────────┤ -│ 'Stringify Object (Vec3)' │ '6,270,322' │ -│ 'Parse Object (Vec3)' │ '8,000,195' | -│ 'Stringify Number Array' │ '6,664,937' │ -│ 'Parse Number Array' │ '6,557,357' │ -│ 'Stringify String' │ '6,946,947' │ -│ 'Parse String' │ '10,952,502' │ -└───────────────────────────┴───────────────┘ -``` +JavaScript: 28,629,598 ops/s -Wasmtime v11.0.1 - as-bench v0.0.0-alpha (Cranelift) -``` -┌───────────────────────────┬───────────────┐ -│ Task Name │ ops / sec │ -├───────────────────────────┼───────────────┤ -│ 'Stringify Object (Vec3)' │ '2,038,684' │ -│ 'Parse Object (Vec3)' │ '4,623,337' | -│ 'Stringify Number Array' │ '2,500,947' │ -│ 'Parse Number Array' │ '2,959,180' │ -│ 'Stringify String' │ '3,236,896' │ -│ 'Parse String' │ '5,634,594' │ -└───────────────────────────┴───────────────┘ -``` +AssemblyScript: 64,210,666 ops/s + +**Serialize Integer** + +- Value 12345 + +JavaScript: 31,562,431 ops/s + +AssemblyScript: 48,035,001 ops/s + +**Serialize Float** + +- Value 1.2345 + +JavaScript: 15,977,278 ops/s + +AssemblyScript: 20,322,939 ops/s + +**Serialize Set Theoretical Representation** + +- Value [[],[[]],[[],[[]]]] + +JavaScript: 8,998,624 ops/s + +AssemblyScript: 34,453,102 ops/s + +**Parse Integer** + +- Value: "12345" + +JavaScript: 34,647,886 ops/s + +AssemblyScript: 254,640,930 ops/s ## Issues diff --git a/assembly/bench/bench.ts b/assembly/bench/bench.ts index 5eb19b0..bb7e499 100644 --- a/assembly/bench/bench.ts +++ b/assembly/bench/bench.ts @@ -1,82 +1,38 @@ -import { JSON } from ".."; -import { _deserializeString, deserializeString } from "../deserialize/string"; -import { Sink } from "../src/sink"; - import { bench, blackbox } from "as-bench/assembly/bench"; -import { __atoi_fast, __atoi_fast_safe } from "../src/util"; -import { serializeUnknown } from "../serialize/unknown"; +import { Sink } from "../src/sink"; +import { JSON } from ".."; const set = JSON.Value.from([ JSON.Value.from([]), JSON.Value.from([ - JSON.Value.from([]) + JSON.Value.from([]) ]), JSON.Value.from([ - JSON.Value.from([]), - JSON.Value.from([ - JSON.Value.from([]) - ]), + JSON.Value.from([]), + JSON.Value.from([ + JSON.Value.from([]) + ]), ]), ]); -@unmanaged -class Vec3 { - x: f64; - y: f64; - z: f64; - @inline __JSON_Serialize(out: Sink | null = null): Sink { - if (!out) { - out = Sink.withCapacity(25); - } - - out.write(this.__JSON_Serialize_Unsafe()); - - return out; - } - @inline __JSON_Serialize_Unsafe(): string { - return `{"x":${JSON.serialize(this.x)},"y":${JSON.serialize(this.y)},"z":${JSON.serialize(this.z)}}`; - } -} - -const vec: Vec3 = { - x: 3.4, - y: 1.2, - z: -5.6 -} - -const map = new Map(); -map.set("x", JSON.Value.from(3.4)); -map.set("y", JSON.Value.from(1.2)); -map.set("z", JSON.Value.from(-5.6)); -/* bench("Serialize Set Theoretical Representation", () => { - blackbox(serializeUnknown(set)); -}); - -bench("Serialize Vector 3 Struct", () => { - blackbox(vec.__JSON_Serialize_Unsafe()); -}); -bench("Serialize String (Sink)", () => { - blackbox(JSON.serialize("hello world")); + blackbox(JSON.serialize(set)); }); -bench("Serialize String (No Sink)", () => { - blackbox(JSON.serialize("hello world").toString()); +/*bench("Serialize Float", () => { + blackbox(JSON.serialize(1.2345)); }); -bench("Parse String (Raw)", () => { - blackbox(_deserializeString("\"hello world\"")); + +bench("Serialize Float32", () => { + blackbox(JSON.serialize(1.2345)); }); -bench("Parse String (Product)", () => { - blackbox(JSON.parse("\"hello world\"")); +bench("Serialize String", () => { + blackbox(JSON.serialize("hello world")); }); -bench("Parse String (Unwrap)", () => { - blackbox(JSON.parse("\"hello world\"").unwrap()); -});*/ -bench("ATOI (Unsafe): " + __atoi_fast("1234567890").toString(), () => { - blackbox(__atoi_fast("1234567890")); +bench("Serialize Integer", () => { + blackbox(JSON.serialize(12345)); }); -bench("ATOI (Safe): " + __atoi_fast_safe("1234567890").toString(), () => { - blackbox(__atoi_fast_safe("1234567890")); -}); -bench("empty", () => {}) \ No newline at end of file +bench("Parse Number: " + __atoi_fast("12345").toString(), () => { + blackbox(__atoi_fast("12345")); +});*/ \ No newline at end of file diff --git a/bench.ts b/bench.ts new file mode 100644 index 0000000..2c4502c --- /dev/null +++ b/bench.ts @@ -0,0 +1,27 @@ +import Benchmark from "benchmark"; +const suite = new Benchmark.Suite; + +suite.add("Serialize Set Theoretical Representation", () => { + JSON.stringify([[],[[]],[[],[[]]]]); +}); +/* +suite.add("Serialize Float", () => { + JSON.stringify(1.2345); +}); + +suite.add("Serialize Integer", () => { + JSON.stringify(12345); +}); +suite.add("Serialize String", () => { + JSON.stringify("hello world"); +}); +suite.add("Parse Number", () => { + JSON.parse("12345"); +}); +*/ +suite.on("cycle", (cycle) => { + console.log(cycle.target.toString()); +}); + + +suite.run(); \ No newline at end of file diff --git a/index.ts b/index.ts index 1001d3c..57136b9 100644 --- a/index.ts +++ b/index.ts @@ -1 +1,2 @@ export { JSON } from "./assembly/src/json"; + diff --git a/package.json b/package.json index bca8904..fb2ad9e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "build:test": "asc assembly/test.ts -o build/test.wasm --transform ./transform --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json", "build:bench": "asc assembly/bench/bench.ts -o build/bench.wasm --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --optimizeLevel 3 --converge --exportRuntime --runtime stub", "bench:wasmtime": "wasmtime ./build/bench.wasm", - "bench:wavm": "wavm run ./build/bench.wasm", + "bench:wasmer": "wasmer run ./build/bench.wasm --llvm", "build:transform": "tsc -p ./transform", "test:wasmtime": "wasmtime ./build/test.wasm", "test:wavm": "wavm run ./build/test.wasm", @@ -32,6 +32,7 @@ "@as-pect/cli": "^8.1.0", "@as-tral/cli": "^3.0.2", "@assemblyscript/wasi-shim": "^0.1.0", + "@types/benchmark": "^2.1.5", "as-bench": "^0.0.0-alpha", "as-test": "JairusSW/as-test#03e96e7", "assemblyscript": "^0.27.22", @@ -40,14 +41,13 @@ "kati": "^0.6.2", "microtime": "^3.1.1", "prettier": "^3.1.1", - "tinybench": "^2.5.1", + "tinybench": "^2.8.0", "typescript": "^5.3.3", "visitor-as": "^0.11.4" }, "dependencies": { "as-container": "^0.8.0", "as-string-sink": "^0.5.3", - "as-test": "JairusSW/as-test", "as-variant": "^0.4.1", "as-virtual": "^0.1.9" },