ic-mops 0.28.1 → 0.28.2

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 (46) hide show
  1. package/.gitignore +2 -1
  2. package/LICENSE +21 -0
  3. package/commands/init.ts +16 -9
  4. package/declarations/main/main.did +36 -0
  5. package/declarations/main/main.did.d.ts +28 -0
  6. package/declarations/main/main.did.js +32 -0
  7. package/dist/bench/$USER_BENCH_FILE.mo +45 -0
  8. package/dist/bench/bench-canister.mo +57 -0
  9. package/dist/commands/bench/$USER_BENCH_FILE.mo +45 -0
  10. package/dist/commands/bench/bench/$USER_BENCH_FILE.mo +45 -0
  11. package/dist/commands/bench/bench/bench-canister.mo +57 -0
  12. package/dist/commands/bench/bench-canister.mo +85 -0
  13. package/dist/commands/bench/declarations/bench/bench.did.d.ts +6 -0
  14. package/dist/commands/bench/declarations/bench/bench.did.js +22 -0
  15. package/dist/commands/bench/declarations/bench/index.d.ts +2 -0
  16. package/dist/commands/bench/declarations/bench/index.js +30 -0
  17. package/dist/commands/bench/declarations/main/index.d.ts +2 -0
  18. package/dist/commands/bench/declarations/main/index.js +30 -0
  19. package/dist/commands/bench/declarations/main/main.did.d.ts +6 -0
  20. package/dist/commands/bench/declarations/main/main.did.js +242 -0
  21. package/dist/commands/bench/declarations/storage/index.d.ts +4 -0
  22. package/dist/commands/bench/declarations/storage/index.js +26 -0
  23. package/dist/commands/bench/declarations/storage/storage.did.d.ts +6 -0
  24. package/dist/commands/bench/declarations/storage/storage.did.js +34 -0
  25. package/dist/commands/bench/user-bench.mo +14 -0
  26. package/dist/commands/bench.d.ts +9 -2
  27. package/dist/commands/bench.js +155 -71
  28. package/dist/commands/init.js +16 -9
  29. package/dist/declarations/bench/bench.did +24 -0
  30. package/dist/declarations/bench/bench.did.d.ts +24 -0
  31. package/dist/declarations/bench/bench.did.js +24 -0
  32. package/dist/declarations/bench/index.d.ts +50 -0
  33. package/dist/declarations/bench/index.js +41 -0
  34. package/dist/declarations/main/main.did +36 -0
  35. package/dist/declarations/main/main.did.d.ts +28 -0
  36. package/dist/declarations/main/main.did.js +32 -0
  37. package/dist/helpers/get-dfx-version.d.ts +1 -0
  38. package/dist/helpers/get-dfx-version.js +9 -0
  39. package/dist/helpers/get-moc-path.d.ts +1 -0
  40. package/dist/helpers/get-moc-path.js +11 -0
  41. package/dist/helpers/get-moc-version.d.ts +1 -0
  42. package/dist/helpers/get-moc-version.js +7 -0
  43. package/dist/package.json +1 -1
  44. package/mops.toml +7 -0
  45. package/package.json +1 -1
  46. package/src/lib.mo +15 -0
