ic-mops 1.11.1 → 2.0.0

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 (352) hide show
  1. package/.DS_Store +0 -0
  2. package/.eslintrc.json +7 -7
  3. package/CHANGELOG.md +15 -0
  4. package/api/actors.ts +41 -37
  5. package/api/downloadPackageFiles.ts +75 -61
  6. package/api/getHighestVersion.ts +5 -5
  7. package/api/index.ts +4 -4
  8. package/api/network.ts +19 -21
  9. package/api/resolveVersion.ts +14 -11
  10. package/bin/mops.js +1 -1
  11. package/bun.lock +234 -198
  12. package/bundle/bench/bench-canister.mo +2 -2
  13. package/bundle/bench/user-bench.mo +0 -4
  14. package/bundle/bin/mops.js +1 -1
  15. package/bundle/cli.js +1000 -924
  16. package/bundle/cli.tgz +0 -0
  17. package/bundle/declarations/bench/bench.did +3 -3
  18. package/bundle/declarations/bench/bench.did.d.ts +3 -3
  19. package/bundle/declarations/bench/index.d.ts +3 -3
  20. package/bundle/declarations/bench/index.js +1 -1
  21. package/bundle/declarations/main/index.d.ts +3 -3
  22. package/bundle/declarations/main/index.js +1 -1
  23. package/bundle/declarations/main/main.did +78 -121
  24. package/bundle/declarations/main/main.did.d.ts +48 -98
  25. package/bundle/declarations/main/main.did.js +53 -107
  26. package/bundle/declarations/storage/index.d.ts +3 -3
  27. package/bundle/declarations/storage/index.js +4 -4
  28. package/bundle/declarations/storage/storage.did.d.ts +3 -3
  29. package/bundle/package.json +6 -5
  30. package/bundle/templates/mops-publish.yml +3 -3
  31. package/bundle/templates/mops-test.yml +3 -3
  32. package/bundle-package-json.ts +8 -8
  33. package/cache.ts +80 -65
  34. package/check-requirements.ts +49 -45
  35. package/cli.ts +577 -376
  36. package/commands/add.ts +142 -129
  37. package/commands/available-updates.ts +55 -28
  38. package/commands/bench/bench-canister.mo +114 -108
  39. package/commands/bench/user-bench.mo +6 -6
  40. package/commands/bench-replica.ts +146 -106
  41. package/commands/bench.ts +563 -497
  42. package/commands/build.ts +177 -0
  43. package/commands/bump.ts +68 -57
  44. package/commands/check-candid.ts +24 -0
  45. package/commands/docs-coverage.ts +124 -102
  46. package/commands/docs.ts +118 -108
  47. package/commands/format.ts +171 -155
  48. package/commands/init.ts +301 -275
  49. package/commands/install/install-all.ts +75 -62
  50. package/commands/install/install-dep.ts +43 -28
  51. package/commands/install/install-deps.ts +23 -15
  52. package/commands/install/install-local-dep.ts +42 -34
  53. package/commands/install/install-mops-dep.ts +154 -123
  54. package/commands/install/sync-local-cache.ts +39 -35
  55. package/commands/maintainer.ts +109 -99
  56. package/commands/outdated.ts +31 -18
  57. package/commands/owner.ts +107 -99
  58. package/commands/publish.ts +534 -443
  59. package/commands/remove.ts +119 -89
  60. package/commands/replica.ts +391 -303
  61. package/commands/search.ts +42 -36
  62. package/commands/self.ts +63 -56
  63. package/commands/sources.ts +66 -49
  64. package/commands/sync.ts +92 -75
  65. package/commands/template.ts +145 -102
  66. package/commands/test/mmf1.ts +146 -119
  67. package/commands/test/reporters/compact-reporter.ts +87 -84
  68. package/commands/test/reporters/files-reporter.ts +56 -51
  69. package/commands/test/reporters/reporter.ts +12 -6
  70. package/commands/test/reporters/silent-reporter.ts +58 -59
  71. package/commands/test/reporters/verbose-reporter.ts +66 -54
  72. package/commands/test/test.ts +497 -460
  73. package/commands/test/utils.ts +85 -6
  74. package/commands/toolchain/index.ts +363 -322
  75. package/commands/toolchain/moc.ts +78 -50
  76. package/commands/toolchain/pocket-ic.ts +41 -34
  77. package/commands/toolchain/toolchain-utils.ts +92 -72
  78. package/commands/toolchain/wasmtime.ts +37 -34
  79. package/commands/update.ts +91 -56
  80. package/commands/user.ts +90 -81
  81. package/commands/watch/deployer.ts +188 -152
  82. package/commands/watch/error-checker.ts +90 -80
  83. package/commands/watch/formatter.ts +72 -60
  84. package/commands/watch/generator.ts +116 -96
  85. package/commands/watch/globMoFiles.ts +13 -13
  86. package/commands/watch/parseDfxJson.ts +63 -57
  87. package/commands/watch/tester.ts +83 -65
  88. package/commands/watch/warning-checker.ts +149 -136
  89. package/commands/watch/watch.ts +123 -95
  90. package/declarations/bench/bench.did.d.ts +3 -3
  91. package/declarations/bench/index.d.ts +3 -3
  92. package/declarations/bench/index.js +1 -1
  93. package/declarations/main/index.d.ts +3 -3
  94. package/declarations/main/index.js +1 -1
  95. package/declarations/main/main.did.d.ts +3 -3
  96. package/declarations/storage/index.d.ts +3 -3
  97. package/declarations/storage/index.js +4 -4
  98. package/declarations/storage/storage.did.d.ts +3 -3
  99. package/dist/api/actors.d.ts +4 -4
  100. package/dist/api/actors.js +8 -8
  101. package/dist/api/downloadPackageFiles.d.ts +2 -2
  102. package/dist/api/downloadPackageFiles.js +10 -10
  103. package/dist/api/getHighestVersion.js +1 -1
  104. package/dist/api/index.d.ts +4 -4
  105. package/dist/api/index.js +4 -4
  106. package/dist/api/network.js +9 -9
  107. package/dist/api/resolveVersion.js +3 -3
  108. package/dist/bin/mops.js +1 -1
  109. package/dist/bundle-package-json.js +8 -8
  110. package/dist/cache.js +22 -17
  111. package/dist/check-requirements.js +11 -11
  112. package/dist/cli.js +283 -186
  113. package/dist/commands/add.d.ts +1 -1
  114. package/dist/commands/add.js +41 -38
  115. package/dist/commands/available-updates.d.ts +1 -1
  116. package/dist/commands/available-updates.js +32 -14
  117. package/dist/commands/bench/bench-canister.mo +114 -108
  118. package/dist/commands/bench/user-bench.mo +6 -6
  119. package/dist/commands/bench-replica.d.ts +6 -5
  120. package/dist/commands/bench-replica.js +58 -36
  121. package/dist/commands/bench.d.ts +5 -5
  122. package/dist/commands/bench.js +134 -118
  123. package/dist/commands/build.d.ts +7 -0
  124. package/dist/commands/build.js +121 -0
  125. package/dist/commands/bump.js +27 -18
  126. package/dist/commands/check-candid.d.ts +4 -0
  127. package/dist/commands/check-candid.js +15 -0
  128. package/dist/commands/docs-coverage.d.ts +1 -1
  129. package/dist/commands/docs-coverage.js +45 -31
  130. package/dist/commands/docs.d.ts +1 -1
  131. package/dist/commands/docs.js +39 -38
  132. package/dist/commands/format.js +31 -27
  133. package/dist/commands/init.js +102 -92
  134. package/dist/commands/install/install-all.d.ts +2 -2
  135. package/dist/commands/install/install-all.js +23 -21
  136. package/dist/commands/install/install-dep.d.ts +1 -1
  137. package/dist/commands/install/install-dep.js +21 -8
  138. package/dist/commands/install/install-deps.d.ts +1 -1
  139. package/dist/commands/install/install-deps.js +1 -1
  140. package/dist/commands/install/install-local-dep.js +11 -9
  141. package/dist/commands/install/install-mops-dep.d.ts +1 -1
  142. package/dist/commands/install/install-mops-dep.js +32 -27
  143. package/dist/commands/install/sync-local-cache.js +10 -10
  144. package/dist/commands/maintainer.js +21 -21
  145. package/dist/commands/outdated.js +16 -6
  146. package/dist/commands/owner.js +21 -21
  147. package/dist/commands/publish.js +148 -128
  148. package/dist/commands/remove.d.ts +1 -1
  149. package/dist/commands/remove.js +42 -30
  150. package/dist/commands/replica.d.ts +9 -8
  151. package/dist/commands/replica.js +105 -65
  152. package/dist/commands/search.js +15 -13
  153. package/dist/commands/self.js +31 -28
  154. package/dist/commands/sources.d.ts +5 -1
  155. package/dist/commands/sources.js +23 -17
  156. package/dist/commands/sync.d.ts +1 -1
  157. package/dist/commands/sync.js +38 -25
  158. package/dist/commands/template.js +66 -56
  159. package/dist/commands/test/mmf1.d.ts +3 -3
  160. package/dist/commands/test/mmf1.js +33 -31
  161. package/dist/commands/test/reporters/compact-reporter.d.ts +3 -3
  162. package/dist/commands/test/reporters/compact-reporter.js +19 -15
  163. package/dist/commands/test/reporters/files-reporter.d.ts +3 -3
  164. package/dist/commands/test/reporters/files-reporter.js +18 -14
  165. package/dist/commands/test/reporters/reporter.d.ts +2 -2
  166. package/dist/commands/test/reporters/silent-reporter.d.ts +3 -3
  167. package/dist/commands/test/reporters/silent-reporter.js +4 -4
  168. package/dist/commands/test/reporters/verbose-reporter.d.ts +3 -3
  169. package/dist/commands/test/reporters/verbose-reporter.js +17 -13
  170. package/dist/commands/test/test.d.ts +4 -4
  171. package/dist/commands/test/test.js +151 -181
  172. package/dist/commands/test/utils.d.ts +6 -0
  173. package/dist/commands/test/utils.js +63 -2
  174. package/dist/commands/toolchain/index.d.ts +1 -1
  175. package/dist/commands/toolchain/index.js +81 -69
  176. package/dist/commands/toolchain/moc.d.ts +1 -1
  177. package/dist/commands/toolchain/moc.js +48 -24
  178. package/dist/commands/toolchain/pocket-ic.js +12 -12
  179. package/dist/commands/toolchain/toolchain-utils.d.ts +2 -0
  180. package/dist/commands/toolchain/toolchain-utils.js +32 -23
  181. package/dist/commands/toolchain/wasmtime.js +11 -11
  182. package/dist/commands/update.d.ts +1 -1
  183. package/dist/commands/update.js +30 -12
  184. package/dist/commands/user.js +31 -28
  185. package/dist/commands/watch/deployer.d.ts +4 -4
  186. package/dist/commands/watch/deployer.js +45 -36
  187. package/dist/commands/watch/error-checker.d.ts +2 -2
  188. package/dist/commands/watch/error-checker.js +27 -27
  189. package/dist/commands/watch/formatter.d.ts +4 -4
  190. package/dist/commands/watch/formatter.js +17 -17
  191. package/dist/commands/watch/generator.d.ts +3 -3
  192. package/dist/commands/watch/generator.js +28 -23
  193. package/dist/commands/watch/globMoFiles.js +8 -8
  194. package/dist/commands/watch/parseDfxJson.d.ts +2 -2
  195. package/dist/commands/watch/parseDfxJson.js +9 -9
  196. package/dist/commands/watch/tester.d.ts +4 -4
  197. package/dist/commands/watch/tester.js +23 -21
  198. package/dist/commands/watch/warning-checker.d.ts +3 -3
  199. package/dist/commands/watch/warning-checker.js +36 -36
  200. package/dist/commands/watch/watch.js +45 -32
  201. package/dist/declarations/bench/bench.did.d.ts +3 -3
  202. package/dist/declarations/bench/index.d.ts +3 -3
  203. package/dist/declarations/bench/index.js +1 -1
  204. package/dist/declarations/main/index.d.ts +3 -3
  205. package/dist/declarations/main/index.js +1 -1
  206. package/dist/declarations/main/main.did.d.ts +3 -3
  207. package/dist/declarations/storage/index.d.ts +3 -3
  208. package/dist/declarations/storage/index.js +4 -4
  209. package/dist/declarations/storage/storage.did.d.ts +3 -3
  210. package/dist/environments/nodejs/cli.d.ts +1 -0
  211. package/dist/environments/nodejs/cli.js +4 -0
  212. package/dist/environments/web/cli.d.ts +1 -0
  213. package/dist/environments/web/cli.js +4 -0
  214. package/dist/error.d.ts +1 -0
  215. package/dist/error.js +5 -0
  216. package/dist/fix-dist.js +5 -5
  217. package/dist/helpers/find-changelog-entry.js +8 -5
  218. package/dist/helpers/get-dep-name.d.ts +1 -0
  219. package/dist/helpers/get-dep-name.js +4 -1
  220. package/dist/helpers/get-dfx-version.js +4 -4
  221. package/dist/helpers/get-moc-path.js +8 -7
  222. package/dist/helpers/get-moc-version.js +10 -7
  223. package/dist/helpers/get-package-id.js +2 -2
  224. package/dist/helpers/is-candid-compatible.d.ts +1 -0
  225. package/dist/helpers/is-candid-compatible.js +20 -0
  226. package/dist/integrity.d.ts +1 -1
  227. package/dist/integrity.js +47 -38
  228. package/dist/jest.config.d.ts +11 -0
  229. package/dist/jest.config.js +14 -0
  230. package/dist/mops.d.ts +6 -6
  231. package/dist/mops.js +87 -80
  232. package/dist/notify-installs.js +4 -4
  233. package/dist/package.json +11 -10
  234. package/dist/pem.d.ts +3 -3
  235. package/dist/pem.js +20 -12
  236. package/dist/release-cli.js +20 -20
  237. package/dist/resolve-packages.d.ts +1 -1
  238. package/dist/resolve-packages.js +52 -36
  239. package/dist/templates/mops-publish.yml +3 -3
  240. package/dist/templates/mops-test.yml +3 -3
  241. package/dist/templates/src/lib.mo +13 -13
  242. package/dist/templates/test/lib.test.mo +2 -2
  243. package/dist/templates.js +1 -1
  244. package/dist/tests/cli.test.d.ts +1 -0
  245. package/dist/tests/cli.test.js +63 -0
  246. package/dist/types.d.ts +14 -4
  247. package/dist/vessel.d.ts +2 -2
  248. package/dist/vessel.js +41 -34
  249. package/dist/wasm/pkg/bundler/package.json +20 -0
  250. package/dist/wasm/pkg/bundler/wasm.d.ts +3 -0
  251. package/dist/wasm/pkg/bundler/wasm.js +5 -0
  252. package/dist/wasm/pkg/bundler/wasm_bg.js +93 -0
  253. package/dist/wasm/pkg/bundler/wasm_bg.wasm +0 -0
  254. package/dist/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
  255. package/dist/wasm/pkg/nodejs/package.json +14 -0
  256. package/dist/wasm/pkg/nodejs/wasm.d.ts +3 -0
  257. package/dist/wasm/pkg/nodejs/wasm.js +98 -0
  258. package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  259. package/dist/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
  260. package/dist/wasm/pkg/web/package.json +18 -0
  261. package/dist/wasm/pkg/web/wasm.d.ts +35 -0
  262. package/dist/wasm/pkg/web/wasm.js +191 -0
  263. package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
  264. package/dist/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
  265. package/dist/wasm.d.ts +5 -0
  266. package/dist/wasm.js +10 -0
  267. package/environments/nodejs/cli.ts +6 -0
  268. package/environments/web/cli.ts +6 -0
  269. package/error.ts +6 -0
  270. package/fix-dist.ts +5 -5
  271. package/global.d.ts +3 -3
  272. package/helpers/find-changelog-entry.ts +26 -23
  273. package/helpers/get-dep-name.ts +7 -3
  274. package/helpers/get-dfx-version.ts +8 -9
  275. package/helpers/get-moc-path.ts +25 -26
  276. package/helpers/get-moc-version.ts +21 -19
  277. package/helpers/get-package-id.ts +4 -4
  278. package/helpers/is-candid-compatible.ts +22 -0
  279. package/integrity.ts +270 -236
  280. package/jest.config.js +14 -0
  281. package/mops.ts +238 -215
  282. package/notify-installs.ts +16 -17
  283. package/package.json +21 -15
  284. package/parallel.ts +28 -24
  285. package/pem.ts +55 -47
  286. package/release-cli.ts +73 -39
  287. package/resolve-packages.ts +231 -189
  288. package/templates/mops-publish.yml +3 -3
  289. package/templates/mops-test.yml +3 -3
  290. package/templates/src/lib.mo +13 -13
  291. package/templates/test/lib.test.mo +2 -2
  292. package/templates.ts +4 -4
  293. package/tests/__snapshots__/cli.test.ts.snap +202 -0
  294. package/tests/build/error/candid/bar.did +3 -0
  295. package/tests/build/error/dfx.json +12 -0
  296. package/tests/build/error/mops.toml +9 -0
  297. package/tests/build/error/src/Bar.mo +5 -0
  298. package/tests/build/error/src/Foo.mo +5 -0
  299. package/tests/build/success/.dfx/local/canister_ids.json +17 -0
  300. package/tests/build/success/.dfx/local/canisters/bar/bar.did +3 -0
  301. package/tests/build/success/.dfx/local/canisters/bar/bar.most +4 -0
  302. package/tests/build/success/.dfx/local/canisters/bar/bar.wasm +0 -0
  303. package/tests/build/success/.dfx/local/canisters/bar/constructor.did +3 -0
  304. package/tests/build/success/.dfx/local/canisters/bar/index.js +42 -0
  305. package/tests/build/success/.dfx/local/canisters/bar/init_args.txt +1 -0
  306. package/tests/build/success/.dfx/local/canisters/bar/service.did +3 -0
  307. package/tests/build/success/.dfx/local/canisters/bar/service.did.d.ts +7 -0
  308. package/tests/build/success/.dfx/local/canisters/bar/service.did.js +4 -0
  309. package/tests/build/success/.dfx/local/canisters/foo/constructor.did +3 -0
  310. package/tests/build/success/.dfx/local/canisters/foo/foo.did +3 -0
  311. package/tests/build/success/.dfx/local/canisters/foo/foo.most +4 -0
  312. package/tests/build/success/.dfx/local/canisters/foo/foo.wasm +0 -0
  313. package/tests/build/success/.dfx/local/canisters/foo/index.js +42 -0
  314. package/tests/build/success/.dfx/local/canisters/foo/init_args.txt +1 -0
  315. package/tests/build/success/.dfx/local/canisters/foo/service.did +3 -0
  316. package/tests/build/success/.dfx/local/canisters/foo/service.did.d.ts +7 -0
  317. package/tests/build/success/.dfx/local/canisters/foo/service.did.js +4 -0
  318. package/tests/build/success/.dfx/local/lsp/ucwa4-rx777-77774-qaada-cai.did +3 -0
  319. package/tests/build/success/.dfx/local/lsp/ulvla-h7777-77774-qaacq-cai.did +3 -0
  320. package/tests/build/success/.dfx/local/network-id +4 -0
  321. package/tests/build/success/candid/bar.did +3 -0
  322. package/tests/build/success/dfx.json +12 -0
  323. package/tests/build/success/mops.toml +9 -0
  324. package/tests/build/success/src/Bar.mo +5 -0
  325. package/tests/build/success/src/Foo.mo +5 -0
  326. package/tests/check-candid/a.did +3 -0
  327. package/tests/check-candid/b.did +5 -0
  328. package/tests/check-candid/c.did +3 -0
  329. package/tests/cli.test.ts +82 -0
  330. package/tsconfig.json +26 -19
  331. package/types.ts +41 -31
  332. package/vessel.ts +219 -187
  333. package/wasm/Cargo.lock +1475 -0
  334. package/wasm/Cargo.toml +28 -0
  335. package/wasm/pkg/bundler/package.json +20 -0
  336. package/wasm/pkg/bundler/wasm.d.ts +3 -0
  337. package/wasm/pkg/bundler/wasm.js +5 -0
  338. package/wasm/pkg/bundler/wasm_bg.js +93 -0
  339. package/wasm/pkg/bundler/wasm_bg.wasm +0 -0
  340. package/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
  341. package/wasm/pkg/nodejs/package.json +14 -0
  342. package/wasm/pkg/nodejs/wasm.d.ts +3 -0
  343. package/wasm/pkg/nodejs/wasm.js +98 -0
  344. package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  345. package/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
  346. package/wasm/pkg/web/package.json +18 -0
  347. package/wasm/pkg/web/wasm.d.ts +35 -0
  348. package/wasm/pkg/web/wasm.js +191 -0
  349. package/wasm/pkg/web/wasm_bg.wasm +0 -0
  350. package/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
  351. package/wasm/src/lib.rs +17 -0
  352. package/wasm.ts +16 -0
