json-as 0.5.42 → 0.5.50

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/README.md CHANGED
@@ -93,25 +93,34 @@ Fully supports:
93
93
 
94
94
  ## Performance
95
95
 
96
- Number parsing speed has doubled over the last 5 versions due to the use of a `atoi_fast` function found in `assembly/util.ts`. This can be further optimized with SIMD.
97
-
98
- String serialization has more than tripled in performance (+360%). The algorithm was rewritten for less if statements and more traps.
99
-
100
- String deserialization was quadrupled from 3.4m ops to 14.8 ops (435%). It went from using `.replaceAll` to a specialized algorithm.
101
-
102
- Schema (object) parsing is being optimized on GitHub and should be at least doubled if not tripled. (Current speed of barely-optimized version is 6.9m ops) This is due to taking advantage of the types with a type map and eliminating extra checking.
103
-
104
- **Serialize Object (Vec3):** 6.7m ops/5s
105
-
106
- **Deserialize Object (Vec3):** 5.1m ops/5s
107
-
108
- **Serialize Array (int[]):** 6.6m ops/5s
109
-
110
- **Deserialize Array (int[]):** 8.6m ops/5s
111
-
112
- **Serialize String (5):** 5.9m ops/5s
113
-
114
- **Deserialize String (5):** 16.3m ops/5s
96
+ Here are some benchmarks I took with `tinybench` (JavaScript) and `astral` (AssemblyScript).
97
+ I took the benchmarks using the minimal runtime which doesn't call the Garbage Collector, so you may expect a 10% to 40% decrease from low to high throughput.
98
+
99
+ Tests are run on Ubuntu/WSL2 with a AMD Ryzen 9 CPU
100
+
101
+ JavaScript Results (TinyBench/NodeJS 19)
102
+ ┌───────────────────────────┬─────────────┬────────────────────┬──────────┐
103
+ │ Task Name │ ops / sec │ Average Time(ns) │ Margin │
104
+ ├───────────────────────────┼─────────────┼────────────────────┼──────────┤
105
+ │ 'Stringify Object (Vec3)' │ '817,816' │ 1222.76 │ '±3.55%' │
106
+ │ 'Parse Object (Vec3)' │ '726,115' │ 1377.19 │ '±3.21%'
107
+ │ 'Stringify Number Array' │ '1,104,036' │ 905.77 │ '±6.48%' │
108
+ │ 'Parse Number Array' │ '1,114,053' │ 897.62 │ '±2.58%' │
109
+ │ 'Stringify String' │ '1,565,716' │ 638.69 │ '±2.04%' │
110
+ │ 'Parse String' │ '69,568' │ 14374.22 │ '±2.55%'
111
+ └───────────────────────────┴─────────────┴────────────────────┴──────────┘
112
+
113
+ AssemblyScript Results (Runtime Minimal)
114
+ ┌───────────────────────────┬─────────────┬────────────────────┬──────────┐
115
+ │ Task Name │ ops / sec │ Average Time(ns) │ Diff │
116
+ ├───────────────────────────┼─────────────┼────────────────────┼──────────┤
117
+ │ 'Stringify Object (Vec3)' │ '2,091,000' │ 417.22 │ -805ns │
118
+ │ 'Parse Object (Vec3)' │ '1,780,000' │ 539.02 │ -838ns |
119
+ │ 'Stringify Number Array' │ '1,920,000' │ 445.43 │ -460ns │
120
+ │ 'Parse Number Array' │ '1,660,000' │ 597.17 │ -300ns │
121
+ │ 'Stringify String' │ '1,280,000' │ 736.27 │ +97ns │
122
+ │ 'Parse String' │ '4,230,000' │ 239.21 │ -14135ns │
123
+ └───────────────────────────┴─────────────┴────────────────────┴──────────┘
115
124
 
116
125
  ## Issues
117
126
 
