ic-mops 0.31.2 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.ts +14 -0
- package/commands/bench/bench-canister.mo +87 -0
- package/commands/bench/user-bench.mo +14 -0
- package/commands/bench.ts +337 -0
- package/commands/publish.ts +4 -0
- package/commands/sources.ts +4 -4
- package/declarations/bench/bench.did +26 -0
- package/declarations/bench/bench.did.d.ts +26 -0
- package/declarations/bench/bench.did.js +26 -0
- package/declarations/bench/index.d.ts +50 -0
- package/declarations/bench/index.js +41 -0
- package/dist/cli.js +13 -0
- package/dist/commands/bench/bench-canister.mo +20 -27
- package/dist/commands/bench.js +17 -9
- package/dist/commands/publish.js +4 -0
- package/dist/commands/sources.d.ts +2 -1
- package/dist/commands/sources.js +4 -4
- package/dist/package.json +81 -80
- package/helpers/get-dfx-version.ts +10 -0
- package/helpers/get-moc-path.ts +12 -0
- package/helpers/get-moc-version.ts +8 -0
- package/package.json +81 -80
- package/tsconfig.json +2 -0
package/cli.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {bump} from './commands/bump.js';
|
|
|
24
24
|
import {sync} from './commands/sync.js';
|
|
25
25
|
import {outdated} from './commands/outdated.js';
|
|
26
26
|
import {update} from './commands/update.js';
|
|
27
|
+
import {bench} from './commands/bench.js';
|
|
27
28
|
import {transferOwnership} from './commands/transfer-ownership.js';
|
|
28
29
|
// import {docs} from './commands/docs.js';
|
|
29
30
|
|
|
@@ -198,6 +199,19 @@ program
|
|
|
198
199
|
await test(filter, options);
|
|
199
200
|
});
|
|
200
201
|
|
|
202
|
+
// bench
|
|
203
|
+
program
|
|
204
|
+
.command('bench [filter]')
|
|
205
|
+
.description('Run benchmarks')
|
|
206
|
+
.addOption(new Option('--save', 'Save benchmark results to .bench/<filename>.json'))
|
|
207
|
+
.addOption(new Option('--compare', 'Run benchmark and compare results with .bench/<filename>.json'))
|
|
208
|
+
.addOption(new Option('--gc <gc>', 'Garbage collector').choices(['copying', 'compacting', 'generational', 'incremental']).default('incremental'))
|
|
209
|
+
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
210
|
+
.addOption(new Option('--verbose', 'Show more information'))
|
|
211
|
+
.action(async (filter, options) => {
|
|
212
|
+
await bench(filter, options);
|
|
213
|
+
});
|
|
214
|
+
|
|
201
215
|
// template
|
|
202
216
|
program
|
|
203
217
|
.command('template')
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import Nat64 "mo:base/Nat64";
|
|
2
|
+
import Nat "mo:base/Nat";
|
|
3
|
+
import Debug "mo:base/Debug";
|
|
4
|
+
import ExperimentalInternetComputer "mo:base/ExperimentalInternetComputer";
|
|
5
|
+
import Prim "mo:prim";
|
|
6
|
+
import Bench "mo:bench";
|
|
7
|
+
|
|
8
|
+
import UserBench "./user-bench"; // file path will be replaced with the *.bench.mo file path
|
|
9
|
+
|
|
10
|
+
actor class() {
|
|
11
|
+
var benchOpt : ?Bench.Bench = null;
|
|
12
|
+
|
|
13
|
+
public func init() : async Bench.BenchSchema {
|
|
14
|
+
let bench = UserBench.init();
|
|
15
|
+
benchOpt := ?bench;
|
|
16
|
+
bench.getSchema();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
public query func getSchema() : async Bench.BenchSchema {
|
|
20
|
+
let ?bench = benchOpt else Debug.trap("bench not initialized");
|
|
21
|
+
bench.getSchema();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
func _getStats() : Bench.BenchResult {
|
|
25
|
+
{
|
|
26
|
+
instructions = 0;
|
|
27
|
+
rts_heap_size = Prim.rts_heap_size();
|
|
28
|
+
rts_memory_size = Prim.rts_memory_size();
|
|
29
|
+
rts_total_allocation = Prim.rts_total_allocation();
|
|
30
|
+
rts_mutator_instructions = Prim.rts_mutator_instructions();
|
|
31
|
+
rts_collector_instructions = Prim.rts_collector_instructions();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
func _diffStats(before : Bench.BenchResult, after : Bench.BenchResult) : Bench.BenchResult {
|
|
36
|
+
{
|
|
37
|
+
instructions = after.instructions - before.instructions;
|
|
38
|
+
rts_heap_size = after.rts_heap_size - before.rts_heap_size;
|
|
39
|
+
rts_memory_size = after.rts_memory_size - before.rts_memory_size;
|
|
40
|
+
rts_total_allocation = after.rts_total_allocation - before.rts_total_allocation;
|
|
41
|
+
rts_mutator_instructions = after.rts_mutator_instructions - before.rts_mutator_instructions;
|
|
42
|
+
rts_collector_instructions = after.rts_collector_instructions - before.rts_collector_instructions;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
func _runCell(rowIndex : Nat, colIndex : Nat) : Bench.BenchResult {
|
|
47
|
+
let ?bench = benchOpt else Debug.trap("bench not initialized");
|
|
48
|
+
let statsBefore = _getStats();
|
|
49
|
+
|
|
50
|
+
let instructions = Nat64.toNat(ExperimentalInternetComputer.countInstructions(func() {
|
|
51
|
+
bench.runCell(rowIndex, colIndex);
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
let statsAfter = _getStats();
|
|
55
|
+
_diffStats(statsBefore, { statsAfter with instructions });
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
func _runCellAwait(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
59
|
+
let ?bench = benchOpt else Debug.trap("bench not initialized");
|
|
60
|
+
let statsBefore = _getStats();
|
|
61
|
+
|
|
62
|
+
let instructions = Nat64.toNat(ExperimentalInternetComputer.countInstructions(func() {
|
|
63
|
+
bench.runCell(rowIndex, colIndex);
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
await (func() : async () {})();
|
|
67
|
+
|
|
68
|
+
let statsAfter = _getStats();
|
|
69
|
+
_diffStats(statsBefore, { statsAfter with instructions });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
public query func getStats() : async Bench.BenchResult {
|
|
73
|
+
_getStats();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
public query func runCellQuery(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
77
|
+
_runCell(rowIndex, colIndex);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
public func runCellUpdate(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
81
|
+
_runCell(rowIndex, colIndex);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
public func runCellUpdateAwait(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
85
|
+
await _runCellAwait(rowIndex, colIndex);
|
|
86
|
+
};
|
|
87
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import {execSync} from 'node:child_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 logUpdate from 'log-update';
|
|
9
|
+
|
|
10
|
+
import {getRootDir} from '../mops.js';
|
|
11
|
+
import {parallel} from '../parallel.js';
|
|
12
|
+
import {createActor} from '../declarations/bench/index.js';
|
|
13
|
+
import {BenchResult, BenchSchema, _SERVICE} from '../declarations/bench/bench.did.js';
|
|
14
|
+
import {absToRel} from './test/utils.js';
|
|
15
|
+
import {getMocVersion} from '../helpers/get-moc-version.js';
|
|
16
|
+
import {getDfxVersion} from '../helpers/get-dfx-version.js';
|
|
17
|
+
import {getMocPath} from '../helpers/get-moc-path.js';
|
|
18
|
+
import {sources} from './sources.js';
|
|
19
|
+
import {execaCommand} from 'execa';
|
|
20
|
+
|
|
21
|
+
let ignore = [
|
|
22
|
+
'**/node_modules/**',
|
|
23
|
+
'**/.mops/**',
|
|
24
|
+
'**/.vessel/**',
|
|
25
|
+
'**/.git/**',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
let globConfig = {
|
|
29
|
+
nocase: true,
|
|
30
|
+
ignore: ignore,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type BenchOptions = {
|
|
34
|
+
dfx?: string,
|
|
35
|
+
moc?: string,
|
|
36
|
+
gc?: 'copying' | 'compacting' | 'generational' | 'incremental',
|
|
37
|
+
forceGc?: boolean,
|
|
38
|
+
save?: boolean,
|
|
39
|
+
compare?: boolean,
|
|
40
|
+
verbose?: boolean,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export async function bench(filter = '', options: BenchOptions = {}): Promise<boolean> {
|
|
44
|
+
let defaultOptions: BenchOptions = {
|
|
45
|
+
moc: getMocVersion(),
|
|
46
|
+
dfx: getDfxVersion(),
|
|
47
|
+
gc: 'incremental',
|
|
48
|
+
forceGc: true,
|
|
49
|
+
save: false,
|
|
50
|
+
compare: false,
|
|
51
|
+
verbose: false,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
options = {...defaultOptions, ...options};
|
|
55
|
+
|
|
56
|
+
options.verbose && console.log(options);
|
|
57
|
+
|
|
58
|
+
let rootDir = getRootDir();
|
|
59
|
+
let globStr = '**/bench?(mark)/**/*.bench.mo';
|
|
60
|
+
if (filter) {
|
|
61
|
+
globStr = `**/bench?(mark)/**/*${filter}*.mo`;
|
|
62
|
+
}
|
|
63
|
+
let files = globSync(path.join(rootDir, globStr), globConfig);
|
|
64
|
+
if (!files.length) {
|
|
65
|
+
if (filter) {
|
|
66
|
+
console.log(`No benchmark files found for filter '${filter}'`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
console.log('No *.bench.mo files found');
|
|
70
|
+
console.log('Put your benchmark code in \'bench\' directory in *.bench.mo files');
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
files.sort();
|
|
75
|
+
|
|
76
|
+
let benchDir = `${getRootDir()}/.mops/.bench/`;
|
|
77
|
+
fs.rmSync(benchDir, {recursive: true, force: true});
|
|
78
|
+
fs.mkdirSync(benchDir, {recursive: true});
|
|
79
|
+
|
|
80
|
+
console.log('Benchmark files:');
|
|
81
|
+
for (let file of files) {
|
|
82
|
+
console.log(chalk.gray(`• ${absToRel(file)}`));
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log('='.repeat(50));
|
|
86
|
+
console.log('');
|
|
87
|
+
|
|
88
|
+
console.log('Starting dfx replica...');
|
|
89
|
+
startDfx(options.verbose);
|
|
90
|
+
|
|
91
|
+
console.log('Deploying canisters...');
|
|
92
|
+
await parallel(os.cpus().length, files, async (file: string) => {
|
|
93
|
+
try {
|
|
94
|
+
await deployBenchFile(file, options);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.error('Unexpected error. Stopping dfx replica...');
|
|
98
|
+
stopDfx(options.verbose);
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await parallel(1, files, async (file: string) => {
|
|
104
|
+
console.log('\n' + '—'.repeat(50));
|
|
105
|
+
console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
|
|
106
|
+
console.log('');
|
|
107
|
+
try {
|
|
108
|
+
await runBenchFile(file, options);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.error('Unexpected error. Stopping dfx replica...');
|
|
112
|
+
stopDfx(options.verbose);
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log('Stopping dfx replica...');
|
|
118
|
+
stopDfx(options.verbose);
|
|
119
|
+
|
|
120
|
+
fs.rmSync(benchDir, {recursive: true, force: true});
|
|
121
|
+
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getMocArgs(options: BenchOptions): string {
|
|
126
|
+
let args = '';
|
|
127
|
+
if (options.forceGc) {
|
|
128
|
+
args += ' --force-gc';
|
|
129
|
+
}
|
|
130
|
+
if (options.gc) {
|
|
131
|
+
args += ` --${options.gc}-gc`;
|
|
132
|
+
}
|
|
133
|
+
return args;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function dfxJson(canisterName: string, options: BenchOptions = {}) {
|
|
137
|
+
options || console.log(options);
|
|
138
|
+
|
|
139
|
+
let canisters: Record<string, any> = {};
|
|
140
|
+
if (canisterName) {
|
|
141
|
+
canisters[canisterName] = {
|
|
142
|
+
type: 'custom',
|
|
143
|
+
wasm: 'canister.wasm',
|
|
144
|
+
candid: 'canister.did',
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
version: 1,
|
|
150
|
+
canisters,
|
|
151
|
+
defaults: {
|
|
152
|
+
build: {
|
|
153
|
+
packtool: 'mops sources',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
networks: {
|
|
157
|
+
local: {
|
|
158
|
+
type: 'ephemeral',
|
|
159
|
+
bind: '127.0.0.1:4944',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function startDfx(verbose = false) {
|
|
166
|
+
stopDfx(verbose);
|
|
167
|
+
let dir = path.join(getRootDir(), '.mops/.bench');
|
|
168
|
+
fs.writeFileSync(path.join(dir, 'dfx.json'), JSON.stringify(dfxJson(''), null, 2));
|
|
169
|
+
execSync('dfx start --background --clean' + (verbose ? '' : ' -qqqq'), {cwd: dir, stdio: ['inherit', verbose ? 'inherit' : 'ignore', 'inherit']});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function stopDfx(verbose = false) {
|
|
173
|
+
let dir = path.join(getRootDir(), '.mops/.bench');
|
|
174
|
+
execSync('dfx stop' + (verbose ? '' : ' -qqqq'), {cwd: dir, stdio: ['pipe', verbose ? 'inherit' : 'ignore', 'pipe']});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function deployBenchFile(file: string, options: BenchOptions = {}): Promise<void> {
|
|
178
|
+
let rootDir = getRootDir();
|
|
179
|
+
let tempDir = path.join(rootDir, '.mops/.bench/', path.parse(file).name);
|
|
180
|
+
let canisterName = path.parse(file).name;
|
|
181
|
+
|
|
182
|
+
// prepare temp files
|
|
183
|
+
fs.mkdirSync(tempDir, {recursive: true});
|
|
184
|
+
fs.writeFileSync(path.join(tempDir, 'dfx.json'), JSON.stringify(dfxJson(canisterName, options), null, 2));
|
|
185
|
+
|
|
186
|
+
let benchCanisterData = fs.readFileSync(new URL('./bench/bench-canister.mo', import.meta.url), 'utf8');
|
|
187
|
+
benchCanisterData = benchCanisterData.replace('./user-bench', path.relative(tempDir, file).replace(/.mo$/g, ''));
|
|
188
|
+
fs.writeFileSync(path.join(tempDir, 'canister.mo'), benchCanisterData);
|
|
189
|
+
|
|
190
|
+
// build canister
|
|
191
|
+
let mocPath = getMocPath();
|
|
192
|
+
let mocArgs = getMocArgs(options);
|
|
193
|
+
options.verbose && console.time(`build ${canisterName}`);
|
|
194
|
+
await execaCommand(`${mocPath} -c --idl canister.mo ${mocArgs} ${(await sources({cwd: tempDir})).join(' ')}`, {cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
|
|
195
|
+
options.verbose && console.timeEnd(`build ${canisterName}`);
|
|
196
|
+
|
|
197
|
+
// deploy canister
|
|
198
|
+
options.verbose && console.time(`deploy ${canisterName}`);
|
|
199
|
+
await execaCommand(`dfx deploy ${canisterName} --mode reinstall --yes --identity anonymous`, {cwd: tempDir, stdio: options.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
|
|
200
|
+
options.verbose && console.timeEnd(`deploy ${canisterName}`);
|
|
201
|
+
|
|
202
|
+
// init bench
|
|
203
|
+
options.verbose && console.time(`init ${canisterName}`);
|
|
204
|
+
let canisterId = execSync(`dfx canister id ${canisterName}`, {cwd: tempDir}).toString().trim();
|
|
205
|
+
let actor: _SERVICE = await createActor(canisterId, {
|
|
206
|
+
agentOptions: {
|
|
207
|
+
host: 'http://127.0.0.1:4944',
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
await actor.init();
|
|
211
|
+
options.verbose && console.timeEnd(`init ${canisterName}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
type RunBenchFileResult = {
|
|
215
|
+
schema: BenchSchema,
|
|
216
|
+
results: Map<string, BenchResult>,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
async function runBenchFile(file: string, options: BenchOptions = {}): Promise<RunBenchFileResult> {
|
|
220
|
+
let rootDir = getRootDir();
|
|
221
|
+
let tempDir = path.join(rootDir, '.mops/.bench/', path.parse(file).name);
|
|
222
|
+
let canisterName = path.parse(file).name;
|
|
223
|
+
|
|
224
|
+
let canisterId = execSync(`dfx canister id ${canisterName}`, {cwd: tempDir}).toString().trim();
|
|
225
|
+
let actor: _SERVICE = await createActor(canisterId, {
|
|
226
|
+
agentOptions: {
|
|
227
|
+
host: 'http://127.0.0.1:4944',
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
let schema = await actor.getSchema();
|
|
232
|
+
|
|
233
|
+
// load previous results
|
|
234
|
+
let prevResults: Map<string, BenchResult> | undefined;
|
|
235
|
+
let resultsJsonFile = path.join(rootDir, '.bench', `${path.parse(file).name}.json`);
|
|
236
|
+
if (options.compare) {
|
|
237
|
+
if (fs.existsSync(resultsJsonFile)) {
|
|
238
|
+
let prevResultsJson = JSON.parse(fs.readFileSync(resultsJsonFile).toString());
|
|
239
|
+
prevResults = new Map(prevResultsJson.results);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
console.log(chalk.yellow(`No previous results found "${resultsJsonFile}"`));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let results = new Map<string, BenchResult>();
|
|
247
|
+
|
|
248
|
+
let formatNumber = (n: bigint | number): string => {
|
|
249
|
+
return n.toLocaleString('en-US').replaceAll(',', '_');
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
let getTable = (prop: keyof BenchResult): string => {
|
|
253
|
+
let resArr = [['', ...schema.cols]];
|
|
254
|
+
|
|
255
|
+
for (let [_rowIndex, row] of schema.rows.entries()) {
|
|
256
|
+
let curRow = [row];
|
|
257
|
+
|
|
258
|
+
for (let [_colIndex, col] of schema.cols.entries()) {
|
|
259
|
+
let res = results.get(`${row}:${col}`);
|
|
260
|
+
if (res) {
|
|
261
|
+
|
|
262
|
+
// compare with previous results
|
|
263
|
+
let diff = '';
|
|
264
|
+
if (options.compare && prevResults) {
|
|
265
|
+
let prevRes = prevResults.get(`${row}:${col}`);
|
|
266
|
+
if (prevRes) {
|
|
267
|
+
let percent = (Number(res[prop]) - Number(prevRes[prop])) / Number(prevRes[prop]) * 100;
|
|
268
|
+
let sign = percent > 0 ? '+' : '';
|
|
269
|
+
let percentText = percent == 0 ? '0%' : sign + percent.toFixed(2) + '%';
|
|
270
|
+
// diff = ' (' + (percent > 0 ? chalk.red(percentText) : chalk.green(percentText)) + ')'; // alignment is broken
|
|
271
|
+
diff = ' (' + percentText + ')';
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
diff = chalk.yellow(' (no previous results)');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// add to table
|
|
279
|
+
curRow.push(formatNumber(res[prop]) + diff);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
curRow.push('');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
resArr.push(curRow);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return markdownTable(resArr, {align: ['l', ...'r'.repeat(schema.cols.length)]});
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
let printResults = () => {
|
|
292
|
+
logUpdate(`
|
|
293
|
+
\n${chalk.bold(schema.name)}
|
|
294
|
+
${schema.description ? '\n' + chalk.gray(schema.description) : ''}
|
|
295
|
+
\n\n${chalk.blue('Instructions')}\n\n${getTable('instructions')}
|
|
296
|
+
\n\n${chalk.blue('Heap')}\n\n${getTable('rts_heap_size')}
|
|
297
|
+
`);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
printResults();
|
|
301
|
+
|
|
302
|
+
// run all cells
|
|
303
|
+
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
304
|
+
for (let [colIndex, col] of schema.cols.entries()) {
|
|
305
|
+
// let res = await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex));
|
|
306
|
+
// let res = await actor.runCellUpdate(BigInt(rowIndex), BigInt(colIndex));
|
|
307
|
+
let res = await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
308
|
+
results.set(`${row}:${col}`, res);
|
|
309
|
+
printResults();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
logUpdate.done();
|
|
313
|
+
|
|
314
|
+
// save results
|
|
315
|
+
if (options.save) {
|
|
316
|
+
console.log(`Saving results to ${chalk.gray(absToRel(resultsJsonFile))}`);
|
|
317
|
+
let json: Record<any, any> = {
|
|
318
|
+
version: 1,
|
|
319
|
+
moc: options.moc,
|
|
320
|
+
dfx: options.dfx,
|
|
321
|
+
gc: options.gc,
|
|
322
|
+
forceGc: options.forceGc,
|
|
323
|
+
results: Array.from(results.entries()),
|
|
324
|
+
};
|
|
325
|
+
fs.mkdirSync(path.dirname(resultsJsonFile), {recursive: true});
|
|
326
|
+
fs.writeFileSync(resultsJsonFile, JSON.stringify(json, (_, val) => {
|
|
327
|
+
if (typeof val === 'bigint') {
|
|
328
|
+
return Number(val);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
return val;
|
|
332
|
+
}
|
|
333
|
+
}, 2));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return {schema, results};
|
|
337
|
+
}
|
package/commands/publish.ts
CHANGED
|
@@ -197,6 +197,10 @@ export async function publish(options: {docs?: boolean, test?: boolean} = {}) {
|
|
|
197
197
|
'!tests/**',
|
|
198
198
|
'!**/*.test.mo',
|
|
199
199
|
'!**/*.Test.mo',
|
|
200
|
+
'!bench/**',
|
|
201
|
+
'!benchmark/**',
|
|
202
|
+
'!**/*.bench.mo',
|
|
203
|
+
'!**/*.Bench.mo',
|
|
200
204
|
];
|
|
201
205
|
let files = config.package.files || ['**/*.mo'];
|
|
202
206
|
files = [...files, ...defaultFiles];
|
package/commands/sources.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {checkConfigFile, formatDir, formatGithubDir, getDependencyType, readConf
|
|
|
4
4
|
import {resolvePackages} from '../resolve-packages.js';
|
|
5
5
|
|
|
6
6
|
// TODO: resolve conflicts
|
|
7
|
-
export async function sources({verbose = false} = {}) {
|
|
7
|
+
export async function sources({verbose = false, cwd = process.cwd()} = {}) {
|
|
8
8
|
if (!checkConfigFile()) {
|
|
9
9
|
return [];
|
|
10
10
|
}
|
|
@@ -17,13 +17,13 @@ export async function sources({verbose = false} = {}) {
|
|
|
17
17
|
|
|
18
18
|
let pkgDir;
|
|
19
19
|
if (depType === 'local') {
|
|
20
|
-
pkgDir = path.relative(
|
|
20
|
+
pkgDir = path.relative(cwd, version);
|
|
21
21
|
}
|
|
22
22
|
else if (depType === 'github') {
|
|
23
|
-
pkgDir = path.relative(
|
|
23
|
+
pkgDir = path.relative(cwd, formatGithubDir(name, version));
|
|
24
24
|
}
|
|
25
25
|
else if (depType === 'mops') {
|
|
26
|
-
pkgDir = path.relative(
|
|
26
|
+
pkgDir = path.relative(cwd, formatDir(name, version));
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
29
|
return;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type anon_class_10_1 =
|
|
2
|
+
service {
|
|
3
|
+
getSchema: () -> (BenchSchema) query;
|
|
4
|
+
getStats: () -> (BenchResult) query;
|
|
5
|
+
init: () -> (BenchSchema);
|
|
6
|
+
runCellQuery: (nat, nat) -> (BenchResult) query;
|
|
7
|
+
runCellUpdate: (nat, nat) -> (BenchResult);
|
|
8
|
+
runCellUpdateAwait: (nat, nat) -> (BenchResult);
|
|
9
|
+
};
|
|
10
|
+
type BenchSchema =
|
|
11
|
+
record {
|
|
12
|
+
cols: vec text;
|
|
13
|
+
description: text;
|
|
14
|
+
name: text;
|
|
15
|
+
rows: vec text;
|
|
16
|
+
};
|
|
17
|
+
type BenchResult =
|
|
18
|
+
record {
|
|
19
|
+
instructions: int;
|
|
20
|
+
rts_collector_instructions: int;
|
|
21
|
+
rts_heap_size: int;
|
|
22
|
+
rts_memory_size: int;
|
|
23
|
+
rts_mutator_instructions: int;
|
|
24
|
+
rts_total_allocation: int;
|
|
25
|
+
};
|
|
26
|
+
service : () -> anon_class_10_1
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Principal } from '@dfinity/principal';
|
|
2
|
+
import type { ActorMethod } from '@dfinity/agent';
|
|
3
|
+
|
|
4
|
+
export interface BenchResult {
|
|
5
|
+
'instructions' : bigint,
|
|
6
|
+
'rts_memory_size' : bigint,
|
|
7
|
+
'rts_total_allocation' : bigint,
|
|
8
|
+
'rts_collector_instructions' : bigint,
|
|
9
|
+
'rts_mutator_instructions' : bigint,
|
|
10
|
+
'rts_heap_size' : bigint,
|
|
11
|
+
}
|
|
12
|
+
export interface BenchSchema {
|
|
13
|
+
'cols' : Array<string>,
|
|
14
|
+
'name' : string,
|
|
15
|
+
'rows' : Array<string>,
|
|
16
|
+
'description' : string,
|
|
17
|
+
}
|
|
18
|
+
export interface anon_class_10_1 {
|
|
19
|
+
'getSchema' : ActorMethod<[], BenchSchema>,
|
|
20
|
+
'getStats' : ActorMethod<[], BenchResult>,
|
|
21
|
+
'init' : ActorMethod<[], BenchSchema>,
|
|
22
|
+
'runCellQuery' : ActorMethod<[bigint, bigint], BenchResult>,
|
|
23
|
+
'runCellUpdate' : ActorMethod<[bigint, bigint], BenchResult>,
|
|
24
|
+
'runCellUpdateAwait' : ActorMethod<[bigint, bigint], BenchResult>,
|
|
25
|
+
}
|
|
26
|
+
export interface _SERVICE extends anon_class_10_1 {}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const idlFactory = ({ IDL }) => {
|
|
2
|
+
const BenchSchema = IDL.Record({
|
|
3
|
+
'cols' : IDL.Vec(IDL.Text),
|
|
4
|
+
'name' : IDL.Text,
|
|
5
|
+
'rows' : IDL.Vec(IDL.Text),
|
|
6
|
+
'description' : IDL.Text,
|
|
7
|
+
});
|
|
8
|
+
const BenchResult = IDL.Record({
|
|
9
|
+
'instructions' : IDL.Int,
|
|
10
|
+
'rts_memory_size' : IDL.Int,
|
|
11
|
+
'rts_total_allocation' : IDL.Int,
|
|
12
|
+
'rts_collector_instructions' : IDL.Int,
|
|
13
|
+
'rts_mutator_instructions' : IDL.Int,
|
|
14
|
+
'rts_heap_size' : IDL.Int,
|
|
15
|
+
});
|
|
16
|
+
const anon_class_10_1 = IDL.Service({
|
|
17
|
+
'getSchema' : IDL.Func([], [BenchSchema], ['query']),
|
|
18
|
+
'getStats' : IDL.Func([], [BenchResult], ['query']),
|
|
19
|
+
'init' : IDL.Func([], [BenchSchema], []),
|
|
20
|
+
'runCellQuery' : IDL.Func([IDL.Nat, IDL.Nat], [BenchResult], ['query']),
|
|
21
|
+
'runCellUpdate' : IDL.Func([IDL.Nat, IDL.Nat], [BenchResult], []),
|
|
22
|
+
'runCellUpdateAwait' : IDL.Func([IDL.Nat, IDL.Nat], [BenchResult], []),
|
|
23
|
+
});
|
|
24
|
+
return anon_class_10_1;
|
|
25
|
+
};
|
|
26
|
+
export const init = ({ IDL }) => { return []; };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActorSubclass,
|
|
3
|
+
HttpAgentOptions,
|
|
4
|
+
ActorConfig,
|
|
5
|
+
Agent,
|
|
6
|
+
} from "@dfinity/agent";
|
|
7
|
+
import type { Principal } from "@dfinity/principal";
|
|
8
|
+
import type { IDL } from "@dfinity/candid";
|
|
9
|
+
|
|
10
|
+
import { _SERVICE } from './bench.did';
|
|
11
|
+
|
|
12
|
+
export declare const idlFactory: IDL.InterfaceFactory;
|
|
13
|
+
export declare const canisterId: string;
|
|
14
|
+
|
|
15
|
+
export declare interface CreateActorOptions {
|
|
16
|
+
/**
|
|
17
|
+
* @see {@link Agent}
|
|
18
|
+
*/
|
|
19
|
+
agent?: Agent;
|
|
20
|
+
/**
|
|
21
|
+
* @see {@link HttpAgentOptions}
|
|
22
|
+
*/
|
|
23
|
+
agentOptions?: HttpAgentOptions;
|
|
24
|
+
/**
|
|
25
|
+
* @see {@link ActorConfig}
|
|
26
|
+
*/
|
|
27
|
+
actorOptions?: ActorConfig;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister.
|
|
32
|
+
* @constructs {@link ActorSubClass}
|
|
33
|
+
* @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to
|
|
34
|
+
* @param {CreateActorOptions} options - see {@link CreateActorOptions}
|
|
35
|
+
* @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions
|
|
36
|
+
* @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent
|
|
37
|
+
* @see {@link HttpAgentOptions}
|
|
38
|
+
* @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor
|
|
39
|
+
* @see {@link ActorConfig}
|
|
40
|
+
*/
|
|
41
|
+
export declare const createActor: (
|
|
42
|
+
canisterId: string | Principal,
|
|
43
|
+
options?: CreateActorOptions
|
|
44
|
+
) => ActorSubclass<_SERVICE>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Intialized Actor using default settings, ready to talk to a canister using its candid interface
|
|
48
|
+
* @constructs {@link ActorSubClass}
|
|
49
|
+
*/
|
|
50
|
+
export declare const bench: ActorSubclass<_SERVICE>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Actor, HttpAgent } from "@dfinity/agent";
|
|
2
|
+
|
|
3
|
+
// Imports and re-exports candid interface
|
|
4
|
+
import { idlFactory } from "./bench.did.js";
|
|
5
|
+
export { idlFactory } from "./bench.did.js";
|
|
6
|
+
|
|
7
|
+
/* CANISTER_ID is replaced by webpack based on node environment
|
|
8
|
+
* Note: canister environment variable will be standardized as
|
|
9
|
+
* process.env.CANISTER_ID_<CANISTER_NAME_UPPERCASE>
|
|
10
|
+
* beginning in dfx 0.15.0
|
|
11
|
+
*/
|
|
12
|
+
export const canisterId =
|
|
13
|
+
process.env.CANISTER_ID_BENCH ||
|
|
14
|
+
process.env.BENCH_CANISTER_ID;
|
|
15
|
+
|
|
16
|
+
export const createActor = (canisterId, options = {}) => {
|
|
17
|
+
const agent = options.agent || new HttpAgent({ ...options.agentOptions });
|
|
18
|
+
|
|
19
|
+
if (options.agent && options.agentOptions) {
|
|
20
|
+
console.warn(
|
|
21
|
+
"Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent."
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Fetch root key for certificate validation during development
|
|
26
|
+
if (process.env.DFX_NETWORK !== "ic") {
|
|
27
|
+
agent.fetchRootKey().catch((err) => {
|
|
28
|
+
console.warn(
|
|
29
|
+
"Unable to fetch root key. Check to ensure that your local replica is running"
|
|
30
|
+
);
|
|
31
|
+
console.error(err);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Creates an actor with using the candid interface and the HttpAgent
|
|
36
|
+
return Actor.createActor(idlFactory, {
|
|
37
|
+
agent,
|
|
38
|
+
canisterId,
|
|
39
|
+
...options.actorOptions,
|
|
40
|
+
});
|
|
41
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ import { bump } from './commands/bump.js';
|
|
|
22
22
|
import { sync } from './commands/sync.js';
|
|
23
23
|
import { outdated } from './commands/outdated.js';
|
|
24
24
|
import { update } from './commands/update.js';
|
|
25
|
+
import { bench } from './commands/bench.js';
|
|
25
26
|
import { transferOwnership } from './commands/transfer-ownership.js';
|
|
26
27
|
// import {docs} from './commands/docs.js';
|
|
27
28
|
program.name('mops');
|
|
@@ -178,6 +179,18 @@ program
|
|
|
178
179
|
.action(async (filter, options) => {
|
|
179
180
|
await test(filter, options);
|
|
180
181
|
});
|
|
182
|
+
// bench
|
|
183
|
+
program
|
|
184
|
+
.command('bench [filter]')
|
|
185
|
+
.description('Run benchmarks')
|
|
186
|
+
.addOption(new Option('--save', 'Save benchmark results to .bench/<filename>.json'))
|
|
187
|
+
.addOption(new Option('--compare', 'Run benchmark and compare results with .bench/<filename>.json'))
|
|
188
|
+
.addOption(new Option('--gc <gc>', 'Garbage collector').choices(['copying', 'compacting', 'generational', 'incremental']).default('incremental'))
|
|
189
|
+
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
190
|
+
.addOption(new Option('--verbose', 'Show more information'))
|
|
191
|
+
.action(async (filter, options) => {
|
|
192
|
+
await bench(filter, options);
|
|
193
|
+
});
|
|
181
194
|
// template
|
|
182
195
|
program
|
|
183
196
|
.command('template')
|
|
@@ -5,7 +5,7 @@ import ExperimentalInternetComputer "mo:base/ExperimentalInternetComputer";
|
|
|
5
5
|
import Prim "mo:prim";
|
|
6
6
|
import Bench "mo:bench";
|
|
7
7
|
|
|
8
|
-
import UserBench "./user-bench";
|
|
8
|
+
import UserBench "./user-bench"; // file path will be replaced with the *.bench.mo file path
|
|
9
9
|
|
|
10
10
|
actor class() {
|
|
11
11
|
var benchOpt : ?Bench.Bench = null;
|
|
@@ -32,48 +32,41 @@ actor class() {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
func _diffStats(before : Bench.BenchResult, after : Bench.BenchResult) : Bench.BenchResult {
|
|
36
|
+
{
|
|
37
|
+
instructions = after.instructions - before.instructions;
|
|
38
|
+
rts_heap_size = after.rts_heap_size - before.rts_heap_size;
|
|
39
|
+
rts_memory_size = after.rts_memory_size - before.rts_memory_size;
|
|
40
|
+
rts_total_allocation = after.rts_total_allocation - before.rts_total_allocation;
|
|
41
|
+
rts_mutator_instructions = after.rts_mutator_instructions - before.rts_mutator_instructions;
|
|
42
|
+
rts_collector_instructions = after.rts_collector_instructions - before.rts_collector_instructions;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
35
46
|
func _runCell(rowIndex : Nat, colIndex : Nat) : Bench.BenchResult {
|
|
36
47
|
let ?bench = benchOpt else Debug.trap("bench not initialized");
|
|
37
48
|
let statsBefore = _getStats();
|
|
38
49
|
|
|
39
|
-
let instructions = ExperimentalInternetComputer.countInstructions(func() {
|
|
50
|
+
let instructions = Nat64.toNat(ExperimentalInternetComputer.countInstructions(func() {
|
|
40
51
|
bench.runCell(rowIndex, colIndex);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// await (func() : async () {})();
|
|
52
|
+
}));
|
|
44
53
|
|
|
45
54
|
let statsAfter = _getStats();
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
instructions = Nat64.toNat(instructions);
|
|
49
|
-
rts_heap_size = statsAfter.rts_heap_size - statsBefore.rts_heap_size;
|
|
50
|
-
rts_memory_size = statsAfter.rts_memory_size - statsBefore.rts_memory_size;
|
|
51
|
-
rts_total_allocation = statsAfter.rts_total_allocation - statsBefore.rts_total_allocation;
|
|
52
|
-
rts_mutator_instructions = statsAfter.rts_mutator_instructions - statsBefore.rts_mutator_instructions;
|
|
53
|
-
rts_collector_instructions = statsAfter.rts_collector_instructions - statsBefore.rts_collector_instructions;
|
|
54
|
-
}
|
|
55
|
+
_diffStats(statsBefore, { statsAfter with instructions });
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
func _runCellAwait(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
58
59
|
let ?bench = benchOpt else Debug.trap("bench not initialized");
|
|
59
60
|
let statsBefore = _getStats();
|
|
60
61
|
|
|
61
|
-
let instructions = ExperimentalInternetComputer.countInstructions(func() {
|
|
62
|
+
let instructions = Nat64.toNat(ExperimentalInternetComputer.countInstructions(func() {
|
|
62
63
|
bench.runCell(rowIndex, colIndex);
|
|
63
|
-
});
|
|
64
|
+
}));
|
|
64
65
|
|
|
65
66
|
await (func() : async () {})();
|
|
66
67
|
|
|
67
68
|
let statsAfter = _getStats();
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
instructions = Nat64.toNat(instructions);
|
|
71
|
-
rts_heap_size = statsAfter.rts_heap_size - statsBefore.rts_heap_size;
|
|
72
|
-
rts_memory_size = statsAfter.rts_memory_size - statsBefore.rts_memory_size;
|
|
73
|
-
rts_total_allocation = statsAfter.rts_total_allocation - statsBefore.rts_total_allocation;
|
|
74
|
-
rts_mutator_instructions = statsAfter.rts_mutator_instructions - statsBefore.rts_mutator_instructions;
|
|
75
|
-
rts_collector_instructions = statsAfter.rts_collector_instructions - statsBefore.rts_collector_instructions;
|
|
76
|
-
}
|
|
69
|
+
_diffStats(statsBefore, { statsAfter with instructions });
|
|
77
70
|
};
|
|
78
71
|
|
|
79
72
|
public query func getStats() : async Bench.BenchResult {
|
|
@@ -85,10 +78,10 @@ actor class() {
|
|
|
85
78
|
};
|
|
86
79
|
|
|
87
80
|
public func runCellUpdate(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
88
|
-
|
|
81
|
+
_runCell(rowIndex, colIndex);
|
|
89
82
|
};
|
|
90
83
|
|
|
91
84
|
public func runCellUpdateAwait(rowIndex : Nat, colIndex : Nat) : async Bench.BenchResult {
|
|
92
|
-
|
|
85
|
+
await _runCellAwait(rowIndex, colIndex);
|
|
93
86
|
};
|
|
94
87
|
};
|
package/dist/commands/bench.js
CHANGED
|
@@ -36,7 +36,7 @@ export async function bench(filter = '', options = {}) {
|
|
|
36
36
|
verbose: false,
|
|
37
37
|
};
|
|
38
38
|
options = { ...defaultOptions, ...options };
|
|
39
|
-
console.log(options);
|
|
39
|
+
options.verbose && console.log(options);
|
|
40
40
|
let rootDir = getRootDir();
|
|
41
41
|
let globStr = '**/bench?(mark)/**/*.bench.mo';
|
|
42
42
|
if (filter) {
|
|
@@ -67,7 +67,14 @@ export async function bench(filter = '', options = {}) {
|
|
|
67
67
|
startDfx(options.verbose);
|
|
68
68
|
console.log('Deploying canisters...');
|
|
69
69
|
await parallel(os.cpus().length, files, async (file) => {
|
|
70
|
-
|
|
70
|
+
try {
|
|
71
|
+
await deployBenchFile(file, options);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error('Unexpected error. Stopping dfx replica...');
|
|
75
|
+
stopDfx(options.verbose);
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
71
78
|
});
|
|
72
79
|
await parallel(1, files, async (file) => {
|
|
73
80
|
console.log('\n' + '—'.repeat(50));
|
|
@@ -118,7 +125,7 @@ function dfxJson(canisterName, options = {}) {
|
|
|
118
125
|
networks: {
|
|
119
126
|
local: {
|
|
120
127
|
type: 'ephemeral',
|
|
121
|
-
bind: '127.0.0.1:
|
|
128
|
+
bind: '127.0.0.1:4944',
|
|
122
129
|
},
|
|
123
130
|
},
|
|
124
131
|
};
|
|
@@ -140,8 +147,9 @@ async function deployBenchFile(file, options = {}) {
|
|
|
140
147
|
// prepare temp files
|
|
141
148
|
fs.mkdirSync(tempDir, { recursive: true });
|
|
142
149
|
fs.writeFileSync(path.join(tempDir, 'dfx.json'), JSON.stringify(dfxJson(canisterName, options), null, 2));
|
|
143
|
-
fs.
|
|
144
|
-
|
|
150
|
+
let benchCanisterData = fs.readFileSync(new URL('./bench/bench-canister.mo', import.meta.url), 'utf8');
|
|
151
|
+
benchCanisterData = benchCanisterData.replace('./user-bench', path.relative(tempDir, file).replace(/.mo$/g, ''));
|
|
152
|
+
fs.writeFileSync(path.join(tempDir, 'canister.mo'), benchCanisterData);
|
|
145
153
|
// build canister
|
|
146
154
|
let mocPath = getMocPath();
|
|
147
155
|
let mocArgs = getMocArgs(options);
|
|
@@ -157,7 +165,7 @@ async function deployBenchFile(file, options = {}) {
|
|
|
157
165
|
let canisterId = execSync(`dfx canister id ${canisterName}`, { cwd: tempDir }).toString().trim();
|
|
158
166
|
let actor = await createActor(canisterId, {
|
|
159
167
|
agentOptions: {
|
|
160
|
-
host: 'http://127.0.0.1:
|
|
168
|
+
host: 'http://127.0.0.1:4944',
|
|
161
169
|
},
|
|
162
170
|
});
|
|
163
171
|
await actor.init();
|
|
@@ -170,7 +178,7 @@ async function runBenchFile(file, options = {}) {
|
|
|
170
178
|
let canisterId = execSync(`dfx canister id ${canisterName}`, { cwd: tempDir }).toString().trim();
|
|
171
179
|
let actor = await createActor(canisterId, {
|
|
172
180
|
agentOptions: {
|
|
173
|
-
host: 'http://127.0.0.1:
|
|
181
|
+
host: 'http://127.0.0.1:4944',
|
|
174
182
|
},
|
|
175
183
|
});
|
|
176
184
|
let schema = await actor.getSchema();
|
|
@@ -235,9 +243,9 @@ async function runBenchFile(file, options = {}) {
|
|
|
235
243
|
// run all cells
|
|
236
244
|
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
237
245
|
for (let [colIndex, col] of schema.cols.entries()) {
|
|
238
|
-
let res = await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex));
|
|
246
|
+
// let res = await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex));
|
|
239
247
|
// let res = await actor.runCellUpdate(BigInt(rowIndex), BigInt(colIndex));
|
|
240
|
-
|
|
248
|
+
let res = await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
241
249
|
results.set(`${row}:${col}`, res);
|
|
242
250
|
printResults();
|
|
243
251
|
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -176,6 +176,10 @@ export async function publish(options = {}) {
|
|
|
176
176
|
'!tests/**',
|
|
177
177
|
'!**/*.test.mo',
|
|
178
178
|
'!**/*.Test.mo',
|
|
179
|
+
'!bench/**',
|
|
180
|
+
'!benchmark/**',
|
|
181
|
+
'!**/*.bench.mo',
|
|
182
|
+
'!**/*.Bench.mo',
|
|
179
183
|
];
|
|
180
184
|
let files = config.package.files || ['**/*.mo'];
|
|
181
185
|
files = [...files, ...defaultFiles];
|
package/dist/commands/sources.js
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import { checkConfigFile, formatDir, formatGithubDir, getDependencyType, readConfig } from '../mops.js';
|
|
4
4
|
import { resolvePackages } from '../resolve-packages.js';
|
|
5
5
|
// TODO: resolve conflicts
|
|
6
|
-
export async function sources({ verbose = false } = {}) {
|
|
6
|
+
export async function sources({ verbose = false, cwd = process.cwd() } = {}) {
|
|
7
7
|
if (!checkConfigFile()) {
|
|
8
8
|
return [];
|
|
9
9
|
}
|
|
@@ -13,13 +13,13 @@ export async function sources({ verbose = false } = {}) {
|
|
|
13
13
|
let depType = getDependencyType(version);
|
|
14
14
|
let pkgDir;
|
|
15
15
|
if (depType === 'local') {
|
|
16
|
-
pkgDir = path.relative(
|
|
16
|
+
pkgDir = path.relative(cwd, version);
|
|
17
17
|
}
|
|
18
18
|
else if (depType === 'github') {
|
|
19
|
-
pkgDir = path.relative(
|
|
19
|
+
pkgDir = path.relative(cwd, formatGithubDir(name, version));
|
|
20
20
|
}
|
|
21
21
|
else if (depType === 'mops') {
|
|
22
|
-
pkgDir = path.relative(
|
|
22
|
+
pkgDir = path.relative(cwd, formatDir(name, version));
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
25
|
return;
|
package/dist/package.json
CHANGED
|
@@ -1,82 +1,83 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
2
|
+
"name": "ic-mops",
|
|
3
|
+
"version": "0.32.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mops": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"*",
|
|
10
|
+
"!network.txt",
|
|
11
|
+
"!.mops",
|
|
12
|
+
"/templates"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mops.one",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/ZenVoich/mops.git"
|
|
18
|
+
},
|
|
19
|
+
"author": "Zen Voich <zen.voich@gmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=16.0.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"bundle": "esbuild --bundle --outfile=cli.js --platform=node --packages=external --target=node16 --format=esm ./dist/cli.js",
|
|
27
|
+
"copy": "cp -r commands/bench dist/commands && cp -r declarations templates network.txt package.json dist | true",
|
|
28
|
+
"save-network": "cp -r dist/network.txt . | true",
|
|
29
|
+
"prepare": "npm run save-network && npm run build && npm run copy",
|
|
30
|
+
"check": "tsc --project tsconfig.json --noEmit",
|
|
31
|
+
"tsc": "tsc",
|
|
32
|
+
"esbuild": "esbuild"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@dfinity/agent": "^0.18.1",
|
|
36
|
+
"@dfinity/candid": "^0.18.1",
|
|
37
|
+
"@dfinity/identity": "^0.18.1",
|
|
38
|
+
"@dfinity/identity-secp256k1": "^0.18.1",
|
|
39
|
+
"@dfinity/principal": "^0.18.1",
|
|
40
|
+
"@iarna/toml": "^2.2.5",
|
|
41
|
+
"as-table": "^1.0.55",
|
|
42
|
+
"cacheable-request": "10.2.12",
|
|
43
|
+
"camelcase": "^7.0.1",
|
|
44
|
+
"chalk": "^5.3.0",
|
|
45
|
+
"chokidar": "^3.5.3",
|
|
46
|
+
"commander": "^11.0.0",
|
|
47
|
+
"debounce": "^1.2.1",
|
|
48
|
+
"decompress": "^4.2.1",
|
|
49
|
+
"del": "^7.0.0",
|
|
50
|
+
"dhall-to-json-cli": "^1.7.6",
|
|
51
|
+
"eslint": "^8.45.0",
|
|
52
|
+
"execa": "7.1.1",
|
|
53
|
+
"get-folder-size": "^4.0.0",
|
|
54
|
+
"glob": "^10.3.3",
|
|
55
|
+
"globby": "^13.2.2",
|
|
56
|
+
"got": "13.0.0",
|
|
57
|
+
"log-update": "^5.0.1",
|
|
58
|
+
"markdown-table": "3.0.3",
|
|
59
|
+
"mdast-util-from-markdown": "^2.0.0",
|
|
60
|
+
"mdast-util-to-markdown": "^2.1.0",
|
|
61
|
+
"minimatch": "^9.0.3",
|
|
62
|
+
"ncp": "^2.0.0",
|
|
63
|
+
"node-fetch": "^3.3.2",
|
|
64
|
+
"pem-file": "^1.0.1",
|
|
65
|
+
"prompts": "^2.4.2",
|
|
66
|
+
"stream-to-promise": "^3.0.0",
|
|
67
|
+
"tar": "^6.1.15"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@tsconfig/strictest": "^2.0.1",
|
|
71
|
+
"@types/debounce": "^1.2.1",
|
|
72
|
+
"@types/decompress": "^4.2.4",
|
|
73
|
+
"@types/glob": "^8.1.0",
|
|
74
|
+
"@types/ncp": "^2.0.5",
|
|
75
|
+
"@types/node": "^20.4.4",
|
|
76
|
+
"@types/prompts": "^2.4.4",
|
|
77
|
+
"@types/stream-to-promise": "^2.2.1",
|
|
78
|
+
"@types/tar": "^6.1.5",
|
|
79
|
+
"esbuild": "^0.18.16",
|
|
80
|
+
"tsx": "^3.12.7",
|
|
81
|
+
"typescript": "^5.1.6"
|
|
82
|
+
}
|
|
82
83
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {execSync} from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
export function getMocPath(): string {
|
|
4
|
+
let mocPath = process.env.DFX_MOC_PATH;
|
|
5
|
+
if (!mocPath) {
|
|
6
|
+
mocPath = execSync('dfx cache show').toString().trim() + '/moc';
|
|
7
|
+
}
|
|
8
|
+
if (!mocPath) {
|
|
9
|
+
mocPath = 'moc';
|
|
10
|
+
}
|
|
11
|
+
return mocPath;
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {execSync} from 'node:child_process';
|
|
2
|
+
import {getMocPath} from './get-moc-path.js';
|
|
3
|
+
|
|
4
|
+
export function getMocVersion(): string {
|
|
5
|
+
let mocPath = getMocPath();
|
|
6
|
+
let match = execSync(mocPath).toString().trim().match(/Motoko compiler ([^\s]+) .*/);
|
|
7
|
+
return match?.[1] || '';
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -1,82 +1,83 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
2
|
+
"name": "ic-mops",
|
|
3
|
+
"version": "0.32.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mops": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"*",
|
|
10
|
+
"!network.txt",
|
|
11
|
+
"!.mops",
|
|
12
|
+
"/templates"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mops.one",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/ZenVoich/mops.git"
|
|
18
|
+
},
|
|
19
|
+
"author": "Zen Voich <zen.voich@gmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=16.0.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"bundle": "esbuild --bundle --outfile=cli.js --platform=node --packages=external --target=node16 --format=esm ./dist/cli.js",
|
|
27
|
+
"copy": "cp -r commands/bench dist/commands && cp -r declarations templates network.txt package.json dist | true",
|
|
28
|
+
"save-network": "cp -r dist/network.txt . | true",
|
|
29
|
+
"prepare": "npm run save-network && npm run build && npm run copy",
|
|
30
|
+
"check": "tsc --project tsconfig.json --noEmit",
|
|
31
|
+
"tsc": "tsc",
|
|
32
|
+
"esbuild": "esbuild"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@dfinity/agent": "^0.18.1",
|
|
36
|
+
"@dfinity/candid": "^0.18.1",
|
|
37
|
+
"@dfinity/identity": "^0.18.1",
|
|
38
|
+
"@dfinity/identity-secp256k1": "^0.18.1",
|
|
39
|
+
"@dfinity/principal": "^0.18.1",
|
|
40
|
+
"@iarna/toml": "^2.2.5",
|
|
41
|
+
"as-table": "^1.0.55",
|
|
42
|
+
"cacheable-request": "10.2.12",
|
|
43
|
+
"camelcase": "^7.0.1",
|
|
44
|
+
"chalk": "^5.3.0",
|
|
45
|
+
"chokidar": "^3.5.3",
|
|
46
|
+
"commander": "^11.0.0",
|
|
47
|
+
"debounce": "^1.2.1",
|
|
48
|
+
"decompress": "^4.2.1",
|
|
49
|
+
"del": "^7.0.0",
|
|
50
|
+
"dhall-to-json-cli": "^1.7.6",
|
|
51
|
+
"eslint": "^8.45.0",
|
|
52
|
+
"execa": "7.1.1",
|
|
53
|
+
"get-folder-size": "^4.0.0",
|
|
54
|
+
"glob": "^10.3.3",
|
|
55
|
+
"globby": "^13.2.2",
|
|
56
|
+
"got": "13.0.0",
|
|
57
|
+
"log-update": "^5.0.1",
|
|
58
|
+
"markdown-table": "3.0.3",
|
|
59
|
+
"mdast-util-from-markdown": "^2.0.0",
|
|
60
|
+
"mdast-util-to-markdown": "^2.1.0",
|
|
61
|
+
"minimatch": "^9.0.3",
|
|
62
|
+
"ncp": "^2.0.0",
|
|
63
|
+
"node-fetch": "^3.3.2",
|
|
64
|
+
"pem-file": "^1.0.1",
|
|
65
|
+
"prompts": "^2.4.2",
|
|
66
|
+
"stream-to-promise": "^3.0.0",
|
|
67
|
+
"tar": "^6.1.15"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@tsconfig/strictest": "^2.0.1",
|
|
71
|
+
"@types/debounce": "^1.2.1",
|
|
72
|
+
"@types/decompress": "^4.2.4",
|
|
73
|
+
"@types/glob": "^8.1.0",
|
|
74
|
+
"@types/ncp": "^2.0.5",
|
|
75
|
+
"@types/node": "^20.4.4",
|
|
76
|
+
"@types/prompts": "^2.4.4",
|
|
77
|
+
"@types/stream-to-promise": "^2.2.1",
|
|
78
|
+
"@types/tar": "^6.1.5",
|
|
79
|
+
"esbuild": "^0.18.16",
|
|
80
|
+
"tsx": "^3.12.7",
|
|
81
|
+
"typescript": "^5.1.6"
|
|
82
|
+
}
|
|
82
83
|
}
|