package/commands/bench.ts CHANGED
@@ -1,527 +1,593 @@
1
- import process from 'node:process';
2
- import path from 'node:path';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import chalk from 'chalk';
6
- import {globSync} from 'glob';
7
- import {markdownTable} from 'markdown-table';
8
- import {createLogUpdate} from 'log-update';
9
- import {execaCommand} from 'execa';
10
- import stringWidth from 'string-width';
11
- import {filesize} from 'filesize';
12
- import terminalSize from 'terminal-size';
13
- import {SemVer} from 'semver';
14
-
15
- import {getRootDir, readConfig, readDfxJson} from '../mops.js';
16
- import {parallel} from '../parallel.js';
17
- import {absToRel} from './test/utils.js';
18
- import {getMocVersion} from '../helpers/get-moc-version.js';
19
- import {getDfxVersion} from '../helpers/get-dfx-version.js';
20
- import {getMocPath} from '../helpers/get-moc-path.js';
21
- import {sources} from './sources.js';
22
-
23
- import {Benchmark, Benchmarks} from '../declarations/main/main.did.js';
24
- import {BenchResult, _SERVICE} from '../declarations/bench/bench.did.js';
25
- import {BenchReplica} from './bench-replica.js';
26
-
27
- type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
1
+ import process from "node:process";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import chalk from "chalk";
6
+ import { globSync } from "glob";
7
+ import { markdownTable } from "markdown-table";
8
+ import { createLogUpdate } from "log-update";
9
+ import { execaCommand } from "execa";
10
+ import stringWidth from "string-width";
11
+ import { filesize } from "filesize";
12
+ import terminalSize from "terminal-size";
13
+ import { SemVer } from "semver";
14
+
15
+ import { getRootDir, readConfig, readDfxJson } from "../mops.js";
16
+ import { parallel } from "../parallel.js";
17
+ import { absToRel } from "./test/utils.js";
18
+ import { getMocVersion } from "../helpers/get-moc-version.js";
19
+ import { getDfxVersion } from "../helpers/get-dfx-version.js";
20
+ import { getMocPath } from "../helpers/get-moc-path.js";
21
+ import { sources } from "./sources.js";
22
+
23
+ import { Benchmark, Benchmarks } from "../declarations/main/main.did.js";
24
+ import { BenchResult, _SERVICE } from "../declarations/bench/bench.did.js";
25
+ import { BenchReplica } from "./bench-replica.js";
26
+
27
+ type ReplicaName = "dfx" | "pocket-ic" | "dfx-pocket-ic";
28
28
 
