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
@@ -1,126 +1,127 @@
1
- import { bench } from "./lib/bench.js";
1
+ import { bench, blackbox, dumpToFile } from "./lib/bench.js";
2
2
 
3
- class Vec3 {
4
- public x!: number;
5
- public y!: number;
6
- public z!: number;
3
+ class RepoOwner {
4
+ login: string = "octocat";
5
+ id: number = 583231;
6
+ node_id: string = "MDQ6VXNlcjU4MzIzMQ==";
7
+ avatar_url: string = "https://avatars.githubusercontent.com/u/583231?v=4";
8
+ gravatar_id: string = "";
9
+ url: string = "https://api.github.com/users/octocat";
10
+ html_url: string = "https://github.com/octocat";
11
+ followers_url: string = "https://api.github.com/users/octocat/followers";
12
+ following_url: string = "https://api.github.com/users/octocat/following{/other_user}";
13
+ gists_url: string = "https://api.github.com/users/octocat/gists{/gist_id}";
14
+ starred_url: string = "https://api.github.com/users/octocat/starred{/owner}{/repo}";
15
+ subscriptions_url: string = "https://api.github.com/users/octocat/subscriptions";
16
+ organizations_url: string = "https://api.github.com/users/octocat/orgs";
17
+ repos_url: string = "https://api.github.com/users/octocat/repos";
18
+ events_url: string = "https://api.github.com/users/octocat/events{/privacy}";
19
+ received_events_url: string = "https://api.github.com/users/octocat/received_events";
20
+ type: string = "User";
21
+ user_view_type: string = "public";
22
+ site_admin: boolean = false;
7
23
  }
8
24
 
9
- class LargeJSON {
10
- public id!: number;
11
- public name!: string;
12
- public age!: number;
13
- public email!: string;
14
- public street!: string;
15
- public city!: string;
16
- public state!: string;
17
- public zip!: string;
18
- public tags!: string[];
19
- public theme!: string;
20
- public notifications!: boolean;
21
- public language!: string;
22
- public movement!: Vec3[];
25
+ class RepoLicense {
26
+ key: string = "";
27
+ name: string = "";
28
+ spdx_id: string = "";
29
+ url: string | null = null;
30
+ node_id: string = "";
23
31
  }
24
32
 
25
- const v1: LargeJSON = {
26
- id: 2,
27
- name: "Medium Object",
28
- age: 18,
29
- email: "me@jairus.dev",
30
- street: "I don't want to say my street",
31
- city: "I don't want to say this either",
32
- state: "It really depends",
33
- zip: "I forget what it is",
34
- tags: ["me", "dogs", "mountains", "bar", "foo"],
35
- theme: "Hyper Term Black",
36
- notifications: true,
37
- language: "en-US",
38
- movement: [
39
- { x: 1, y: 2, z: 3 },
40
- { x: 1, y: 2, z: 3 },
41
- { x: 1, y: 2, z: 3 },
42
- { x: 1, y: 2, z: 3 },
43
- { x: 1, y: 2, z: 3 },
44
- { x: 1, y: 2, z: 3 },
45
- { x: 1, y: 2, z: 3 },
46
- { x: 1, y: 2, z: 3 },
47
- { x: 1, y: 2, z: 3 },
48
- { x: 1, y: 2, z: 3 },
49
- { x: 1, y: 2, z: 3 },
50
- { x: 1, y: 2, z: 3 },
51
- { x: 1, y: 2, z: 3 },
52
- { x: 1, y: 2, z: 3 },
53
- { x: 1, y: 2, z: 3 },
54
- { x: 1, y: 2, z: 3 },
55
- { x: 1, y: 2, z: 3 },
56
- { x: 1, y: 2, z: 3 },
57
- { x: 1, y: 2, z: 3 },
58
- { x: 1, y: 2, z: 3 },
59
- { x: 1, y: 2, z: 3 },
60
- { x: 1, y: 2, z: 3 },
61
- { x: 1, y: 2, z: 3 },
62
- { x: 1, y: 2, z: 3 },
63
- { x: 1, y: 2, z: 3 },
64
- { x: 1, y: 2, z: 3 },
65
- { x: 1, y: 2, z: 3 },
66
- { x: 1, y: 2, z: 3 },
67
- { x: 1, y: 2, z: 3 },
68
- { x: 1, y: 2, z: 3 },
69
- { x: 1, y: 2, z: 3 },
70
- { x: 1, y: 2, z: 3 },
71
- { x: 1, y: 2, z: 3 },
72
- { x: 1, y: 2, z: 3 },
73
- { x: 1, y: 2, z: 3 },
74
- { x: 1, y: 2, z: 3 },
75
- { x: 1, y: 2, z: 3 },
76
- { x: 1, y: 2, z: 3 },
77
- { x: 1, y: 2, z: 3 },
78
- { x: 1, y: 2, z: 3 },
79
- { x: 1, y: 2, z: 3 },
80
- { x: 1, y: 2, z: 3 },
81
- { x: 1, y: 2, z: 3 },
82
- { x: 1, y: 2, z: 3 },
83
- { x: 1, y: 2, z: 3 },
84
- { x: 1, y: 2, z: 3 },
85
- { x: 1, y: 2, z: 3 },
86
- { x: 1, y: 2, z: 3 },
87
- { x: 1, y: 2, z: 3 },
88
- { x: 1, y: 2, z: 3 },
89
- { x: 1, y: 2, z: 3 },
90
- { x: 1, y: 2, z: 3 },
91
- { x: 1, y: 2, z: 3 },
92
- { x: 1, y: 2, z: 3 },
93
- { x: 1, y: 2, z: 3 },
94
- { x: 1, y: 2, z: 3 },
95
- { x: 1, y: 2, z: 3 },
96
- { x: 1, y: 2, z: 3 },
97
- { x: 1, y: 2, z: 3 },
98
- { x: 1, y: 2, z: 3 },
99
- { x: 1, y: 2, z: 3 },
100
- { x: 1, y: 2, z: 3 },
101
- { x: 1, y: 2, z: 3 },
102
- { x: 1, y: 2, z: 3 },
103
- { x: 1, y: 2, z: 3 },
104
- { x: 1, y: 2, z: 3 },
105
- { x: 1, y: 2, z: 3 },
106
- { x: 1, y: 2, z: 3 },
107
- ],
108
- };
33
+ class Repo {
34
+ id: number = 132935648;
35
+ node_id: string = "MDEwOlJlcG9zaXRvcnkxMzI5MzU2NDg=";
36
+ name: string = "boysenberry-repo-1";
37
+ full_name: string = "octocat/boysenberry-repo-1";
38
+ private: boolean = true;
39
+ owner: RepoOwner = new RepoOwner();
40
+ html_url: string = "https://github.com/octocat/boysenberry-repo-1";
41
+ description: string | null = "Testing";
42
+ fork: boolean = true;
43
+ url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1";
44
+ forks_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/forks";
45
+ keys_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/keys{/key_id}";
46
+ collaborators_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/collaborators{/collaborator}";
47
+ teams_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/teams";
48
+ hooks_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/hooks";
49
+ issue_events_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/issues/events{/number}";
50
+ events_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/events";
51
+ assignees_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/assignees{/user}";
52
+ branches_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/branches{/branch}";
53
+ tags_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/tags";
54
+ blobs_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/git/blobs{/sha}";
55
+ git_tags_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/git/tags{/sha}";
56
+ git_refs_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/git/refs{/sha}";
57
+ trees_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/git/trees{/sha}";
58
+ statuses_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/statuses/{sha}";
59
+ languages_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/languages";
60
+ stargazers_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/stargazers";
61
+ contributors_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/contributors";
62
+ subscribers_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/subscribers";
63
+ subscription_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/subscription";
64
+ commits_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/commits{/sha}";
65
+ git_commits_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/git/commits{/sha}";
66
+ comments_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/comments{/number}";
67
+ issue_comment_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/issues/comments{/number}";
68
+ contents_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/contents/{+path}";
69
+ compare_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/compare/{base}...{head}";
70
+ merges_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/merges";
71
+ archive_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/{archive_format}{/ref}";
72
+ downloads_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/downloads";
73
+ issues_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/issues{/number}";
74
+ pulls_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/pulls{/number}";
75
+ milestones_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/milestones{/number}";
76
+ notifications_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/notifications{?since,all,participating}";
77
+ labels_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/labels{/name}";
78
+ releases_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/releases{/id}";
79
+ deployments_url: string = "https://api.github.com/repos/octocat/boysenberry-repo-1/deployments";
80
+ created_at: string = "2018-05-10T17:51:29Z";
81
+ updated_at: string = "2025-05-24T02:01:19Z";
82
+ pushed_at: string = "2024-05-26T07:02:05Z";
83
+ git_url: string = "git://github.com/octocat/boysenberry-repo-1.git";
84
+ ssh_url: string = "git@github.com:octocat/boysenberry-repo-1.git";
85
+ clone_url: string = "https://github.com/octocat/boysenberry-repo-1.git";
86
+ svn_url: string = "https://github.com/octocat/boysenberry-repo-1";
87
+ homepage: string | null = "";
88
+ size: number = 4;
89
+ stargazers_count: number = 332;
90
+ watchers_count: number = 332;
91
+ language: string | null = null;
92
+ has_issues: boolean = false;
93
+ has_projects: boolean = true;
94
+ has_downloads: boolean = true;
95
+ has_wiki: boolean = true;
96
+ has_pages: boolean = false;
97
+ has_discussions: boolean = false;
98
+ forks_count: number = 20;
99
+ mirror_url: string | null = null;
100
+ archived: boolean = false;
101
+ disabled: boolean = false;
102
+ open_issues_count: number = 1;
103
+ license: RepoLicense | null = null;
104
+ allow_forking: boolean = true;
105
+ is_template: boolean = false;
106
+ web_commit_signoff_required: boolean = false;
107
+ topics: string[] = [];
108
+ visibility: string = "public";
109
+ forks: number = 20;
110
+ open_issues: number = 1;
111
+ watchers: number = 332;
112
+ default_branch: string = "master";
113
+ }
114
+
115
+ const v1 = new Repo();
109
116
 
110
- const v2 = `{"id":2,"name":"Medium Object","age":18,"email":"me@jairus.dev","street":"I don't want to say my street","city":"I don't want to say this either","state":"It really depends","zip":"I forget what it is","tags":["me","dogs","mountains","bar","foo"],"theme":"Hyper Term Black","notifications":true,"language":"en-US","movement":[{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3}]}`;
117
+ const v2 = `{"id":132935648,"node_id":"MDEwOlJlcG9zaXRvcnkxMzI5MzU2NDg=","name":"boysenberry-repo-1","full_name":"octocat/boysenberry-repo-1","private":true,"owner":{"login":"octocat","id":583231,"node_id":"MDQ6VXNlcjU4MzIzMQ==","avatar_url":"https://avatars.githubusercontent.com/u/583231?v=4","gravatar_id":"","url":"https://api.github.com/users/octocat","html_url":"https://github.com/octocat","followers_url":"https://api.github.com/users/octocat/followers","following_url":"https://api.github.com/users/octocat/following{/other_user}","gists_url":"https://api.github.com/users/octocat/gists{/gist_id}","starred_url":"https://api.github.com/users/octocat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/octocat/subscriptions","organizations_url":"https://api.github.com/users/octocat/orgs","repos_url":"https://api.github.com/users/octocat/repos","events_url":"https://api.github.com/users/octocat/events{/privacy}","received_events_url":"https://api.github.com/users/octocat/received_events","type":"User","user_view_type":"public","site_admin":false},"html_url":"https://github.com/octocat/boysenberry-repo-1","description":"Testing","fork":true,"url":"https://api.github.com/repos/octocat/boysenberry-repo-1","forks_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/forks","keys_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/keys{/key_id}","collaborators_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/teams","hooks_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/hooks","issue_events_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/issues/events{/number}","events_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/events","assignees_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/assignees{/user}","branches_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/branches{/branch}","tags_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/tags","blobs_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/git/refs{/sha}","trees_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/git/trees{/sha}","statuses_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/statuses/{sha}","languages_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/languages","stargazers_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/stargazers","contributors_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/contributors","subscribers_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/subscribers","subscription_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/subscription","commits_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/commits{/sha}","git_commits_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/git/commits{/sha}","comments_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/comments{/number}","issue_comment_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/issues/comments{/number}","contents_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/contents/{+path}","compare_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/compare/{base}...{head}","merges_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/merges","archive_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/downloads","issues_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/issues{/number}","pulls_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/pulls{/number}","milestones_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/milestones{/number}","notifications_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/labels{/name}","releases_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/releases{/id}","deployments_url":"https://api.github.com/repos/octocat/boysenberry-repo-1/deployments","created_at":"2018-05-10T17:51:29Z","updated_at":"2025-05-24T02:01:19Z","pushed_at":"2024-05-26T07:02:05Z","git_url":"git://github.com/octocat/boysenberry-repo-1.git","ssh_url":"git@github.com:octocat/boysenberry-repo-1.git","clone_url":"https://github.com/octocat/boysenberry-repo-1.git","svn_url":"https://github.com/octocat/boysenberry-repo-1","homepage":"","size":4,"stargazers_count":332,"watchers_count":332,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":20,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":1,"license":null,"allow_forking":true,"is_template":false,"web_commit_signoff_required":false,"topics":[],"visibility":"public","forks":20,"open_issues":1,"watchers":332,"default_branch":"master"}`;
111
118
 
112
- bench(
113
- "Serialize Large Object",
114
- () => {
115
- JSON.stringify(v1);
116
- },
117
- 3_000_00,
118
- );
119
+ bench("Serialize Large API Response", () => {
120
+ blackbox(JSON.stringify(v1));
121
+ }, 100_000, 10502);
122
+ dumpToFile("large", "serialize")
119
123
 
120
- bench(
121
- "Deserialize Large Object",
122
- () => {
123
- JSON.parse(v2);
124
- },
125
- 3_000_00,
126
- );
124
+ bench("Deserialize Large API Response", () => {
125
+ blackbox(JSON.parse(v2));
126
+ }, 100_000, 10502);
127
+ dumpToFile("large", "deserialize")
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Benchmark a routine under V8.
3
+ *
4
+ * @param description Human-readable benchmark name
5
+ * @param routine Function to benchmark (must be side-effect safe)
6
+ * @param ops Number of operations to execute (default: 1,000,000)
7
+ * @param bytesPerOp Bytes processed per operation (used for MB/s reporting)
8
+ */
9
+ export function bench(
10
+ description: string,
11
+ routine: () => void,
12
+ ops?: number,
13
+ bytesPerOp?: number
14
+ ): void;
15
+
16
+ /**
17
+ * Prevents V8 from optimizing away a value.
18
+ *
19
+ * This relies on the V8 intrinsic %PerformMicrotaskCheckpoint and therefore
20
+ * only works under d8 / V8 with --allow-natives-syntax.
21
+ *
22
+ * @param x Value to blackbox
23
+ * @returns The same value
24
+ */
25
+ export function blackbox<T>(x: T): T;
26
+
27
+ export function dumpToFile(suite: string, type: string): void;
@@ -0,0 +1,53 @@
1
+ let result = {};
2
+ export function bench(description, routine, ops = 1_000_000, bytesPerOp = 0) {
3
+ console.log(" - Benchmarking " + description);
4
+ let warmup = Math.floor(ops / 10);
5
+ while (warmup-- > 0) {
6
+ routine();
7
+ }
8
+ const start = performance.now();
9
+ let count = ops;
10
+ while (count-- > 0) {
11
+ routine();
12
+ }
13
+ const end = performance.now();
14
+ const elapsed = Math.max(1, end - start);
15
+ const opsPerSecond = (ops * 1000) / elapsed;
16
+ let log = ` Completed benchmark in ${formatNumber(Math.round(elapsed))}ms at ${formatNumber(Math.round(opsPerSecond))} ops/s`;
17
+ let mbPerSec = 0;
18
+ if (bytesPerOp > 0) {
19
+ const totalBytes = bytesPerOp * ops;
20
+ mbPerSec = totalBytes / (elapsed / 1000) / (1000 * 1000);
21
+ log += ` @ ${formatNumber(Math.round(mbPerSec))}MB/s`;
22
+ }
23
+ result = {
24
+ language: "javascript",
25
+ description,
26
+ elapsed,
27
+ bytes: bytesPerOp,
28
+ operations: ops,
29
+ features: [],
30
+ mbps: mbPerSec
31
+ };
32
+ console.log(log + "\n");
33
+ }
34
+ export function dumpToFile(suite, type) {
35
+ writeFile("./build/logs/js/" + suite+"."+type+".js.json", JSON.stringify(result));
36
+ }
37
+ function formatNumber(n) {
38
+ let str = n.toString();
39
+ let len = str.length;
40
+ let result = "";
41
+ let commaOffset = len % 3;
42
+ for (let i = 0; i < len; i++) {
43
+ if (i > 0 && (i - commaOffset) % 3 === 0)
44
+ result += ",";
45
+ result += str.charAt(i);
46
+ }
47
+ return result;
48
+ }
49
+
50
+ export function blackbox(x) {
51
+ %PerformMicrotaskCheckpoint();
52
+ return x;
53
+ }
@@ -0,0 +1,217 @@
1
+ // chartplot.ts (Bun/ESNext compatible)
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { basename } from "path";
4
+
5
+ type RawBench = {
6
+ description: string;
7
+ elapsed: number; // ms
8
+ bytes: number; // bytes per operation
9
+ operations: number;
10
+ features: string[];
11
+ };
12
+
13
+ type BenchmarkResult = {
14
+ library: string;
15
+ payload: string; // e.g., "small", "medium", "large", "abc", "vec3"
16
+ gbPerSec: number;
17
+ };
18
+
19
+ type ChartData = {
20
+ title: string;
21
+ payloads: string[]; // ordered list of payload names
22
+ results: BenchmarkResult[];
23
+ };
24
+
25
+ if (import.meta.main) {
26
+ const args = process.argv.slice(2);
27
+ if (!args.length) {
28
+ console.error(
29
+ "Usage:\n bun ./chartplot.ts <bench1.json> <bench2.json> [...] [-o output.svg]"
30
+ );
31
+ process.exit(1);
32
+ }
33
+
34
+ let outputFile = "benchmark-chart.svg";
35
+ const inputFiles: string[] = [];
36
+
37
+ for (let i = 0; i < args.length; i++) {
38
+ if (args[i] === "-o") {
39
+ if (i + 1 >= args.length) {
40
+ console.error("Error: -o requires a filename");
41
+ process.exit(1);
42
+ }
43
+ outputFile = args[++i];
44
+ } else {
45
+ inputFiles.push("./build/logs/" +args[i]);
46
+ }
47
+ }
48
+
49
+ if (!inputFiles.length) {
50
+ console.error("Error: no input files provided");
51
+ process.exit(1);
52
+ }
53
+
54
+ generateBarChartFromFiles(inputFiles, outputFile);
55
+ }
56
+
57
+ function generateBarChartFromFiles(files: string[], outputFile: string) {
58
+ const results: BenchmarkResult[] = [];
59
+
60
+ for (const file of files) {
61
+ const raw: RawBench = JSON.parse(readFileSync(file, "utf-8"));
62
+ const impl = inferImplementation(file);
63
+ const payload = inferPayload(file);
64
+
65
+ const gbPerSec = (raw.bytes * raw.operations) / (raw.elapsed * 1e6);
66
+
67
+ results.push({ library: impl, payload, gbPerSec });
68
+ }
69
+
70
+ // Group by payload and sort payloads logically
71
+ const payloadOrder = ["abc", "vec3", "small", "medium", "large"];
72
+ const uniquePayloads = [...new Set(results.map(r => r.payload))].sort(
73
+ (a, b) => payloadOrder.indexOf(a) - payloadOrder.indexOf(b)
74
+ );
75
+
76
+ const uniqueLibraries = [...new Set(results.map(r => r.library))];
77
+ const colors = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6"];
78
+
79
+ const chart: ChartData = {
80
+ title: "JSON Throughput by Payload Size",
81
+ payloads: uniquePayloads,
82
+ results,
83
+ };
84
+
85
+ const svg = generateGroupedBarSVG(chart, uniqueLibraries, colors);
86
+ writeFileSync(outputFile, svg, "utf-8");
87
+ console.log(`✅ Bar chart written to ${outputFile}`);
88
+ }
89
+
90
+ function inferImplementation(file: string): string {
91
+ return basename(file)
92
+ .replace(".log.json", "")
93
+ .replace(/\.bench\./g, " ")
94
+ .replace(/\./g, " ")
95
+ .trim();
96
+ }
97
+
98
+ function inferPayload(file: string): string {
99
+ const name = basename(file);
100
+ if (name.includes("abc.bench")) return "abc";
101
+ if (name.includes("vec3.bench")) return "vec3";
102
+ if (name.includes("small.bench")) return "small";
103
+ if (name.includes("medium.bench")) return "medium";
104
+ if (name.includes("large.bench")) return "large";
105
+ return "unknown";
106
+ }
107
+
108
+ function generateGroupedBarSVG(
109
+ data: ChartData,
110
+ libraries: string[],
111
+ colors: string[]
112
+ ): string {
113
+ const width = 900;
114
+ const height = 550;
115
+ const padding = { top: 80, right: 200, bottom: 80, left: 80 };
116
+ const chartWidth = width - padding.left - padding.right;
117
+ const chartHeight = height - padding.top - padding.bottom;
118
+
119
+ const barPadding = 0.1; // space between groups
120
+ const groupWidth = chartWidth / data.payloads.length;
121
+ const barWidth = groupWidth / libraries.length * (1 - barPadding);
122
+
123
+ const allValues = data.results.map(r => r.gbPerSec);
124
+ const yMax = Math.max(...allValues, 0.1) * 1.1;
125
+
126
+ const yScale = (v: number) =>
127
+ padding.top + chartHeight - (v / yMax) * chartHeight;
128
+
129
+ let svg = `<?xml version="1.0" encoding="UTF-8"?>
130
+ <svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
131
+ <defs>
132
+ <style>
133
+ .title { font: bold 20px sans-serif; fill: #1f2937; }
134
+ .axis-label { font: 14px sans-serif; fill: #374151; }
135
+ .tick { font: 12px sans-serif; fill: #6b7280; }
136
+ .grid { stroke: #e5e7eb; stroke-dasharray: 3,3; }
137
+ .axis { stroke: #9ca3af; stroke-width: 1.5; }
138
+ .bar-label { font: bold 11px sans-serif; fill: white; text-anchor: middle; }
139
+ .legend-text { font: 13px sans-serif; fill: #374151; }
140
+ </style>
141
+ </defs>
142
+
143
+ <rect width="${width}" height="${height}" fill="#fff"/>
144
+
145
+ <!-- Title -->
146
+ <text x="${width / 2}" y="40" text-anchor="middle" class="title">
147
+ ${data.title}
148
+ </text>
149
+
150
+ <!-- Y Axis Grid & Labels -->
151
+ `;
152
+ for (let i = 0; i <= 8; i++) {
153
+ const v = (yMax / 8) * i;
154
+ const y = yScale(v);
155
+ svg += `
156
+ <line x1="${padding.left}" y1="${y}" x2="${width - padding.right}" y2="${y}" class="grid"/>
157
+ <text x="${padding.left - 10}" y="${y + 4}" text-anchor="end" class="tick">
158
+ ${v.toFixed(2)} GB/s
159
+ </text>`;
160
+ }
161
+
162
+ // X Axis Labels (Payloads)
163
+ data.payloads.forEach((payload, i) => {
164
+ const x = padding.left + groupWidth * (i + 0.5);
165
+ svg += `<text x="${x}" y="${height - padding.bottom + 40}" text-anchor="middle" class="tick">
166
+ ${payload.toUpperCase()}
167
+ </text>`;
168
+ });
169
+
170
+ // Axes
171
+ svg += `
172
+ <line x1="${padding.left}" y1="${padding.top}" x2="${padding.left}" y2="${height - padding.bottom}" class="axis"/>
173
+ <line x1="${padding.left}" y1="${height - padding.bottom}" x2="${width - padding.right}" y2="${height - padding.bottom}" class="axis"/>
174
+
175
+ <text x="${width / 2}" y="${height - 20}" text-anchor="middle" class="axis-label">
176
+ Payload Type
177
+ </text>
178
+ <text x="-${height / 2}" y="20" transform="rotate(-90)" text-anchor="middle" class="axis-label">
179
+ Throughput (GB/s)
180
+ </text>
181
+ `;
182
+
183
+ // Bars
184
+ data.payloads.forEach((payload, payloadIdx) => {
185
+ const groupX = padding.left + groupWidth * payloadIdx;
186
+
187
+ libraries.forEach((lib, libIdx) => {
188
+ const result = data.results.find(r => r.payload === payload && r.library === lib);
189
+ if (!result) return;
190
+
191
+ const x = groupX + (libIdx + 0.1) * (groupWidth / libraries.length);
192
+ const barHeight = chartHeight - yScale(result.gbPerSec);
193
+ const y = yScale(result.gbPerSec);
194
+
195
+ const color = colors[libIdx % colors.length];
196
+
197
+ svg += `<rect x="${x}" y="${y}" width="${barWidth}" height="${barHeight}" fill="${color}" rx="4"/>
198
+ <text x="${x + barWidth / 2}" y="${y + 16}" class="bar-label">
199
+ ${result.gbPerSec.toFixed(2)}
200
+ </text>`;
201
+ });
202
+ });
203
+
204
+ // Legend
205
+ libraries.forEach((lib, i) => {
206
+ const y = padding.top + i * 30;
207
+ const color = colors[i % colors.length];
208
+ svg += `
209
+ <rect x="${width - padding.right + 20}" y="${y - 10}" width="18" height="18" fill="${color}" rx="4"/>
210
+ <text x="${width - padding.right + 50}" y="${y + 5}" class="legend-text">
211
+ ${lib}
212
+ </text>`;
213
+ });
214
+
215
+ return svg + "</svg>";
216
+ }
217
+ // bun ./bench/lib/chart.ts abc.bench.incremental.simd.as.log.json vec3.bench.incremental.simd.as.log.json small.bench.incremental.simd.as.log.json medium.bench.incremental.simd.as.log.json large.bench.incremental.simd.as.log.json -o throughput-comparison.svg