@nite-framework/nite-zk-profiler 0.2.0 → 0.2.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.
- package/README.md +31 -11
- package/dist/budget.d.ts +16 -0
- package/dist/budget.js +27 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +39 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,13 +38,14 @@ It reports the cost class of every circuit in your contract.
|
|
|
38
38
|
```text
|
|
39
39
|
$ nite-zk profile Sample.compact
|
|
40
40
|
|
|
41
|
-
circuit
|
|
42
|
-
bump
|
|
43
|
-
balanceOf
|
|
44
|
-
register
|
|
45
|
-
insert32
|
|
46
|
-
|
|
47
|
-
4 circuits, toolchain 0.31.1, zkir 2.1.0, 0.
|
|
41
|
+
circuit rows k capacity cost est. prove
|
|
42
|
+
bump 24 5 32 1x ~10ms
|
|
43
|
+
balanceOf 305 9 512 16x ~165ms
|
|
44
|
+
register 368 9 512 16x ~165ms
|
|
45
|
+
insert32 2299 13 8192 256x ~2.6s
|
|
46
|
+
|
|
47
|
+
4 circuits, toolchain 0.31.1, midnight-zkir 2.1.0, 0.9s
|
|
48
|
+
est. prove is modelled as 2^k on an uncalibrated default. Run `nite-zk calibrate` to anchor it.
|
|
48
49
|
```
|
|
49
50
|
|
|
50
51
|
`k` is the number that matters. `cost` is `2^k` expressed relative to the cheapest circuit in the contract, so you can see at a glance which circuits dominate your proving budget.
|
|
@@ -370,20 +371,21 @@ Anything outside this range is rejected with a clear error naming the version fo
|
|
|
370
371
|
## Command line surface
|
|
371
372
|
|
|
372
373
|
```text
|
|
373
|
-
nite-zk profile <source...> Report rows, k and
|
|
374
|
+
nite-zk profile <source...> Report rows, k, cost and estimated proving time
|
|
374
375
|
nite-zk save <source...> Write zk-budget.json from current measurements
|
|
375
376
|
nite-zk check [<source...>] Compare against zk-budget.json
|
|
376
377
|
nite-zk diff <ref> [<source>] Compare a contract against a git ref
|
|
377
378
|
nite-zk calibrate --observed <ms> --at-k <k>
|
|
378
379
|
Anchor proving estimates to a real proof
|
|
379
380
|
|
|
380
|
-
--estimate
|
|
381
|
+
--no-estimate Hide the modelled proving time column
|
|
381
382
|
--deep Also generate real proving keys, and report
|
|
382
383
|
measured setup time and prover key size
|
|
383
384
|
--json Machine readable output
|
|
384
385
|
--out <dir> Compile into a specific directory
|
|
385
386
|
--budget <file> Use a different baseline path
|
|
386
387
|
--strict check: fail on circuits missing from the budget
|
|
388
|
+
--replace save: overwrite the budget instead of merging
|
|
387
389
|
--no-color Plain output (NO_COLOR is honoured too)
|
|
388
390
|
--no-cache Ignore cached measurements for this run
|
|
389
391
|
+VERSION Pin the Compact toolchain, e.g. +0.31.1
|
|
@@ -401,6 +403,23 @@ Wrote zk-budget.json: 2 contracts, 16 circuits
|
|
|
401
403
|
`check` then reads every contract back out of the budget, so CI stays one step
|
|
402
404
|
whether the repository holds one contract or ten.
|
|
403
405
|
|
|
406
|
+
Contracts can also be added one at a time. `save` merges into an existing
|
|
407
|
+
budget rather than replacing it, and says what it did:
|
|
408
|
+
|
|
409
|
+
```text
|
|
410
|
+
$ nite-zk save packages/mint/src/mint.compact
|
|
411
|
+
Wrote /repo/zk-budget.json
|
|
412
|
+
1 contract, 3 circuits
|
|
413
|
+
added: packages/mint/src/mint.compact
|
|
414
|
+
kept: packages/pool/src/lending.compact
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
`--replace` writes a fresh file when you do want the old entries gone.
|
|
418
|
+
|
|
419
|
+
The budget is written relative to the working directory, and `save` prints the
|
|
420
|
+
full path it wrote, so running it from the wrong directory is visible
|
|
421
|
+
immediately rather than leaving a file somewhere unexpected.
|
|
422
|
+
|
|
404
423
|
### Comparing against a branch
|
|
405
424
|
|
|
406
425
|
```text
|
|
@@ -420,8 +439,9 @@ check without committing a budget file first.
|
|
|
420
439
|
|
|
421
440
|
### Estimated proving time
|
|
422
441
|
|
|
423
|
-
|
|
424
|
-
dominated by work over the full
|
|
442
|
+
`profile` shows an estimated proving time by default, modelled as
|
|
443
|
+
`time = rate * 2^k`, since a Halo2 proof is dominated by work over the full
|
|
444
|
+
`2^k` domain. `--no-estimate` hides the column.
|
|
425
445
|
|
|
426
446
|
The rate is machine specific, so the shipped default is only an order of
|
|
427
447
|
magnitude. Time one real proof and record it, and every estimate becomes
|
package/dist/budget.d.ts
CHANGED
|
@@ -44,6 +44,22 @@ export interface ContractCosts {
|
|
|
44
44
|
}
|
|
45
45
|
/** Build a budget granting every circuit exactly what it currently costs. */
|
|
46
46
|
export declare function budgetFrom(contracts: ContractCosts[], toolchainLine: string): Budget;
|
|
47
|
+
export interface MergeSummary {
|
|
48
|
+
added: string[];
|
|
49
|
+
updated: string[];
|
|
50
|
+
kept: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fold a new save into an existing budget.
|
|
54
|
+
*
|
|
55
|
+
* Saving one contract must not silently discard the others. A monorepo is
|
|
56
|
+
* saved a contract at a time, and without merging each save wipes the previous
|
|
57
|
+
* one, which looks like it worked and quietly loses the ceilings you committed.
|
|
58
|
+
*/
|
|
59
|
+
export declare function mergeBudgets(existing: Budget, incoming: Budget): {
|
|
60
|
+
budget: Budget;
|
|
61
|
+
summary: MergeSummary;
|
|
62
|
+
};
|
|
47
63
|
export declare function writeBudget(path: string, budget: Budget): void;
|
|
48
64
|
export declare function readBudget(path: string): Budget;
|
|
49
65
|
/** Every contract the budget describes. */
|
package/dist/budget.js
CHANGED
|
@@ -24,6 +24,33 @@ export function budgetFrom(contracts, toolchainLine) {
|
|
|
24
24
|
contracts: out,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Fold a new save into an existing budget.
|
|
29
|
+
*
|
|
30
|
+
* Saving one contract must not silently discard the others. A monorepo is
|
|
31
|
+
* saved a contract at a time, and without merging each save wipes the previous
|
|
32
|
+
* one, which looks like it worked and quietly loses the ceilings you committed.
|
|
33
|
+
*/
|
|
34
|
+
export function mergeBudgets(existing, incoming) {
|
|
35
|
+
const contracts = { ...existing.contracts };
|
|
36
|
+
const summary = { added: [], updated: [], kept: [] };
|
|
37
|
+
for (const [source, contract] of Object.entries(incoming.contracts)) {
|
|
38
|
+
(source in contracts ? summary.updated : summary.added).push(source);
|
|
39
|
+
contracts[source] = contract;
|
|
40
|
+
}
|
|
41
|
+
for (const source of Object.keys(existing.contracts)) {
|
|
42
|
+
if (!(source in incoming.contracts) && source.length > 0)
|
|
43
|
+
summary.kept.push(source);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
budget: { ...incoming, contracts },
|
|
47
|
+
summary: {
|
|
48
|
+
added: summary.added.sort(),
|
|
49
|
+
updated: summary.updated.sort(),
|
|
50
|
+
kept: summary.kept.sort(),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
27
54
|
export function writeBudget(path, budget) {
|
|
28
55
|
writeFileSync(path, `${JSON.stringify(budget, null, 2)}\n`, "utf8");
|
|
29
56
|
}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
3
|
import { analyze } from "./analyze.js";
|
|
4
|
-
import { DEFAULT_BUDGET_PATH, budgetFrom, budgetSources, check, readBudget, writeBudget, } from "./budget.js";
|
|
4
|
+
import { DEFAULT_BUDGET_PATH, budgetFrom, budgetSources, check, mergeBudgets, readBudget, writeBudget, } from "./budget.js";
|
|
5
5
|
import { cacheKey, readCache, writeCache } from "./cache.js";
|
|
6
6
|
import { setColorEnabled } from "./colors.js";
|
|
7
7
|
import { compileSkipZk } from "./compile.js";
|
|
@@ -17,7 +17,7 @@ import { toolVersion } from "./version.js";
|
|
|
17
17
|
const USAGE = `nite-zk - see what a Compact circuit costs to prove
|
|
18
18
|
|
|
19
19
|
Usage:
|
|
20
|
-
nite-zk profile <source...> Report rows, k and
|
|
20
|
+
nite-zk profile <source...> Report rows, k, cost and estimated proving time
|
|
21
21
|
nite-zk save <source...> Write zk-budget.json from current measurements
|
|
22
22
|
nite-zk check [<source...>] Compare against zk-budget.json
|
|
23
23
|
Sources are optional once saved, since the
|
|
@@ -27,13 +27,14 @@ Usage:
|
|
|
27
27
|
Anchor proving estimates to a real proof
|
|
28
28
|
|
|
29
29
|
Options:
|
|
30
|
-
--estimate
|
|
30
|
+
--no-estimate Hide the modelled proving time column
|
|
31
31
|
--deep Also generate real proving keys and report
|
|
32
32
|
measured setup time and prover key size
|
|
33
33
|
--json Machine readable output
|
|
34
34
|
--out <dir> Compile into a specific directory (kept)
|
|
35
35
|
--budget <file> Budget path (default: ${DEFAULT_BUDGET_PATH})
|
|
36
36
|
--strict check: fail on circuits missing from the budget
|
|
37
|
+
--replace save: overwrite the budget instead of merging
|
|
37
38
|
--no-color Plain output (also honours NO_COLOR)
|
|
38
39
|
--no-cache Ignore cached measurements for this run
|
|
39
40
|
+VERSION Pin the Compact toolchain, e.g. +0.31.1
|
|
@@ -47,8 +48,9 @@ export function parseArgs(argv) {
|
|
|
47
48
|
sources: [],
|
|
48
49
|
json: false,
|
|
49
50
|
strict: false,
|
|
51
|
+
replace: false,
|
|
50
52
|
deep: false,
|
|
51
|
-
estimate:
|
|
53
|
+
estimate: true,
|
|
52
54
|
noColor: false,
|
|
53
55
|
noCache: false,
|
|
54
56
|
budget: DEFAULT_BUDGET_PATH,
|
|
@@ -61,10 +63,14 @@ export function parseArgs(argv) {
|
|
|
61
63
|
opts.json = true;
|
|
62
64
|
else if (arg === "--strict")
|
|
63
65
|
opts.strict = true;
|
|
66
|
+
else if (arg === "--replace")
|
|
67
|
+
opts.replace = true;
|
|
64
68
|
else if (arg === "--deep")
|
|
65
69
|
opts.deep = true;
|
|
66
70
|
else if (arg === "--estimate")
|
|
67
71
|
opts.estimate = true;
|
|
72
|
+
else if (arg === "--no-estimate")
|
|
73
|
+
opts.estimate = false;
|
|
68
74
|
else if (arg === "--no-color")
|
|
69
75
|
opts.noColor = true;
|
|
70
76
|
else if (arg === "--no-cache")
|
|
@@ -260,12 +266,36 @@ export async function run(argv) {
|
|
|
260
266
|
// stored relative to the budget file so the pair stays portable.
|
|
261
267
|
const base = dirname(resolve(opts.budget));
|
|
262
268
|
const line = `${run_.toolchain.version.split(".").slice(0, 2).join(".")}.x`;
|
|
263
|
-
const
|
|
264
|
-
|
|
269
|
+
const fresh = budgetFrom(run_.contracts.map((c) => ({ source: relative(base, resolve(c.source)), costs: c.costs })), line);
|
|
270
|
+
// Merge rather than overwrite. Saving one contract at a time is the normal
|
|
271
|
+
// way to set up a monorepo, and replacing the file each time would discard
|
|
272
|
+
// ceilings that are already committed, silently and while reporting success.
|
|
273
|
+
let existing;
|
|
274
|
+
if (!opts.replace) {
|
|
275
|
+
try {
|
|
276
|
+
existing = readBudget(opts.budget);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
existing = undefined;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const merged = existing ? mergeBudgets(existing, fresh) : { budget: fresh, summary: undefined };
|
|
283
|
+
writeBudget(opts.budget, merged.budget);
|
|
265
284
|
const circuits = run_.contracts.reduce((n, c) => n + c.costs.length, 0);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
285
|
+
const written = resolve(opts.budget);
|
|
286
|
+
process.stdout.write(`Wrote ${written}\n` +
|
|
287
|
+
` ${run_.contracts.length} contract${run_.contracts.length === 1 ? "" : "s"}, ` +
|
|
288
|
+
`${circuits} circuit${circuits === 1 ? "" : "s"}\n`);
|
|
289
|
+
const s_ = merged.summary;
|
|
290
|
+
if (s_) {
|
|
291
|
+
if (s_.added.length)
|
|
292
|
+
process.stdout.write(` added: ${s_.added.join(", ")}\n`);
|
|
293
|
+
if (s_.updated.length)
|
|
294
|
+
process.stdout.write(` updated: ${s_.updated.join(", ")}\n`);
|
|
295
|
+
if (s_.kept.length)
|
|
296
|
+
process.stdout.write(` kept: ${s_.kept.join(", ")}\n`);
|
|
297
|
+
}
|
|
298
|
+
process.stdout.write("Check it in, then run `nite-zk check` in CI.\n");
|
|
269
299
|
return 0;
|
|
270
300
|
}
|
|
271
301
|
export async function main(argv) {
|