29
29
  let ignore = [
30
- '**/node_modules/**',
31
- '**/.mops/**',
32
- '**/.vessel/**',
33
- '**/.git/**',
30
+ "**/node_modules/**",
31
+ "**/.mops/**",
32
+ "**/.vessel/**",
33
+ "**/.git/**",
34
34
  ];
35
35
 
36
36
  let globConfig = {
37
- nocase: true,
38
- ignore: ignore,
37
+ nocase: true,
38
+ ignore: ignore,
39
39
  };
40
40
 
41
41
  type BenchOptions = {
42
- replica : ReplicaName,
43
- replicaVersion : string,
44
- compiler : 'moc',
45
- compilerVersion : string,
46
- gc : 'copying' | 'compacting' | 'generational' | 'incremental',
47
- forceGc : boolean,
48
- save : boolean,
49
- compare : boolean,
50
- verbose : boolean,
51
- silent : boolean,
52
- profile : 'Debug' | 'Release',
42
+ replica: ReplicaName;
43
+ replicaVersion: string;
44
+ compiler: "moc";
45
+ compilerVersion: string;
46
+ gc: "copying" | "compacting" | "generational" | "incremental";
47
+ forceGc: boolean;
48
+ save: boolean;
49
+ compare: boolean;
50
+ verbose: boolean;
51
+ silent: boolean;
52
+ profile: "Debug" | "Release";
53
53
  };