@@ -0,0 +1,242 @@
1
+ export const idlFactory = ({ IDL }) => {
2
+ const TestsChanges = IDL.Record({
3
+ 'addedNames': IDL.Vec(IDL.Text),
4
+ 'removedNames': IDL.Vec(IDL.Text),
5
+ });
6
+ const DepChange = IDL.Record({
7
+ 'oldVersion': IDL.Text,
8
+ 'name': IDL.Text,
9
+ 'newVersion': IDL.Text,
10
+ });
11
+ const PackageChanges__1 = IDL.Record({
12
+ 'tests': TestsChanges,
13
+ 'deps': IDL.Vec(DepChange),
14
+ 'notes': IDL.Text,
15
+ 'devDeps': IDL.Vec(DepChange),
16
+ });
17
+ const PublishingId = IDL.Text;
18
+ const Err = IDL.Text;
19
+ const Result = IDL.Variant({ 'ok': IDL.Null, 'err': Err });
20
+ const Text = IDL.Text;
21
+ const PackageName__1 = IDL.Text;
22
+ const PackageVersion = IDL.Text;
23
+ const PackageId = IDL.Text;
24
+ const Time = IDL.Int;
25
+ const DownloadsSnapshot__1 = IDL.Record({
26
+ 'startTime': Time,
27
+ 'endTime': Time,
28
+ 'downloads': IDL.Nat,
29
+ });
30
+ const FileId = IDL.Text;
31
+ const Result_7 = IDL.Variant({ 'ok': IDL.Vec(FileId), 'err': Err });
32
+ const SemverPart = IDL.Variant({
33
+ 'major': IDL.Null,
34
+ 'minor': IDL.Null,
35
+ 'patch': IDL.Null,
36
+ });
37
+ const Result_6 = IDL.Variant({
38
+ 'ok': IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion)),
39
+ 'err': Err,
40
+ });
41
+ const Result_5 = IDL.Variant({ 'ok': PackageVersion, 'err': Err });
42
+ const User = IDL.Record({
43
+ 'id': IDL.Principal,
44
+ 'emailVerified': IDL.Bool,
45
+ 'twitter': IDL.Text,
46
+ 'displayName': IDL.Text,
47
+ 'name': IDL.Text,
48
+ 'site': IDL.Text,
49
+ 'email': IDL.Text,
50
+ 'twitterVerified': IDL.Bool,
51
+ 'githubVerified': IDL.Bool,
52
+ 'github': IDL.Text,
53
+ });
54
+ const Script = IDL.Record({ 'value': IDL.Text, 'name': IDL.Text });
55
+ const PackageName = IDL.Text;
56
+ const DependencyV2 = IDL.Record({
57
+ 'name': PackageName,
58
+ 'repo': IDL.Text,
59
+ 'version': IDL.Text,
60
+ });
61
+ const PackageConfigV2__1 = IDL.Record({
62
+ 'dfx': IDL.Text,
63
+ 'moc': IDL.Text,
64
+ 'scripts': IDL.Vec(Script),
65
+ 'baseDir': IDL.Text,
66
+ 'documentation': IDL.Text,
67
+ 'name': PackageName,
68
+ 'homepage': IDL.Text,
69
+ 'description': IDL.Text,
70
+ 'version': IDL.Text,
71
+ 'keywords': IDL.Vec(IDL.Text),
72
+ 'donation': IDL.Text,
73
+ 'devDependencies': IDL.Vec(DependencyV2),
74
+ 'repository': IDL.Text,
75
+ 'dependencies': IDL.Vec(DependencyV2),
76
+ 'license': IDL.Text,
77
+ 'readme': IDL.Text,
78
+ });
79
+ const PackagePublication = IDL.Record({
80
+ 'storage': IDL.Principal,
81
+ 'time': Time,
82
+ 'user': IDL.Principal,
83
+ });
84
+ const PackageSummary = IDL.Record({
85
+ 'ownerInfo': User,
86
+ 'owner': IDL.Principal,
87
+ 'downloadsTotal': IDL.Nat,
88
+ 'downloadsInLast30Days': IDL.Nat,
89
+ 'downloadsInLast7Days': IDL.Nat,
90
+ 'config': PackageConfigV2__1,
91
+ 'publication': PackagePublication,
92
+ });
93
+ const PackageSummary__1 = IDL.Record({
94
+ 'ownerInfo': User,
95
+ 'owner': IDL.Principal,
96
+ 'downloadsTotal': IDL.Nat,
97
+ 'downloadsInLast30Days': IDL.Nat,
98
+ 'downloadsInLast7Days': IDL.Nat,
99
+ 'config': PackageConfigV2__1,
100
+ 'publication': PackagePublication,
101
+ });
102
+ const TestStats__1 = IDL.Record({
103
+ 'passedNames': IDL.Vec(IDL.Text),
104
+ 'passed': IDL.Nat,
105
+ });
106
+ const DownloadsSnapshot = IDL.Record({
107
+ 'startTime': Time,
108
+ 'endTime': Time,
109
+ 'downloads': IDL.Nat,
110
+ });
111
+ const PackageFileStatsPublic = IDL.Record({
112
+ 'sourceFiles': IDL.Nat,
113
+ 'sourceSize': IDL.Nat,
114
+ });
115
+ const PackageChanges = IDL.Record({
116
+ 'tests': TestsChanges,
117
+ 'deps': IDL.Vec(DepChange),
118
+ 'notes': IDL.Text,
119
+ 'devDeps': IDL.Vec(DepChange),
120
+ });
121
+ const PackageSummaryWithChanges__1 = IDL.Record({
122
+ 'ownerInfo': User,
123
+ 'owner': IDL.Principal,
124
+ 'downloadsTotal': IDL.Nat,
125
+ 'downloadsInLast30Days': IDL.Nat,
126
+ 'downloadsInLast7Days': IDL.Nat,
127
+ 'config': PackageConfigV2__1,
128
+ 'changes': PackageChanges,
129
+ 'publication': PackagePublication,
130
+ });
131
+ const PackageDetails = IDL.Record({
132
+ 'ownerInfo': User,
133
+ 'owner': IDL.Principal,
134
+ 'deps': IDL.Vec(PackageSummary__1),
135
+ 'testStats': TestStats__1,
136
+ 'downloadsTotal': IDL.Nat,
137
+ 'downloadsInLast30Days': IDL.Nat,
138
+ 'downloadTrend': IDL.Vec(DownloadsSnapshot),
139
+ 'fileStats': PackageFileStatsPublic,
140
+ 'versionHistory': IDL.Vec(PackageSummaryWithChanges__1),
141
+ 'dependents': IDL.Vec(PackageSummary__1),
142
+ 'devDeps': IDL.Vec(PackageSummary__1),
143
+ 'downloadsInLast7Days': IDL.Nat,
144
+ 'config': PackageConfigV2__1,
145
+ 'changes': PackageChanges,
146
+ 'publication': PackagePublication,
147
+ });
148
+ const Result_4 = IDL.Variant({ 'ok': PackageDetails, 'err': Err });
149
+ const PackageSummaryWithChanges = IDL.Record({
150
+ 'ownerInfo': User,
151
+ 'owner': IDL.Principal,
152
+ 'downloadsTotal': IDL.Nat,
153
+ 'downloadsInLast30Days': IDL.Nat,
154
+ 'downloadsInLast7Days': IDL.Nat,
155
+ 'config': PackageConfigV2__1,
156
+ 'changes': PackageChanges,
157
+ 'publication': PackagePublication,
158
+ });
159
+ const StorageId = IDL.Principal;
160
+ const StorageStats = IDL.Record({
161
+ 'fileCount': IDL.Nat,
162
+ 'cyclesBalance': IDL.Nat,
163
+ 'memorySize': IDL.Nat,
164
+ });
165
+ const User__1 = IDL.Record({
166
+ 'id': IDL.Principal,
167
+ 'emailVerified': IDL.Bool,
168
+ 'twitter': IDL.Text,
169
+ 'displayName': IDL.Text,
170
+ 'name': IDL.Text,
171
+ 'site': IDL.Text,
172
+ 'email': IDL.Text,
173
+ 'twitterVerified': IDL.Bool,
174
+ 'githubVerified': IDL.Bool,
175
+ 'github': IDL.Text,
176
+ });
177
+ const PageCount = IDL.Nat;
178
+ const Result_3 = IDL.Variant({ 'ok': IDL.Null, 'err': IDL.Text });
179
+ const Result_2 = IDL.Variant({ 'ok': FileId, 'err': Err });
180
+ const PackageConfigV2 = IDL.Record({
181
+ 'dfx': IDL.Text,
182
+ 'moc': IDL.Text,
183
+ 'scripts': IDL.Vec(Script),
184
+ 'baseDir': IDL.Text,
185
+ 'documentation': IDL.Text,
186
+ 'name': PackageName,
187
+ 'homepage': IDL.Text,
188
+ 'description': IDL.Text,
189
+ 'version': IDL.Text,
190
+ 'keywords': IDL.Vec(IDL.Text),
191
+ 'donation': IDL.Text,
192
+ 'devDependencies': IDL.Vec(DependencyV2),
193
+ 'repository': IDL.Text,
194
+ 'dependencies': IDL.Vec(DependencyV2),
195
+ 'license': IDL.Text,
196
+ 'readme': IDL.Text,
197
+ });
198
+ const PublishingErr = IDL.Text;
199
+ const Result_1 = IDL.Variant({ 'ok': PublishingId, 'err': PublishingErr });
200
+ const TestStats = IDL.Record({
201
+ 'passedNames': IDL.Vec(IDL.Text),
202
+ 'passed': IDL.Nat,
203
+ });
204
+ return IDL.Service({
205
+ 'backup': IDL.Func([], [], []),
206
+ 'claimAirdrop': IDL.Func([IDL.Principal], [IDL.Text], []),
207
+ 'diff': IDL.Func([IDL.Text, IDL.Text], [PackageChanges__1], ['query']),
208
+ 'finishPublish': IDL.Func([PublishingId], [Result], []),
209
+ 'getAirdropAmount': IDL.Func([], [IDL.Nat], ['query']),
210
+ 'getAirdropAmountAll': IDL.Func([], [IDL.Nat], ['query']),
211
+ 'getApiVersion': IDL.Func([], [Text], ['query']),
212
+ 'getBackupCanisterId': IDL.Func([], [IDL.Principal], ['query']),
213
+ 'getDefaultPackages': IDL.Func([IDL.Text], [IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion))], ['query']),
214
+ 'getDownloadTrendByPackageId': IDL.Func([PackageId], [IDL.Vec(DownloadsSnapshot__1)], ['query']),
215
+ 'getDownloadTrendByPackageName': IDL.Func([PackageName__1], [IDL.Vec(DownloadsSnapshot__1)], ['query']),
216
+ 'getFileIds': IDL.Func([PackageName__1, PackageVersion], [Result_7], ['query']),
217
+ 'getHighestSemverBatch': IDL.Func([IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion, SemverPart))], [Result_6], ['query']),
218
+ 'getHighestVersion': IDL.Func([PackageName__1], [Result_5], ['query']),
219
+ 'getMostDownloadedPackages': IDL.Func([], [IDL.Vec(PackageSummary)], ['query']),
220
+ 'getMostDownloadedPackagesIn7Days': IDL.Func([], [IDL.Vec(PackageSummary)], ['query']),
221
+ 'getNewPackages': IDL.Func([], [IDL.Vec(PackageSummary)], ['query']),
222
+ 'getPackageDetails': IDL.Func([PackageName__1, PackageVersion], [Result_4], ['query']),
223
+ 'getPackagesByCategory': IDL.Func([], [IDL.Vec(IDL.Tuple(IDL.Text, IDL.Vec(PackageSummary)))], ['query']),
224
+ 'getRecentlyUpdatedPackages': IDL.Func([], [IDL.Vec(PackageSummaryWithChanges)], ['query']),
225
+ 'getStoragesStats': IDL.Func([], [IDL.Vec(IDL.Tuple(StorageId, StorageStats))], ['query']),
226
+ 'getTotalDownloads': IDL.Func([], [IDL.Nat], ['query']),
227
+ 'getTotalPackages': IDL.Func([], [IDL.Nat], ['query']),
228
+ 'getUser': IDL.Func([IDL.Principal], [IDL.Opt(User__1)], ['query']),
229
+ 'notifyInstall': IDL.Func([PackageName__1, PackageVersion], [], ['oneway']),
230
+ 'notifyInstalls': IDL.Func([IDL.Vec(IDL.Tuple(PackageName__1, PackageVersion))], [], ['oneway']),
231
+ 'restore': IDL.Func([IDL.Nat, IDL.Nat], [], []),
232
+ 'search': IDL.Func([Text, IDL.Opt(IDL.Nat), IDL.Opt(IDL.Nat)], [IDL.Vec(PackageSummary), PageCount], ['query']),
233
+ 'setUserProp': IDL.Func([IDL.Text, IDL.Text], [Result_3], []),
234
+ 'startFileUpload': IDL.Func([PublishingId, Text, IDL.Nat, IDL.Vec(IDL.Nat8)], [Result_2], []),
235
+ 'startPublish': IDL.Func([PackageConfigV2], [Result_1], []),
236
+ 'takeAirdropSnapshot': IDL.Func([], [], ['oneway']),
237
+ 'uploadFileChunk': IDL.Func([PublishingId, FileId, IDL.Nat, IDL.Vec(IDL.Nat8)], [Result], []),
238
+ 'uploadNotes': IDL.Func([PublishingId, IDL.Text], [Result], []),
239
+ 'uploadTestStats': IDL.Func([PublishingId, TestStats], [Result], []),
240
+ });
241
+ };
242
+ export const init = ({ IDL }) => { return []; };
@@ -0,0 +1,4 @@
1
+ export function createActor(canisterId: string | import("@dfinity/principal").Principal, options?: {
2
+ agentOptions?: import("@dfinity/agent").HttpAgentOptions;
3
+ actorOptions?: import("@dfinity/agent").ActorConfig;
4
+ } | undefined): import("@dfinity/agent").ActorSubclass<import("./storage.did.js")._SERVICE>;
@@ -0,0 +1,26 @@
1
+ import { Actor, HttpAgent } from "@dfinity/agent";
2
+ // Imports and re-exports candid interface
3
+ import { idlFactory } from './storage.did.js';
4
+ export { idlFactory } from './storage.did.js';
5
+ /**
6
+ *
7
+ * @param {string | import("@dfinity/principal").Principal} canisterId Canister ID of Agent
8
+ * @param {{agentOptions?: import("@dfinity/agent").HttpAgentOptions; actorOptions?: import("@dfinity/agent").ActorConfig}} [options]
9
+ * @return {import("@dfinity/agent").ActorSubclass<import("./storage.did.js")._SERVICE>}
10
+ */
11
+ export const createActor = (canisterId, options) => {
12
+ const agent = new HttpAgent({ ...options?.agentOptions });
13
+ // Fetch root key for certificate validation during development
14
+ if (process.env.NODE_ENV !== "production") {
15
+ agent.fetchRootKey().catch(err => {
16
+ console.warn("Unable to fetch root key. Check to ensure that your local replica is running");
17
+ console.error(err);
18
+ });
19
+ }
20
+ // Creates an actor with using the candid interface and the HttpAgent
21
+ return Actor.createActor(idlFactory, {
22
+ agent,
23
+ canisterId,
24
+ ...options?.actorOptions,
25
+ });
26
+ };
@@ -0,0 +1,6 @@
1
+ export function idlFactory({ IDL }: {
2
+ IDL: any;
3
+ }): any;
4
+ export function init({ IDL }: {
5
+ IDL: any;
6
+ }): never[];
@@ -0,0 +1,34 @@
1
+ export const idlFactory = ({ IDL }) => {
2
+ const FileId = IDL.Text;
3
+ const Chunk = IDL.Vec(IDL.Nat8);
4
+ const Err = IDL.Text;
5
+ const Result_2 = IDL.Variant({ 'ok': Chunk, 'err': Err });
6
+ const FileId__1 = IDL.Text;
7
+ const FileMeta = IDL.Record({
8
+ 'id': FileId__1,
9
+ 'owners': IDL.Vec(IDL.Principal),
10
+ 'path': IDL.Text,
11
+ 'chunkCount': IDL.Nat,
12
+ });
13
+ const Result_1 = IDL.Variant({ 'ok': FileMeta, 'err': Err });
14
+ const StorageStats = IDL.Record({
15
+ 'fileCount': IDL.Nat,
16
+ 'cyclesBalance': IDL.Nat,
17
+ 'memorySize': IDL.Nat,
18
+ });
19
+ const Result = IDL.Variant({ 'ok': IDL.Null, 'err': Err });
20
+ const Storage = IDL.Service({
21
+ 'acceptCycles': IDL.Func([], [], []),
22
+ 'deleteFile': IDL.Func([FileId], [], []),
23
+ 'downloadChunk': IDL.Func([FileId, IDL.Nat], [Result_2], ['query']),
24
+ 'finishUpload': IDL.Func([FileId], [], []),
25
+ 'getFileIdsRange': IDL.Func([IDL.Nat, IDL.Nat], [IDL.Vec(FileId)], ['query']),
26
+ 'getFileMeta': IDL.Func([FileId], [Result_1], ['query']),
27
+ 'getStats': IDL.Func([], [StorageStats], ['query']),
28
+ 'startUpload': IDL.Func([FileMeta], [Result], []),
29
+ 'updateFileOwners': IDL.Func([FileId, IDL.Vec(IDL.Principal)], [], []),
30
+ 'uploadChunk': IDL.Func([FileId, IDL.Nat, Chunk], [], []),
31
+ });
32
+ return Storage;
33
+ };
34
+ export const init = ({ IDL }) => { return []; };
@@ -0,0 +1,14 @@
1
+ import Nat "mo:base/Nat";
2
+ import Iter "mo:base/Iter";
3
+ import Buffer "mo:base/Buffer";
4
+ import Vector "mo:vector/Class";
5
+ import Bench "mo:bench";
6
+
7
+ // placeholder file that will be replaced with the *.bench.mo file
8
+ module {
9
+ public func init() : Bench.Bench {
10
+ let bench = Bench.Bench();
11
+ // benchmark code goes here...
12
+ bench;
13
+ };
14
+ };
@@ -1,3 +1,10 @@
1
- type BenchMode = 'replica' | 'wasi';
2
- export declare function bench(filter?: string, mode?: BenchMode): Promise<boolean>;
1
+ type BenchOptions = {
2
+ verbose?: boolean;
3
+ save?: boolean;
4
+ compare?: boolean;
5
+ dfx?: string;
6
+ moc?: string;
7
+ gc?: 'copying' | 'compacting' | 'generational' | 'incremental' | 'none';
8
+ };
9
+ export declare function bench(filter?: string, options?: BenchOptions): Promise<boolean>;
3
10
  export {};