@@ -3,6 +3,13 @@ import { backSlashCode, quoteCode } from "../src/chars";
3
3
  import { atoi_fast, parseSciInteger, unsafeCharCodeAt } from "../src/util";
4
4
  import { HASH } from "util/hash";
5
5
 
6
+
7
+ let last = 1;
8
+ let char = 0;
9
+ let inStr = false;
10
+ let key: string | null = null;
11
+ let pos = 0;
12
+
6
13
  @json
7
14
  class Vec3 {
8
15
  x: i32;
@@ -12,20 +19,15 @@ class Vec3 {
12
19
  data: string,
13
20
  to: Vec3
14
21
  ): Vec3 {
15
- let last = 1;
16
- let char = 0;
17
- let inStr = false;
18
- let key: string | null = null;
19
- let pos = 0;
20
22
  for (; pos < data.length - 1; pos++) {
21
23
  char = unsafeCharCodeAt(data, pos);
22
24
  if (inStr === false && char === quoteCode) {
23
25
  if (key != null) {
24
- if (unsafeCharCodeAt(key, 0) == 120) {
26
+ if (unsafeCharCodeAt(key!, 0) == 120) {
25
27
  to.x = parseSciInteger<i32>(data.substring(last, pos - 1));
26
- } else if (unsafeCharCodeAt(key, 0) == 121) {
28
+ } else if (unsafeCharCodeAt(key!, 0) == 121) {
27
29
  to.y = parseSciInteger<i32>(data.substring(last, pos - 1));
28
- } else if (unsafeCharCodeAt(key, 0) == 122) {
30
+ } else if (unsafeCharCodeAt(key!, 0) == 122) {
29
31
  to.z = parseSciInteger<i32>(data.substring(last, pos - 1));
30
32
  }
31
33
  }
@@ -41,14 +43,20 @@ class Vec3 {
41
43
  }
42
44
  }
43
45
  if (key != null) {
44
- if (unsafeCharCodeAt(key, 0) == 120) {
46
+ if (unsafeCharCodeAt(key!, 0) == 120) {
45
47
  to.x = parseSciInteger<i32>(data.substring(last, pos - 1));
46
- } else if (unsafeCharCodeAt(key, 0) == 121) {
48
+ } else if (unsafeCharCodeAt(key!, 0) == 121) {
47
49
  to.y = parseSciInteger<i32>(data.substring(last, pos - 1));
48
- } else if (unsafeCharCodeAt(key, 0) == 122) {
50
+ } else if (unsafeCharCodeAt(key!, 0) == 122) {
49
51
  to.z = parseSciInteger<i32>(data.substring(last, pos - 1));
50
52
  }
51
53
  }
54
+
55
+ last = 1;
56
+ char = 0;
57
+ inStr = false;
58
+ key = null;
59
+ pos = 0;
52
60
  return to;
53
61
  }
54
62
  }
@@ -57,35 +65,8 @@ const vec: Vec3 = {
57
65
  x: 3,
58
66
  y: 1,
59
67
  z: 8,
60
- };
61
-
62
- @inline function istr8<
63
- T extends number
64
- >(int: T): string {
65
- if (int >= 100) {
66
- const str = changetype<string>(__new(6, idof<String>()));
67
- store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48);
68
- store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 2);
69
- store<u16>(changetype<usize>(str), (int % 10) + 48, 4);
70
- return str;
71
- } else if (int >= 10) {
72
- const str = changetype<string>(__new(4, idof<String>()));
73
- store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48);
74
- store<u16>(changetype<usize>(str), (int % 10) + 48, 2);
75
- return str;
76
- } else {
77
- const str = changetype<string>(__new(2, idof<String>()));
78
- store<u16>(changetype<usize>(str), (int % 10) + 48);
79
- return str;
80
- }
81
68
  }