54
54
 
55
- export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}) : Promise<Benchmarks> {
56
- let config = readConfig();
57
- let dfxJson = readDfxJson();
58
-
59
- let defaultOptions : BenchOptions = {
60
- replica: config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx',
61
- replicaVersion: '',
62
- compiler: 'moc',
63
- compilerVersion: getMocVersion(true),
64
- gc: 'copying',
65
- forceGc: true,
66
- save: false,
67
- compare: false,
68
- verbose: false,
69
- silent: false,
70
- profile: dfxJson?.profile || 'Release',
71
- };
72
-
73
- let options : BenchOptions = {...defaultOptions, ...optionsArg};
74
-
75
- let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx' as ReplicaName);
76
- if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
77
- let dfxVersion = getDfxVersion();
78
- if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
79
- console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
80
- process.exit(1);
81
- }
82
- else {
83
- replicaType = 'dfx-pocket-ic';
84
- }
85
- }
86
-
87
- options.replica = replicaType;
88
-
89
- if (process.env.CI) {
90
- console.log('# Benchmark Results\n\n');
91
- }
92
-
93
- if (replicaType == 'dfx') {
94
- options.replicaVersion = getDfxVersion();
95
- }
96
- else if (replicaType == 'pocket-ic') {
97
- options.replicaVersion = config.toolchain?.['pocket-ic'] || '';
98
- }
99
-
100
- options.verbose && console.log(options);
101
-
102
- let replica = new BenchReplica(replicaType, options.verbose);
103
-
104
- let rootDir = getRootDir();
105
- let globStr = '**/bench?(mark)/**/*.bench.mo';
106
- if (filter) {
107
- globStr = `**/bench?(mark)/**/*${filter}*.mo`;
108
- }
109
- let files = globSync(path.join(rootDir, globStr), globConfig);
110
- if (!files.length) {
111
- if (filter) {
112
- options.silent || console.log(`No benchmark files found for filter '${filter}'`);
113
- return [];
114
- }
115
- if (!options.silent) {
116
- console.log('No *.bench.mo files found');
117
- console.log('Put your benchmark code in \'bench\' directory in *.bench.mo files');
118
- }
119
- return [];
120
- }
121
-
122
- files.sort();
123
-
124
- let benchDir = `${getRootDir()}/.mops/.bench/`;
125
- fs.rmSync(benchDir, {recursive: true, force: true});
126
- fs.mkdirSync(benchDir, {recursive: true});
127
-
128
- if (!options.silent && !process.env.CI) {
129
- console.log('Benchmark files:');
130
- for (let file of files) {
131
- console.log(chalk.gray(`• ${absToRel(file)}`));
132
- }
133
- if (!process.env.CI) {
134
- console.log('');
135
- console.log('='.repeat(50));
136
- console.log('');
137
- }
138
- }
139
-
140
- await replica.start({silent: options.silent});
141
-
142
- if (!process.env.CI && !options.silent) {
143
- console.log('Deploying canisters...');
144
- }
145
-
146
- await parallel(os.cpus().length, files, async (file : string) => {
147
- try {
148
- await deployBenchFile(file, options, replica);
149
- }
150
- catch (err) {
151
- console.error('Unexpected error. Stopping replica...');
152
- await replica.stop();
153
- throw err;
154
- }
155
- });
156
-
157
- let benchResults : Benchmarks = [];
158
-
159
- await parallel(1, files, async (file : string) => {
160
- if (!options.silent && !process.env.CI) {
161
- console.log('\n' + '-'.repeat(50));
162
- console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
163
- console.log('');
164
- }
165
- try {
166
- let benchResult = await runBenchFile(file, options, replica);
167
- benchResults.push(benchResult);
168
- }
169
- catch (err) {
170
- console.error('Unexpected error. Stopping replica...');
171
- await replica.stop();
172
- throw err;
173
- }
174
- });
175
-
176
- if (!process.env.CI && !options.silent) {
177
- console.log('Stopping replica...');
178
- }
179
- await replica.stop();
180
-
181
- fs.rmSync(benchDir, {recursive: true, force: true});
182
-
183
- return benchResults;
55
+ export async function bench(
56
+ filter = "",
57
+ optionsArg: Partial<BenchOptions> = {},
58
+ ): Promise<Benchmarks> {
59
+ let config = readConfig();
60
+ let dfxJson = readDfxJson();
61
+
62
+ let defaultOptions: BenchOptions = {
63
+ replica: config.toolchain?.["pocket-ic"] ? "pocket-ic" : "dfx",
64
+ replicaVersion: "",
65
+ compiler: "moc",
66
+ compilerVersion: getMocVersion(true),
67
+ gc: "copying",
68
+ forceGc: true,
69
+ save: false,
70
+ compare: false,
71
+ verbose: false,
72
+ silent: false,
73
+ profile: dfxJson?.profile || "Release",
74
+ };
75
+
76
+ let options: BenchOptions = { ...defaultOptions, ...optionsArg };
77
+
78
+ let replicaType =
79
+ options.replica ??
80
+ (config.toolchain?.["pocket-ic"] ? "pocket-ic" : ("dfx" as ReplicaName));
81
+ if (replicaType === "pocket-ic" && !config.toolchain?.["pocket-ic"]) {
82
+ let dfxVersion = getDfxVersion();
83
+ if (!dfxVersion || new SemVer(dfxVersion).compare("0.24.1") < 0) {
84
+ console.log(
85
+ chalk.red(
86
+ "Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml",
87
+ ),
88
+ );
89
+ process.exit(1);
90
+ } else {
91
+ replicaType = "dfx-pocket-ic";
92
+ }
93
+ }
94
+
95
+ options.replica = replicaType;
96
+
97
+ if (process.env.CI) {
98
+ console.log("# Benchmark Results\n\n");
99
+ }
100
+
101
+ if (replicaType == "dfx") {
102
+ options.replicaVersion = getDfxVersion();
103
+ } else if (replicaType == "pocket-ic") {
104
+ options.replicaVersion = config.toolchain?.["pocket-ic"] || "";
105
+ }
106
+
107
+ options.verbose && console.log(options);
108
+
109
+ let replica = new BenchReplica(replicaType, options.verbose);
110
+
111
+ let rootDir = getRootDir();
112
+ let globStr = "**/bench?(mark)/**/*.bench.mo";
113
+ if (filter) {
114
+ globStr = `**/bench?(mark)/**/*${filter}*.mo`;
115
+ }
116
+ let files = globSync(path.join(rootDir, globStr), globConfig);
117
+ if (!files.length) {
118
+ if (filter) {
119
+ options.silent ||
120
+ console.log(`No benchmark files found for filter '${filter}'`);
121
+ return [];
122
+ }
123
+ if (!options.silent) {
124
+ console.log("No *.bench.mo files found");
125
+ console.log(
126
+ "Put your benchmark code in 'bench' directory in *.bench.mo files",
127
+ );
128
+ }
129
+ return [];
130
+ }
131
+
132
+ files.sort();
133
+
134
+ let benchDir = `${getRootDir()}/.mops/.bench/`;
135
+ fs.rmSync(benchDir, { recursive: true, force: true });
136
+ fs.mkdirSync(benchDir, { recursive: true });
137
+
138
+ if (!options.silent && !process.env.CI) {
139
+ console.log("Benchmark files:");
140
+ for (let file of files) {
141
+ console.log(chalk.gray(`• ${absToRel(file)}`));
142
+ }
143
+ if (!process.env.CI) {
144
+ console.log("");
145
+ console.log("=".repeat(50));
146
+ console.log("");
147
+ }
148
+ }
149
+
150
+ await replica.start({ silent: options.silent });
151
+
152
+ if (!process.env.CI && !options.silent) {
153
+ console.log("Deploying canisters...");
154
+ }
155
+
156
+ await parallel(os.cpus().length, files, async (file: string) => {
157
+ try {
158
+ await deployBenchFile(file, options, replica);
159
+ } catch (err) {
160
+ console.error("Unexpected error. Stopping replica...");
161
+ await replica.stop();
162
+ throw err;
163
+ }
164
+ });
165
+
166
+ let benchResults: Benchmarks = [];
167
+
168
+ await parallel(1, files, async (file: string) => {
169
+ if (!options.silent && !process.env.CI) {
170
+ console.log("\n" + "-".repeat(50));
171
+ console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
172
+ console.log("");
173
+ }
174
+ try {
175
+ let benchResult = await runBenchFile(file, options, replica);
176
+ benchResults.push(benchResult);
177
+ } catch (err) {
178
+ console.error("Unexpected error. Stopping replica...");
179
+ await replica.stop();
180
+ throw err;
181
+ }
182
+ });
183
+
184
+ if (!process.env.CI && !options.silent) {
185
+ console.log("Stopping replica...");
186
+ }
187
+ await replica.stop();
188
+
189
+ fs.rmSync(benchDir, { recursive: true, force: true });
190
+
191
+ return benchResults;
184
192
  }