@@ -1,14 +1,17 @@
1
1
  import { execSync } from 'node:child_process';
2
2
  import path from 'node:path';
3
3
  import fs from 'node:fs';
4
- import os from 'node:os';
5
- // import chalk from 'chalk';
4
+ // import os from 'node:os';
5
+ import chalk from 'chalk';
6
6
  import { globSync } from 'glob';
7
- // import chokidar from 'chokidar';
8
- // import debounce from 'debounce';
9
- // import {sources} from './sources.js';
7
+ import { markdownTable } from 'markdown-table';
8
+ import logUpdate from 'log-update';
10
9
  import { getRootDir } from '../mops.js';
11
10
  import { parallel } from '../parallel.js';
11
+ import { createActor } from '../declarations/bench/index.js';
12
+ import { absToRel } from './test/utils.js';
13
+ import { getMocVersion } from '../helpers/get-moc-version.js';
14
+ import { getDfxVersion } from '../helpers/get-dfx-version.js';
12
15
  let ignore = [
13
16
  '**/node_modules/**',
14
17
  '**/.mops/**',
@@ -19,8 +22,7 @@ let globConfig = {
19
22
  nocase: true,
20
23
  ignore: ignore,
21
24
  };
22
- let mocPath = process.env.DFX_MOC_PATH;
23
- export async function bench(filter = '', mode = 'replica') {
25
+ export async function bench(filter = '', options = {}) {
24
26
  let rootDir = getRootDir();
25
27
  let globStr = '**/bench?(mark)/**/*.bench.mo';
26
28
  if (filter) {
@@ -36,21 +38,58 @@ export async function bench(filter = '', mode = 'replica') {
36
38
  console.log('Put your benchmark files in \'bench\' directory in *.bench.mo files');
37
39
  return false;
38
40
  }
39
- if (!mocPath) {
40
- mocPath = execSync('dfx cache show').toString().trim() + '/moc';
41
- }
41
+ files.sort();
42
42
  let benchDir = `${getRootDir()}/.mops/.bench/`;
43
+ fs.rmSync(benchDir, { recursive: true, force: true });
43
44
  fs.mkdirSync(benchDir, { recursive: true });
44
- console.log(files);
45
- console.log('Running dfx replica...');
46
- startDfx();
47
- await parallel(os.cpus().length, files, async (file) => {
48
- console.log(`Running ${file}...`);
49
- await runBenchFile(file, mode);
45
+ console.log('Benchmark files:');
46
+ for (let file of files) {
47
+ console.log(chalk.gray(`• ${absToRel(file)}`));
48
+ }
49
+ console.log('');
50
+ console.log('='.repeat(50));
51
+ console.log('Starting dfx replica...');
52
+ startDfx(options.verbose);
53
+ let resultsByName = new Map();
54
+ // await parallel(os.cpus().length, files, async (file: string) => {
55
+ await parallel(1, files, async (file) => {
56
+ console.log('\n' + '—'.repeat(50));
57
+ console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
58
+ console.log('');
59
+ try {
60
+ let { schema, results } = await runBenchFile(file, options);
61
+ resultsByName.set(schema.name || absToRel(file), results);
62
+ }
63
+ catch (err) {
64
+ console.error('Unexpected error. Stopping dfx replica...');
65
+ stopDfx(options.verbose);
66
+ throw err;
67
+ }
50
68
  });
69
+ if (options.save) {
70
+ console.log('Saving results to mops.bench.json...');
71
+ let json = {
72
+ version: 1,
73
+ moc: options.moc || getMocVersion(),
74
+ dfx: options.dfx || getDfxVersion(),
75
+ gc: options.gc || 'incremental',
76
+ results: {},
77
+ };
78
+ resultsByName.forEach((results, name) => {
79
+ json.results[name] = Array.from(results.entries());
80
+ });
81
+ fs.writeFileSync(path.join(rootDir, 'mops.bench.json'), JSON.stringify(json, (_, val) => {
82
+ if (typeof val === 'bigint') {
83
+ return Number(val);
84
+ }
85
+ else {
86
+ return val;
87
+ }
88
+ }, 2));
89
+ }
51
90
  console.log('Stopping dfx replica...');
52
- stopDfx();
53
- // fs.rmSync(benchDir, {recursive: true, force: true});
91
+ stopDfx(options.verbose);
92
+ fs.rmSync(benchDir, { recursive: true, force: true });
54
93
  return true;
55
94
  }
56
95
  function dfxJson(canisterName) {
@@ -60,7 +99,7 @@ function dfxJson(canisterName) {
60
99
  [canisterName]: {
61
100
  type: 'motoko',
62
101
  main: 'canister.mo',
63
- args: '--force-gc --generational-gc',
102
+ args: '--force-gc --incremental-gc',
64
103
  }
65
104
  },
66
105
  defaults: {
@@ -68,63 +107,108 @@ function dfxJson(canisterName) {
68
107
  packtool: 'mops sources',
69
108
  },
70
109
  },
71
- // networks: {
72
- // local: {
73
- // type: 'ephemeral',
74
- // bind: '127.0.0.1:4941',
75
- // },
76
- // },
110
+ networks: {
111
+ local: {
112
+ type: 'ephemeral',
113
+ bind: '127.0.0.1:4947',
114
+ },
115
+ },
77
116
  };
78
117
  }
79
- function startDfx() {
80
- // stopDfx();
81
- // let dir = path.join(getRootDir(), '.mops/.bench');
82
- // fs.writeFileSync(path.join(dir, 'dfx.json'), JSON.stringify(dfxJson(''), null, 2));
83
- // execSync('dfx start --background', {cwd: dir});
118
+ function startDfx(verbose = false) {
119
+ stopDfx(verbose);
120
+ let dir = path.join(getRootDir(), '.mops/.bench');
121
+ fs.writeFileSync(path.join(dir, 'dfx.json'), JSON.stringify(dfxJson(''), null, 2));
122
+ execSync('dfx start --background --clean', { cwd: dir, stdio: ['inherit', verbose ? 'inherit' : 'ignore', 'inherit'] });
84
123
  }
85
- function stopDfx() {
86
- // let dir = path.join(getRootDir(), '.mops/.bench');
87
- // execSync('dfx stop', {cwd: dir});
124
+ function stopDfx(verbose = false) {
125
+ let dir = path.join(getRootDir(), '.mops/.bench');
126
+ execSync('dfx stop', { cwd: dir, stdio: ['pipe', verbose ? 'inherit' : 'ignore', 'pipe'] });
88
127
  }
89
- async function runBenchFile(file, mode = 'replica') {
90
- let tempDir = path.join(getRootDir(), '.mops/.bench/', path.parse(file).name);
128
+ async function runBenchFile(file, options = {}) {
129
+ let rootDir = getRootDir();
130
+ let tempDir = path.join(rootDir, '.mops/.bench/', path.parse(file).name);
91
131
  fs.mkdirSync(tempDir, { recursive: true });
92
- if (fs.readFileSync(file, 'utf8').startsWith('// @benchmode wasi')) {
93
- mode = 'wasi';
94
- }
95
- if (!mocPath) {
96
- mocPath = 'moc';
97
- }
98
- // replica mode
99
- if (mode === 'replica') {
100
- let canisterName = Date.now().toString(36);
101
- fs.writeFileSync(path.join(tempDir, 'dfx.json'), JSON.stringify(dfxJson(canisterName), null, 2));
102
- fs.cpSync(file, path.join(tempDir, 'canister.mo'));
103
- execSync(`dfx deploy ${canisterName} --mode reinstall --yes`, { cwd: tempDir });
104
- let res = execSync(`dfx canister call ${canisterName} run 1`, { cwd: tempDir });
105
- console.log(res.toString());
132
+ let canisterName = Date.now().toString(36);
133
+ // prepare temp files
134
+ fs.writeFileSync(path.join(tempDir, 'dfx.json'), JSON.stringify(dfxJson(canisterName), null, 2));
135
+ fs.cpSync(new URL('./bench/bench-canister.mo', import.meta.url), path.join(tempDir, 'canister.mo'));
136
+ fs.cpSync(file, path.join(tempDir, 'user-bench.mo'));
137
+ // deploy canister
138
+ execSync(`dfx deploy ${canisterName} --mode reinstall --yes --identity anonymous`, { cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe'] });
139
+ let canisterId = execSync(`dfx canister id ${canisterName}`, { cwd: tempDir }).toString().trim();
140
+ let actor = await createActor(canisterId, {
141
+ agentOptions: {
142
+ host: 'http://127.0.0.1:4947',
143
+ },
144
+ });
145
+ let schema = await actor.init();
146
+ // load previous results
147
+ let prevResults;
148
+ if (options.compare) {
149
+ let prevResultsJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'mops.bench.json')).toString());
150
+ if (prevResultsJson.results[schema.name]) {
151
+ prevResults = new Map(prevResultsJson.results[schema.name]);
152
+ }
153
+ else {
154
+ console.log(chalk.yellow(`No previous results found for benchmark with name "${schema.name}"`));
155
+ }
106
156
  }
107
- // wasi mode
108
- else if (mode === 'wasi') {
109
- // let sourcesArr = await sources();
110
- // let mocArgs = ['--hide-warnings', '--error-detail=2', ...sourcesArr.join(' ').split(' '), file].filter(x => x);
111
- // let wasmFile = `${path.join(tempDir, path.parse(file).name)}.wasm`;
112
- // // build
113
- // let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs]);
114
- // buildProc.on('close', (code) => {
115
- // if (code !== 0) {
116
- // throw new Error(`unknown exit code: ${code}`);
117
- // }
118
- // resolve();
119
- // });
120
- // // run
121
- // let proc = spawn('wasmtime', ['--max-wasm-stack=2000000', wasmFile]);
122
- // proc.on('close', (code) => {
123
- // if (code !== 0) {
124
- // throw new Error(`unknown exit code: ${code}`);
125
- // }
126
- // resolve();
127
- // });
128
- // fs.rmSync(wasmFile, {force: true});
157
+ let results = new Map();
158
+ let formatNumber = (n) => {
159
+ return n.toLocaleString('en-US').replaceAll(',', '_');
160
+ };
161
+ let getTable = (prop) => {
162
+ let resArr = [['', ...schema.cols]];
163
+ for (let [_rowIndex, row] of schema.rows.entries()) {
164
+ let curRow = [row];
165
+ for (let [_colIndex, col] of schema.cols.entries()) {
166
+ let res = results.get(`${row}:${col}`);
167
+ if (res) {
168
+ // compare with previous results
169
+ let diff = '';
170
+ if (options.compare && prevResults) {
171
+ let prevRes = prevResults.get(`${row}:${col}`);
172
+ if (prevRes) {
173
+ let percent = (Number(res[prop]) - Number(prevRes[prop])) / Number(prevRes[prop]) * 100;
174
+ let sign = percent > 0 ? '+' : '';
175
+ let percentText = percent == 0 ? '0%' : sign + percent.toFixed(2) + '%';
176
+ // diff = ' (' + (percent > 0 ? chalk.red(percentText) : chalk.green(percentText)) + ')'; // alignment is broken
177
+ diff = ' (' + percentText + ')';
178
+ }
179
+ else {
180
+ diff = chalk.yellow(' (no previous results)');
181
+ }
182
+ }
183
+ // add to table
184
+ curRow.push(formatNumber(res[prop]) + diff);
185
+ }
186
+ else {
187
+ curRow.push('');
188
+ }
189
+ }
190
+ resArr.push(curRow);
191
+ }
192
+ return markdownTable(resArr, { align: ['l', ...'r'.repeat(schema.cols.length)] });
193
+ };
194
+ let printResults = () => {
195
+ logUpdate(`
196
+ \n${chalk.bold(schema.name)}
197
+ ${schema.description ? '\n' + chalk.gray(schema.description) : ''}
198
+ \n\n${chalk.blue('Instructions')}\n\n${getTable('instructions')}
199
+ \n\n${chalk.blue('Heap')}\n\n${getTable('rts_heap_size')}
200
+ `);
201
+ };
202
+ printResults();
203
+ // run all cells
204
+ for (let [rowIndex, row] of schema.rows.entries()) {
205
+ for (let [colIndex, col] of schema.cols.entries()) {
206
+ // let res = await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex));
207
+ let res = await actor.runCellUpdate(BigInt(rowIndex), BigInt(colIndex));
208
+ results.set(`${row}:${col}`, res);
209
+ printResults();
210
+ }
129
211
  }
212
+ logUpdate.done();
213
+ return { schema, results };
130
214
  }
@@ -146,15 +146,22 @@ async function applyInit({ type, config, setupWorkflow, addTest, copyrightOwner
146
146
  let dfxJsonData;
147
147
  if (existsSync(dfxJson)) {
148
148
  let dfxJsonText = readFileSync(dfxJson).toString();
149
- dfxJsonData = JSON.parse(dfxJsonText);
150
- console.log('Setting packtool in dfx.json...');
151
- dfxJsonData.defaults = dfxJsonData.defaults || {};
152
- dfxJsonData.defaults.build = dfxJsonData.defaults.build || {};
153
- if (dfxJsonData.defaults.build.packtool !== 'mops sources') {
154
- dfxJsonData.defaults.build.packtool = 'mops sources';
155
- let indent = dfxJsonText.match(/([ \t]+)"/)?.[1] || ' ';
156
- writeFileSync(path.join(process.cwd(), 'dfx.json'), JSON.stringify(dfxJsonData, null, indent));
157
- console.log(chalk.green('packtool set to "mops sources"'));
149
+ try {
150
+ dfxJsonData = JSON.parse(dfxJsonText);
151
+ }
152
+ catch (err) {
153
+ console.log(chalk.yellow('Failed to parse dfx.json'));
154
+ }
155
+ if (dfxJsonData) {
156
+ console.log('Setting packtool in dfx.json...');
157
+ dfxJsonData.defaults = dfxJsonData.defaults || {};
158
+ dfxJsonData.defaults.build = dfxJsonData.defaults.build || {};
159
+ if (dfxJsonData.defaults.build.packtool !== 'mops sources') {
160
+ dfxJsonData.defaults.build.packtool = 'mops sources';
161
+ let indent = dfxJsonText.match(/([ \t]+)"/)?.[1] || ' ';
162
+ writeFileSync(path.join(process.cwd(), 'dfx.json'), JSON.stringify(dfxJsonData, null, indent));
163
+ console.log(chalk.green('packtool set to "mops sources"'));
164
+ }
158
165
  }
159
166
  }
160
167
  // get default packages