82
-
83
- bench("strint", () => {
84
- blackbox<string>(istr8<i32>(123));
85
- });
86
- bench("tostr", () => {
87
- blackbox<string>((<i32>123).toString());
88
- });
69
+ /*
89
70
  bench("Stringify Object (Vec3)", () => {
90
71
  blackbox<string>(vec.__JSON_Serialize());
91
72
  });
@@ -99,10 +80,18 @@ bench("Stringify Number Array", () => {
99
80
  blackbox(JSON.stringify<i32[]>([1, 2, 3]));
100
81
  });
101
82
 
102
- bench("Parse Array", () => {
83
+ bench("Parse Number Array", () => {
103
84
  blackbox(JSON.parse<i32[]>(blackbox("[1,2,3]")));
104
85
  });
105
86
 
87
+ bench("Stringify String", () => {
88
+ blackbox(JSON.stringify(blackbox('Hello "World!')));
89
+ });
90
+ */
91
+ bench("Parse String", () => {
92
+ blackbox(JSON.parse<string>(blackbox('"Hello "World!"')));
93
+ });
94
+ /*
106
95
  bench("Stringify Boolean Array", () => {
107
96
  blackbox(JSON.stringify<boolean[]>([true, false, true]));
108
97
  });
@@ -111,14 +100,6 @@ bench("Stringify String Array", () => {
111
100
  blackbox(JSON.stringify<string[]>(["a", "b", "c"]));
112
101
  });
113
102
 
114
- bench("Stringify String", () => {
115
- blackbox(JSON.stringify(blackbox('Hello "World!')));
116
- });
117
-
118
- bench("Parse String", () => {
119
- blackbox(JSON.parse<string>(blackbox('"Hello "World!"')));
120
- });
121
-
122
103
  bench("Stringify Boolean", () => {
123
104
  blackbox(JSON.stringify(blackbox(true)));
124
105
  });
@@ -142,3 +123,4 @@ bench("Stringify Float", () => {
142
123
  bench("Parse Float", () => {
143
124
  blackbox(JSON.parse<f32>(blackbox("3.14")));
144
125
  });
126
+ */
@@ -1,13 +1,4 @@
1
1
  import { JSON } from "..";