185
193
 
186
194
  function computeDiff(
187
- results : Map<string, BenchResult>,
188
- prevResults : Map<string, BenchResult> | undefined,
189
- rows : string[],
190
- cols : string[],
191
- metric : keyof BenchResult,
192
- ) : number {
193
- let diff = 0;
194
- let count = 0;
195
-
196
- for (let [_rowIndex, row] of rows.entries()) {
197
- for (let [_colIndex, col] of cols.entries()) {
198
- let res = results.get(`${row}:${col}`);
199
- if (res && prevResults) {
200
- let prevRes = prevResults.get(`${row}:${col}`);
201
- if (prevRes) {
202
- let denom = Number(prevRes[metric]);
203
- let numerator = Number(res[metric]) - denom;
204
- let percent = 0;
205
- if (denom !== 0) {
206
- percent = (numerator / denom) * 100;
207
- }
208
- if (!Number.isFinite(percent)) {
209
- percent = 0;
210
- }
211
- diff += percent;
212
- count++;
213
- }
214
- }
215
- }
216
- }
217
-
218
- return count > 0 ? diff / count : 0;
195
+ results: Map<string, BenchResult>,
196
+ prevResults: Map<string, BenchResult> | undefined,
197
+ rows: string[],
198
+ cols: string[],
199
+ metric: keyof BenchResult,
200
+ ): number {
201
+ let diff = 0;
202
+ let count = 0;
203
+
204
+ for (let [_rowIndex, row] of rows.entries()) {
205
+ for (let [_colIndex, col] of cols.entries()) {
206
+ let res = results.get(`${row}:${col}`);
207
+ if (res && prevResults) {
208
+ let prevRes = prevResults.get(`${row}:${col}`);
209
+ if (prevRes) {
210
+ let denom = Number(prevRes[metric]);
211
+ let numerator = Number(res[metric]) - denom;
212
+ let percent = 0;
213
+ if (denom !== 0) {
214
+ percent = (numerator / denom) * 100;
215
+ }
216
+ if (!Number.isFinite(percent)) {
217
+ percent = 0;
218
+ }
219
+ diff += percent;
220
+ count++;
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ return count > 0 ? diff / count : 0;
219
227
  }
220
228
 
221
229
  function computeDiffAll(
222
- currentResults : Map<string, BenchResult>,
223
- prevResults : Map<string, BenchResult> | undefined,
224
- rows : string[],
225
- cols : string[],
226
- ) : number {
227
- let metrics : (keyof BenchResult)[] = ['instructions', 'rts_heap_size', 'rts_logical_stable_memory_size', 'rts_reclaimed'];
228
- let diff = 0;
229
-
230
- for (let metric of metrics) {
231
- diff += computeDiff(currentResults, prevResults, rows, cols, metric);
232
- }
233
-
234
- return diff;
230
+ currentResults: Map<string, BenchResult>,
231
+ prevResults: Map<string, BenchResult> | undefined,
232
+ rows: string[],
233
+ cols: string[],
234
+ ): number {
235
+ let metrics: (keyof BenchResult)[] = [
236
+ "instructions",
237
+ "rts_heap_size",
238
+ "rts_logical_stable_memory_size",
239
+ "rts_reclaimed",
240
+ ];
241
+ let diff = 0;
242
+
243
+ for (let metric of metrics) {
244
+ diff += computeDiff(currentResults, prevResults, rows, cols, metric);
245
+ }
246
+
247
+ return diff;
235
248
  }
236
249
 
237
- function getMocArgs(options : BenchOptions) : string {
238
- let args = '';
250
+ function getMocArgs(options: BenchOptions): string {
251
+ let args = "";
239
252
 
240
- if (options.compilerVersion && new SemVer(options.compilerVersion).compare('0.15.0') >= 0) {
241
- args += ' --legacy-persistence';
242
- }
253
+ if (
254
+ options.compilerVersion &&
255
+ new SemVer(options.compilerVersion).compare("0.15.0") >= 0
256
+ ) {
257
+ args += " --legacy-persistence";
258
+ }
243
259
 
244
- if (options.forceGc) {
245
- args += ' --force-gc';
246
- }
260
+ if (options.forceGc) {
261
+ args += " --force-gc";
262
+ }
247
263
 
248
- if (options.gc) {
249
- args += ` --${options.gc}-gc`;
250
- }
264
+ if (options.gc) {
265
+ args += ` --${options.gc}-gc`;
266
+ }
251
267
 
252
- if (options.profile === 'Debug') {
253
- args += ' --debug';
254
- }
255
- else if (options.profile === 'Release') {
256
- args += ' --release';
257
- }
268
+ if (options.profile === "Debug") {
269
+ args += " --debug";
270
+ } else if (options.profile === "Release") {
271
+ args += " --release";
272
+ }
258
273
 
259
- return args;
274
+ return args;
260
275
  }
261
276
 
262
- async function deployBenchFile(file : string, options : BenchOptions, replica : BenchReplica) : Promise<void> {
263
- let rootDir = getRootDir();
264
- let tempDir = path.join(rootDir, '.mops/.bench/', path.parse(file).name);
265
- let canisterName = path.parse(file).name;
266
-
267
- // prepare temp files
268
- fs.mkdirSync(tempDir, {recursive: true});
269
- fs.writeFileSync(path.join(tempDir, 'dfx.json'), JSON.stringify(replica.dfxJson(canisterName), null, 2));
270
-
271
- let benchCanisterData = fs.readFileSync(new URL('./bench/bench-canister.mo', import.meta.url), 'utf8');
272
- benchCanisterData = benchCanisterData.replace('./user-bench', path.relative(tempDir, file).replace(/.mo$/g, ''));
273
- fs.writeFileSync(path.join(tempDir, 'canister.mo'), benchCanisterData);
274
-
275
- // build canister
276
- let mocPath = getMocPath();
277
- let mocArgs = getMocArgs(options);
278
- options.verbose && console.time(`build ${canisterName}`);
279
- await execaCommand(`${mocPath} -c --idl canister.mo ${mocArgs} ${(await sources({cwd: tempDir})).join(' ')}`, {cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
280
- options.verbose && console.timeEnd(`build ${canisterName}`);
281
-
282
- // deploy canister
283
- let wasm = path.join(tempDir, 'canister.wasm');
284
- options.verbose && console.time(`deploy ${canisterName}`);
285
- // await execaCommand(`dfx deploy ${canisterName} --mode reinstall --yes --identity anonymous`, {cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
286
- await replica.deploy(canisterName, wasm, tempDir);
287
- options.verbose && console.timeEnd(`deploy ${canisterName}`);
288
-
289
- // init bench
290
- options.verbose && console.time(`init ${canisterName}`);
291
- let actor = await replica.getActor(canisterName) as _SERVICE;
292
- await actor.init();
293
- options.verbose && console.timeEnd(`init ${canisterName}`);
277
+ async function deployBenchFile(
278
+ file: string,
279
+ options: BenchOptions,
280
+ replica: BenchReplica,
281
+ ): Promise<void> {
282
+ let rootDir = getRootDir();
283
+ let tempDir = path.join(rootDir, ".mops/.bench/", path.parse(file).name);
284
+ let canisterName = path.parse(file).name;
285
+
286
+ // prepare temp files
287
+ fs.mkdirSync(tempDir, { recursive: true });
288
+ fs.writeFileSync(
289
+ path.join(tempDir, "dfx.json"),
290
+ JSON.stringify(replica.dfxJson(canisterName), null, 2),
291
+ );
292
+
293
+ let benchCanisterData = fs.readFileSync(
294
+ new URL("./bench/bench-canister.mo", import.meta.url),
295
+ "utf8",
296
+ );
297
+ benchCanisterData = benchCanisterData.replace(
298
+ "./user-bench",
299
+ path.relative(tempDir, file).replace(/.mo$/g, ""),
300
+ );
301
+ fs.writeFileSync(path.join(tempDir, "canister.mo"), benchCanisterData);
302
+
303
+ // build canister
304
+ let mocPath = getMocPath();
305
+ let mocArgs = getMocArgs(options);
306
+ options.verbose && console.time(`build ${canisterName}`);
307
+ await execaCommand(
308
+ `${mocPath} -c --idl canister.mo ${mocArgs} ${(await sources({ cwd: tempDir })).join(" ")}`,
309
+ {
310
+ cwd: tempDir,
311
+ stdio: options.verbose ? "pipe" : ["pipe", "ignore", "pipe"],
312
+ },
313
+ );
314
+ options.verbose && console.timeEnd(`build ${canisterName}`);
315
+
316
+ // deploy canister
317
+ let wasm = path.join(tempDir, "canister.wasm");
318
+ options.verbose && console.time(`deploy ${canisterName}`);
319
+ // await execaCommand(`dfx deploy ${canisterName} --mode reinstall --yes --identity anonymous`, {cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
320
+ await replica.deploy(canisterName, wasm, tempDir);
321
+ options.verbose && console.timeEnd(`deploy ${canisterName}`);
322
+
323
+ // init bench
324
+ options.verbose && console.time(`init ${canisterName}`);
325
+ let actor = (await replica.getActor(canisterName)) as _SERVICE;
326
+ await actor.init();
327
+ options.verbose && console.timeEnd(`init ${canisterName}`);
294
328
  }
295
329
 
296
- async function runBenchFile(file : string, options : BenchOptions, replica : BenchReplica) : Promise<Benchmark> {
297
- let rootDir = getRootDir();
298
- let canisterName = path.parse(file).name;
299
-
300
- let actor = await replica.getActor(canisterName) as _SERVICE;
301
- let schema = await actor.getSchema();
302
-
303
- // load previous results
304
- let prevResults : Map<string, BenchResult> | undefined;
305
- let resultsJsonFile = path.join(rootDir, '.bench', `${path.parse(file).name}.json`);
306
- if (options.compare) {
307
- if (fs.existsSync(resultsJsonFile)) {
308
- let prevResultsJson = JSON.parse(fs.readFileSync(resultsJsonFile).toString());
309
- prevResults = new Map(prevResultsJson.results);
310
- }
311
- else {
312
- console.log(chalk.yellow(`No previous results found "${resultsJsonFile}"`));
313
- }
314
- }
315
-
316
- let results = new Map<string, BenchResult>();
317
-
318
- let instructionsCells : bigint[][] = Array.from({length: schema.rows.length}, () => []);
319
- let heapCells : bigint[][] = Array.from({length: schema.rows.length}, () => []);
320
- let logicalStableMemoryCells : bigint[][] = Array.from({length: schema.rows.length}, () => []);
321
- let reclaimedCells : bigint[][] = Array.from({length: schema.rows.length}, () => []);
322
-
323
- let formatNumber = (n : bigint | number) : string => {
324
- return n.toLocaleString('en-US').replaceAll(',', '_');
325
- };
326
-
327
- let formatSize = (n : bigint | number) : string => {
328
- return filesize(n, {standard: 'iec', round: 2});
329
- };
330
-
331
- let colorizePercent = (percent : number, wrapInParens = false) : string => {
332
- let sign = percent > 0 ? '+' : '';
333
- let percentText = percent == 0 ? '0%' : sign + percent.toFixed(2) + '%';
334
- let color : keyof typeof chalk = percent == 0 ? 'gray' : (percent > 0 ? 'red' : 'green');
335
- let parens = wrapInParens ? ['(', ')'] : ['', ''];
336
- if (process.env.CI) {
337
- return `$${parens[0]}{\\color{${color}}${percentText.replace('%', '\\\\%')}}${parens[1]}$`;
338
- }
339
- else {
340
- return `${parens[0]}${chalk[color](percentText)}${parens[1]}`;
341
- }
342
- };
343
-
344
- let getTable = (prop : keyof BenchResult) : string => {
345
- let resArr = [['', ...schema.cols]];
346
- let allZero = true;
347
-
348
- for (let [_rowIndex, row] of schema.rows.entries()) {
349
- let curRow = [row];
350
-
351
- for (let [_colIndex, col] of schema.cols.entries()) {
352
- let res = results.get(`${row}:${col}`);
353
- if (res) {
354
- if (res[prop] != 0n) {
355
- allZero = false;
356
- }
357
-
358
- // compare with previous results
359
- let diff = '';
360
- if (options.compare && prevResults) {
361
- let prevRes = prevResults.get(`${row}:${col}`);
362
- if (prevRes) {
363
- let percent = (Number(res[prop]) - Number(prevRes[prop])) / Number(prevRes[prop]) * 100;
364
- if (Object.is(percent, NaN)) {
365
- percent = 0;
366
- }
367
- diff = ' ' + colorizePercent(percent, true);
368
- }
369
- else {
370
- diff = chalk.yellow(' (no previous results)');
371
- }
372
- }
373
-
374
- // add to table
375
- let value = '';
376
- if (prop == 'rts_logical_stable_memory_size') {
377
- value = formatSize(res[prop] * 65536n);
378
- }
379
- else if (prop === 'rts_heap_size' || prop == 'rts_reclaimed') {
380
- value = formatSize(res[prop]);
381
- }
382
- else {
383
- value = formatNumber(res[prop]);
384
- }
385
- curRow.push(value + diff);
386
- }
387
- else {
388
- curRow.push('');
389
- }
390
- }
391
- resArr.push(curRow);
392
- }
393
-
394
- // don't show Stable Memory table if all values are 0
395
- if (allZero && prop == 'rts_logical_stable_memory_size') {
396
- return '';
397
- }
398
-
399
- return markdownTable(resArr, {
400
- align: ['l', ...'r'.repeat(schema.cols.length)],
401
- stringLength: stringWidth,
402
- });
403
- };
404
-
405
- let logUpdate = createLogUpdate(process.stdout, {showCursor: true});
406
-
407
- let getOutput = () => {
408
- if (process.env.CI) {
409
- return [
410
- '\n<details>',
411
- `\n<summary>${absToRel(file)} ${colorizePercent(computeDiffAll(results, prevResults, schema.rows, schema.cols), true).replace('\\\\%', '\\%')}</summary>`,
412
- `\n${process.env.CI ? `### ${schema.name}` : chalk.bold(schema.name)}`,
413
- `${schema.description ? '\n' + (process.env.CI ? `_${schema.description}_` : chalk.gray(schema.description)) : ''}`,
414
- `\n\nInstructions: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, 'instructions'), false)}`,
415
- `Heap: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, 'rts_heap_size'), false)}`,
416
- `Stable Memory: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, 'rts_logical_stable_memory_size'), false)}`,
417
- `Garbage Collection: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, 'rts_reclaimed'), false)}`,
418
- `\n\n**Instructions**\n\n${getTable('instructions')}`,
419
- `\n\n**Heap**\n\n${getTable('rts_heap_size')}`,
420
- `\n\n**Garbage Collection**\n\n${getTable('rts_reclaimed')}`,
421
- `${getTable('rts_logical_stable_memory_size') ? `\n\n**Stable Memory**\n\n${getTable('rts_logical_stable_memory_size')}` : ''}`,
422
- '\n</details>',
423
- ].join('\n');
424
- }
425
- else {
426
- return `
330
+ async function runBenchFile(
331
+ file: string,
332
+ options: BenchOptions,
333
+ replica: BenchReplica,
334
+ ): Promise<Benchmark> {
335
+ let rootDir = getRootDir();
336
+ let canisterName = path.parse(file).name;
337
+
338
+ let actor = (await replica.getActor(canisterName)) as _SERVICE;
339
+ let schema = await actor.getSchema();
340
+
341
+ // load previous results
342
+ let prevResults: Map<string, BenchResult> | undefined;
343
+ let resultsJsonFile = path.join(
344
+ rootDir,
345
+ ".bench",
346
+ `${path.parse(file).name}.json`,
347
+ );
348
+ if (options.compare) {
349
+ if (fs.existsSync(resultsJsonFile)) {
350
+ let prevResultsJson = JSON.parse(
351
+ fs.readFileSync(resultsJsonFile).toString(),
352
+ );
353
+ prevResults = new Map(prevResultsJson.results);
354
+ } else {
355
+ console.log(
356
+ chalk.yellow(`No previous results found "${resultsJsonFile}"`),
357
+ );
358
+ }
359
+ }
360
+
361
+ let results = new Map<string, BenchResult>();
362
+
363
+ let instructionsCells: bigint[][] = Array.from(
364
+ { length: schema.rows.length },
365
+ () => [],
366
+ );
367
+ let heapCells: bigint[][] = Array.from(
368
+ { length: schema.rows.length },
369
+ () => [],
370
+ );
371
+ let logicalStableMemoryCells: bigint[][] = Array.from(
372
+ { length: schema.rows.length },
373
+ () => [],
374
+ );
375
+ let reclaimedCells: bigint[][] = Array.from(
376
+ { length: schema.rows.length },
377
+ () => [],
378
+ );
379
+
380
+ let formatNumber = (n: bigint | number): string => {
381
+ return n.toLocaleString("en-US").replaceAll(",", "_");
382
+ };
383
+
384
+ let formatSize = (n: bigint | number): string => {
385
+ return filesize(n, { standard: "iec", round: 2 });
386
+ };
387
+
388
+ let colorizePercent = (percent: number, wrapInParens = false): string => {
389
+ let sign = percent > 0 ? "+" : "";
390
+ let percentText = percent == 0 ? "0%" : sign + percent.toFixed(2) + "%";
391
+ let color: keyof typeof chalk =
392
+ percent == 0 ? "gray" : percent > 0 ? "red" : "green";
393
+ let parens = wrapInParens ? ["(", ")"] : ["", ""];
394
+ if (process.env.CI) {
395
+ return `$${parens[0]}{\\color{${color}}${percentText.replace("%", "\\\\%")}}${parens[1]}$`;
396
+ } else {
397
+ return `${parens[0]}${chalk[color](percentText)}${parens[1]}`;
398
+ }
399
+ };
400
+
401
+ let getTable = (prop: keyof BenchResult): string => {
402
+ let resArr = [["", ...schema.cols]];
403
+ let allZero = true;
404
+
405
+ for (let [_rowIndex, row] of schema.rows.entries()) {
406
+ let curRow = [row];
407
+
408
+ for (let [_colIndex, col] of schema.cols.entries()) {
409
+ let res = results.get(`${row}:${col}`);
410
+ if (res) {
411
+ if (res[prop] != 0n) {
412
+ allZero = false;
413
+ }
414
+
415
+ // compare with previous results
416
+ let diff = "";
417
+ if (options.compare && prevResults) {
418
+ let prevRes = prevResults.get(`${row}:${col}`);
419
+ if (prevRes) {
420
+ let percent =
421
+ ((Number(res[prop]) - Number(prevRes[prop])) /
422
+ Number(prevRes[prop])) *
423
+ 100;
424
+ if (Object.is(percent, NaN)) {
425
+ percent = 0;
426
+ }
427
+ diff = " " + colorizePercent(percent, true);
428
+ } else {
429
+ diff = chalk.yellow(" (no previous results)");
430
+ }
431
+ }
432
+
433
+ // add to table
434
+ let value = "";
435
+ if (prop == "rts_logical_stable_memory_size") {
436
+ value = formatSize(res[prop] * 65536n);
437
+ } else if (prop === "rts_heap_size" || prop == "rts_reclaimed") {
438
+ value = formatSize(res[prop]);
439
+ } else {
440
+ value = formatNumber(res[prop]);
441
+ }
442
+ curRow.push(value + diff);
443
+ } else {
444
+ curRow.push("");
445
+ }
446
+ }
447
+ resArr.push(curRow);
448
+ }
449
+
450
+ // don't show Stable Memory table if all values are 0
451
+ if (allZero && prop == "rts_logical_stable_memory_size") {
452
+ return "";
453
+ }
454
+
455
+ return markdownTable(resArr, {
456
+ align: ["l", ..."r".repeat(schema.cols.length)],
457
+ stringLength: stringWidth,
458
+ });
459
+ };
460
+
461
+ let logUpdate = createLogUpdate(process.stdout, { showCursor: true });
462
+
463
+ let getOutput = () => {
464
+ if (process.env.CI) {
465
+ return [
466
+ "\n<details>",
467
+ `\n<summary>${absToRel(file)} ${colorizePercent(computeDiffAll(results, prevResults, schema.rows, schema.cols), true).replace("\\\\%", "\\%")}</summary>`,
468
+ `\n${process.env.CI ? `### ${schema.name}` : chalk.bold(schema.name)}`,
469
+ `${schema.description ? "\n" + (process.env.CI ? `_${schema.description}_` : chalk.gray(schema.description)) : ""}`,
470
+ `\n\nInstructions: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, "instructions"), false)}`,
471
+ `Heap: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, "rts_heap_size"), false)}`,
472
+ `Stable Memory: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, "rts_logical_stable_memory_size"), false)}`,
473
+ `Garbage Collection: ${colorizePercent(computeDiff(results, prevResults, schema.rows, schema.cols, "rts_reclaimed"), false)}`,
474
+ `\n\n**Instructions**\n\n${getTable("instructions")}`,
475
+ `\n\n**Heap**\n\n${getTable("rts_heap_size")}`,
476
+ `\n\n**Garbage Collection**\n\n${getTable("rts_reclaimed")}`,
477
+ `${getTable("rts_logical_stable_memory_size") ? `\n\n**Stable Memory**\n\n${getTable("rts_logical_stable_memory_size")}` : ""}`,
478
+ "\n</details>",
479
+ ].join("\n");
480
+ } else {
481
+ return `
427
482
  \n${chalk.bold(schema.name)}
428
- ${schema.description ? '\n' + chalk.gray(schema.description) : ''}
429
- \n\n${chalk.blue('Instructions')}\n\n${getTable('instructions')}
430
- \n\n${chalk.blue('Heap')}\n\n${getTable('rts_heap_size')}
431
- \n\n${chalk.blue('Garbage Collection')}\n\n${getTable('rts_reclaimed')}
432
- ${getTable('rts_logical_stable_memory_size') ? `\n\n${chalk.blue('Stable Memory')}\n\n${getTable('rts_logical_stable_memory_size')}` : ''}
483
+ ${schema.description ? "\n" + chalk.gray(schema.description) : ""}
484
+ \n\n${chalk.blue("Instructions")}\n\n${getTable("instructions")}
485
+ \n\n${chalk.blue("Heap")}\n\n${getTable("rts_heap_size")}
486
+ \n\n${chalk.blue("Garbage Collection")}\n\n${getTable("rts_reclaimed")}
487
+ ${getTable("rts_logical_stable_memory_size") ? `\n\n${chalk.blue("Stable Memory")}\n\n${getTable("rts_logical_stable_memory_size")}` : ""}
433
488
  `;
434
- }
435
- };
436
-
437
- let canUpdateLog = !process.env.CI && !options.silent && terminalSize().rows > getOutput().split('\n').length;
438
-
439
- let log = () => {
440
- if (options.silent) {
441
- return;
442
- }
443
- let output = getOutput();
444
- if (process.env.CI || terminalSize().rows <= output.split('\n').length) {
445
- console.log(output);
446
- }
447
- else {
448
- logUpdate(output);
449
- }
450
- };
451
-
452
- if (canUpdateLog) {
453
- log();
454
- }
455
-
456
- // run all cells
457
- for (let [rowIndex, row] of schema.rows.entries()) {
458
- for (let [colIndex, col] of schema.cols.entries()) {
459
- let res = await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
460
- results.set(`${row}:${col}`, res);
461
-
462
- // @ts-ignore
463
- instructionsCells[rowIndex][colIndex] = res.instructions;
464
- // @ts-ignore
465
- heapCells[rowIndex][colIndex] = res.rts_heap_size;
466
- // @ts-ignore
467
- logicalStableMemoryCells[rowIndex][colIndex] = res.rts_logical_stable_memory_size;
468
- // @ts-ignore
469
- reclaimedCells[rowIndex][colIndex] = res.rts_reclaimed;
470
-
471
- if (canUpdateLog) {
472
- log();
473
- }
474
- }
475
- }
476
-
477
- if (canUpdateLog) {
478
- logUpdate.done();
479
- }
480
- else {
481
- log();
482
- }
483
-
484
- // save results
485
- if (options.save) {
486
- console.log(`Saving results to ${chalk.gray(absToRel(resultsJsonFile))}`);
487
- let json : Record<any, any> = {
488
- version: 1,
489
- moc: options.compilerVersion,
490
- replica: options.replica,
491
- replicaVersion: options.replicaVersion,
492
- gc: options.gc,
493
- forceGc: options.forceGc,
494
- results: Array.from(results.entries()),
495
- };
496
- fs.mkdirSync(path.dirname(resultsJsonFile), {recursive: true});
497
- fs.writeFileSync(resultsJsonFile, JSON.stringify(json, (_, val) => {
498
- if (typeof val === 'bigint') {
499
- return Number(val);
500
- }
501
- else {
502
- return val;
503
- }
504
- }, 2));
505
- }
506
-
507
- // for backend
508
- return {
509
- name: schema.name,
510
- description: schema.description,
511
- file: absToRel(file),
512
- gc: options.gc,
513
- forceGC: options.forceGc,
514
- replica: options.replica,
515
- replicaVersion: options.replicaVersion,
516
- compiler: options.compiler,
517
- compilerVersion: options.compilerVersion,
518
- rows: schema.rows,
519
- cols: schema.cols,
520
- metrics: [
521
- ['instructions', instructionsCells],
522
- ['rts_heap_size', heapCells],
523
- ['rts_logical_stable_memory_size', logicalStableMemoryCells],
524
- ['rts_reclaimed', reclaimedCells],
525
- ],
526
- };
489
+ }
490
+ };
491
+
492
+ let canUpdateLog =
493
+ !process.env.CI &&
494
+ !options.silent &&
495
+ terminalSize().rows > getOutput().split("\n").length;
496
+
497
+ let log = () => {
498
+ if (options.silent) {
499
+ return;
500
+ }
501
+ let output = getOutput();
502
+ if (process.env.CI || terminalSize().rows <= output.split("\n").length) {
503
+ console.log(output);
504
+ } else {
505
+ logUpdate(output);
506
+ }
507
+ };
508
+
509
+ if (canUpdateLog) {
510
+ log();
511
+ }
512
+
513
+ // run all cells
514
+ for (let [rowIndex, row] of schema.rows.entries()) {
515
+ for (let [colIndex, col] of schema.cols.entries()) {
516
+ let res = await actor.runCellUpdateAwait(
517
+ BigInt(rowIndex),
518
+ BigInt(colIndex),
519
+ );
520
+ results.set(`${row}:${col}`, res);
521
+
522
+ // @ts-ignore
523
+ instructionsCells[rowIndex][colIndex] = res.instructions;
524
+ // @ts-ignore
525
+ heapCells[rowIndex][colIndex] = res.rts_heap_size;
526
+ // @ts-ignore
527
+ logicalStableMemoryCells[rowIndex][colIndex] =
528
+ res.rts_logical_stable_memory_size;
529
+ // @ts-ignore
530
+ reclaimedCells[rowIndex][colIndex] = res.rts_reclaimed;
531
+
532
+ if (canUpdateLog) {
533
+ log();
534
+ }
535
+ }
536
+ }
537
+
538
+ if (canUpdateLog) {
539
+ logUpdate.done();
540
+ } else {
541
+ log();
542
+ }
543
+
544
+ // save results
545
+ if (options.save) {
546
+ console.log(`Saving results to ${chalk.gray(absToRel(resultsJsonFile))}`);
547
+ let json: Record<any, any> = {
548
+ version: 1,
549
+ moc: options.compilerVersion,
550
+ replica: options.replica,
551
+ replicaVersion: options.replicaVersion,
552
+ gc: options.gc,
553
+ forceGc: options.forceGc,
554
+ results: Array.from(results.entries()),
555
+ };
556
+ fs.mkdirSync(path.dirname(resultsJsonFile), { recursive: true });
557
+ fs.writeFileSync(
558
+ resultsJsonFile,
559
+ JSON.stringify(
560
+ json,
561
+ (_, val) => {
562
+ if (typeof val === "bigint") {
563
+ return Number(val);
564
+ } else {
565
+ return val;
566
+ }
567
+ },
568
+ 2,
569
+ ),
570
+ );
571
+ }
572
+
573
+ // for backend
574
+ return {
575
+ name: schema.name,
576
+ description: schema.description,
577
+ file: absToRel(file),
578
+ gc: options.gc,
579
+ forceGC: options.forceGc,
580
+ replica: options.replica,
581
+ replicaVersion: options.replicaVersion,
582
+ compiler: options.compiler,
583
+ compilerVersion: options.compilerVersion,
584
+ rows: schema.rows,
585
+ cols: schema.cols,
586
+ metrics: [
587
+ ["instructions", instructionsCells],
588
+ ["rts_heap_size", heapCells],
589
+ ["rts_logical_stable_memory_size", logicalStableMemoryCells],
590
+ ["rts_reclaimed", reclaimedCells],
591
+ ],
592
+ };
527
593
  }