2
- import {
3
- u128,
4
- u128Safe,
5
- u256,
6
- u256Safe,
7
- i128,
8
- i128Safe,
9
- i256Safe,
10
- } from "as-bignum/assembly";
11
2
  function canSerde<T>(data: T): void {
12
3
  const serialized = JSON.stringify<T>(data);
13
4
  const deserialized = JSON.stringify<T>(JSON.parse<T>(serialized));
package/bench.js ADDED
@@ -0,0 +1,67 @@
1
+ import { Bench } from "tinybench";
2
+ // Trying a new benchmarking lib.
3
+ // It seems to not warmup long at all, so its probably bad.
4
+ // benchmark will probably be best here
5
+
6
+ // JavaScript Results
7
+ // ┌─────────┬───────────────────────────┬─────────────┬────────────────────┬──────────┬─────────┐
8
+ // │ (index) │ Task Name │ ops / sec │ Average Time(ns) │ Margin │ Samples │
9
+ // ├─────────┼───────────────────────────┼─────────────┼────────────────────┼──────────┼─────────┤
10
+ // │ 0 │ 'Stringify Object (Vec3)' │ '817,816' │ 1222.76 │ '±3.55%' │ 81782 │
11
+ // │ 1 │ 'Parse Object (Vec3)' │ '726,115' │ 1377.19 │ '±3.21%' │ 72612 │
12
+ // │ 2 │ 'Stringify Number Array' │ '1,104,036' │ 905.77 │ '±6.48%' │ 110404 │
13
+ // │ 3 │ 'Parse Number Array' │ '1,114,053' │ 897.62 │ '±2.58%' │ 111406 │
14
+ // │ 4 │ 'Stringify String' │ '1,565,716' │ 638.69 │ '±2.04%' │ 156572 │
15
+ // │ 5 │ 'Parse String' │ '69,568' │ 14374.22 │ '±2.55%' │ 6957 │
16
+ // └─────────┴───────────────────────────┴─────────────┴────────────────────┴──────────┴─────────┘
17
+
18
+ // AssemblyScript Results (Runtime Minimal)
19
+ // ┌─────────┬───────────────────────────┬─────────────┬────────────────────┬──────────┬─────────┐
20
+ // │ (index) │ Task Name │ ops / sec │ Average Time(ns) │ Diff │ Samples │
21
+ // ├─────────┼───────────────────────────┼─────────────┼────────────────────┼──────────┼─────────┤
22
+ // │ 0 │ 'Stringify Object (Vec3)' │ '2,091,000' │ 417.22 │ -805ns │ ------- │
23
+ // │ 1 │ 'Parse Object (Vec3)' │ '1,780,000' │ 539.02 │ -838ns │ ------- |
24
+ // │ 2 │ 'Stringify Number Array' │ '1,920,000' │ 445.43 │ -460ns │ ------- │
25
+ // │ 3 │ 'Parse Number Array' │ '1,660,000' │ 597.17 │ -300ns │ ------- │
26
+ // │ 4 │ 'Stringify String' │ '1,280,000' │ 736.27 │ +97ns │ ------- │
27
+ // │ 5 │ 'Parse String' │ '4,230,000' │ 239.21 │ -14135ns │ ------- │
28
+ // └─────────┴───────────────────────────┴─────────────┴────────────────────┴──────────┴─────────┘
29
+
30
+ const vec = {
31
+ x: 3,
32
+ y: 1,
33
+ z: 8,
34
+ };
35
+
36
+ let data;
37
+
38
+ const bench = new Bench({ time: 100 })
39
+
40
+ .add("Stringify Object (Vec3)", () => {
41
+ data = JSON.stringify(vec);
42
+ })
43
+
44
+ .add("Parse Object (Vec3)", () => {
45
+ data = JSON.parse('{"x":0,"y":0,"z":0}');
46
+ })
47
+
48
+ .add("Stringify Number Array", () => {
49
+ data = JSON.stringify([1, 2, 3]);
50
+ })
51
+
52
+ .add("Parse Number Array", () => {
53
+ data = JSON.parse("[1,2,3]");
54
+ })
55
+
56
+ .add("Stringify String", () => {
57
+ data = JSON.stringify('Hello "World!');
58
+ })
59
+
60
+ .add("Parse String", () => {
61
+ data = JSON.parse('"Hello "World!"');
62
+ })
63
+ .todo("unimplemented .add");
64
+
65
+ await bench.run();
66
+
67
+ console.table(bench.table());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "0.5.42",
3
+ "version": "0.5.50",
4
4
  "description": "JSON encoder/decoder for AssemblyScript",
5
5
  "types": "assembly/index.ts",
6
6
  "author": "Jairus Tanaka",
@@ -14,7 +14,7 @@
14
14
  "license": "MIT",
15
15
  "scripts": {
16
16
  "aspect": "asp",
17
- "bench:astral": "astral -Ospeed --noAssert --uncheckedBehavior always",
17
+ "bench:astral": "astral -Ospeed --noAssert --uncheckedBehavior always --runtime minimal",
18
18
  "build:test": "asc assembly/test.ts --target test --runtime stub",
19
19
  "build:transform": "tsc -p ./transform",
20
20
  "test:wasmtime": "wasmtime ./build/test.wasm",
@@ -29,11 +29,11 @@
29
29
  "assemblyscript": "^0.27.1",
30
30
  "assemblyscript-prettier": "^1.0.7",
31
31
  "prettier": "^2.8.4",
32
+ "tinybench": "^2.5.0",
32
33
  "typescript": "^4.9.5",
33
34
  "visitor-as": "^0.11.4"
34
35
  },
35
36
  "dependencies": {
36
- "as-bignum": "^0.2.23",
37
37
  "as-string-sink": "^0.5.3",
38
38
  "as-variant": "^0.4.1"
39
39
  },