perf(rust-kernel): Intern-assigned uids, symbolic Nat offsets, environment-machine WHNF reducer - #442
perf(rust-kernel): Intern-assigned uids, symbolic Nat offsets, environment-machine WHNF reducer#442samuelburnham wants to merge 24 commits into
Conversation
fbf4c7a to
4d2452d
Compare
582d40b to
61cb1bd
Compare
5b0cf31 to
06e1a1d
Compare
|
!benchmark zisk ooc |
|
| env/constant | check-time (main) | check-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|
InitStd |
10.963 s | 17.971 s | +63.9% (1.64× slower) |
8.12K | 4.95K | -39.0% (1.64× slower) |
1.88 GiB | 1.81 GiB | -4.1% 🟢 |
Std.Tactic.BVDecide.BVExpr.bitblast.goCache_Inv_of_Inv._mutual |
6.387 s | 4.896 s | -23.3% (1.30× faster) 🟢 | 887.050 | 1.16K | +30.5% (1.30× faster) 🟢 | 1.88 GiB | 1.75 GiB | -6.7% (1.07× smaller) 🟢 |
Array.extract_append |
1.017 s | 769.2 ms | -24.4% (1.32× faster) 🟢 | 1.52K | 2.01K | +32.2% (1.32× faster) 🟢 | 1.23 GiB | 1.38 GiB | +11.8% (1.12× larger) |
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
529.5 ms | 532.6 ms | +0.6% | 5.09K | 5.06K | -0.6% | 1.23 GiB | 1.12 GiB | -8.7% (1.10× smaller) 🟢 |
Vector.extract_append._proof_2 |
1.012 s | 513.8 ms | -49.3% (1.97× faster) 🟢 | 1.29K | 2.55K | +97.1% (1.97× faster) 🟢 | 1.42 GiB | 1.51 GiB | +6.5% (1.07× larger) |
Char.ofOrdinal_le_of_le |
774.1 ms | 276.9 ms | -64.2% (2.80× faster) 🟢 | 3.43K | 9.60K | +179.6% (2.80× faster) 🟢 | 1.03 GiB | 925.72 MiB | -12.0% (1.14× smaller) 🟢 |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
1.015 s | 267.3 ms | -73.7% (3.80× faster) 🟢 | 1.79K | 6.80K | +279.6% (3.80× faster) 🟢 | 1.45 GiB | 1.53 GiB | +5.9% (1.06× larger) |
String.split |
264.2 ms | 265.2 ms | +0.4% | 6.71K | 6.68K | -0.4% | 1.19 GiB | 1.29 GiB | +8.4% (1.08× larger) |
List.mergeSort |
261.6 ms | 262.7 ms | +0.4% | 5.56K | 5.53K | -0.4% | 932.45 MiB | 975.80 MiB | +4.6% |
Nat.gcd_comm |
254.2 ms | 255.0 ms | +0.3% | 1.53K | 1.53K | -0.3% | 809.72 MiB | 848.80 MiB | +4.8% |
Vector.append |
255.2 ms | 255.0 ms | -0.1% | 1.95K | 1.95K | +0.1% | 808.94 MiB | 760.88 MiB | -5.9% (1.06× smaller) 🟢 |
String.append |
253.0 ms | 253.1 ms | +0.0% | 1.21K | 1.21K | -0.0% | 1.12 GiB | 1.19 GiB | +6.7% (1.07× larger) |
Nat.sub_le_of_le_add |
253.1 ms | 252.7 ms | -0.2% | 671.680 | 672.790 | +0.2% | 586.75 MiB | 572.40 MiB | -2.4% |
Nat.add_comm |
252.1 ms | 252.6 ms | +0.2% | 166.590 | 166.280 | -0.2% | 474.31 MiB | 448.05 MiB | -5.5% (1.06× smaller) 🟢 |
Int.gcd |
252.6 ms | 252.6 ms | +0.0% | 823.580 | 823.520 | -0.0% | 650.78 MiB | 650.53 MiB | -0.0% |
15 env/constants · 8 with regressions · 9 with improvements (|Δ| > 3.0% on any metric).
zisk · InitStd — main from: base run @ 3312c3f (not on bencher)
| constant | execute-time (main) | execute-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% | cycles (main) | cycles (PR) | Δ% | constants (main) | constants (PR) | Δ% | shards (main) | shards (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
n/a | 42.805 s | n/a | n/a | 65 | n/a | n/a | 53.80 GiB | n/a | n/a | 18.72B | n/a | n/a | 2,785 | n/a | n/a | 33 | n/a |
Char.ofOrdinal_le_of_le |
n/a | 29.434 s | n/a | n/a | 94 | n/a | n/a | 53.56 GiB | n/a | n/a | 12.90B | n/a | n/a | 2,776 | n/a | n/a | 22 | n/a |
Array.extract_append |
n/a | 28.808 s | n/a | n/a | 56 | n/a | n/a | 70.50 GiB | n/a | n/a | 12.48B | n/a | n/a | 1,627 | n/a | n/a | 13 | n/a |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
n/a | 16.974 s | n/a | n/a | 112 | n/a | n/a | 52.95 GiB | n/a | n/a | 7.35B | n/a | n/a | 1,896 | n/a | n/a | 13 | n/a |
Vector.extract_append._proof_2 |
n/a | 16.387 s | n/a | n/a | 83 | n/a | n/a | 70.52 GiB | n/a | n/a | 7.03B | n/a | n/a | 1,367 | n/a | n/a | 8 | n/a |
String.split |
n/a | 14.493 s | n/a | n/a | 129 | n/a | n/a | 52.97 GiB | n/a | n/a | 6.42B | n/a | n/a | 1,867 | n/a | n/a | 11 | n/a |
List.mergeSort |
n/a | 11.234 s | n/a | n/a | 135 | n/a | n/a | 52.76 GiB | n/a | n/a | 4.91B | n/a | n/a | 1,517 | n/a | n/a | 9 | n/a |
Vector.append |
n/a | 2.477 s | n/a | n/a | 222 | n/a | n/a | 52.42 GiB | n/a | n/a | 1.10B | n/a | n/a | 550 | n/a | n/a | 3 | n/a |
Nat.gcd_comm |
n/a | 1.683 s | n/a | n/a | 245 | n/a | n/a | 52.08 GiB | n/a | n/a | 742.79M | n/a | n/a | 413 | n/a | n/a | 2 | n/a |
String.append |
n/a | 820.6 ms | n/a | n/a | 409 | n/a | n/a | 55.34 GiB | n/a | n/a | 360.74M | n/a | n/a | 336 | n/a | n/a | 1 | n/a |
Int.gcd |
n/a | 566.4 ms | n/a | n/a | 401 | n/a | n/a | 55.19 GiB | n/a | n/a | 245.33M | n/a | n/a | 227 | n/a | n/a | 1 | n/a |
Nat.sub_le_of_le_add |
n/a | 527.5 ms | n/a | n/a | 356 | n/a | n/a | 55.17 GiB | n/a | n/a | 222.43M | n/a | n/a | 188 | n/a | n/a | 1 | n/a |
Nat.add_comm |
n/a | 110.0 ms | n/a | n/a | 445 | n/a | n/a | 55.20 GiB | n/a | n/a | 31.51M | n/a | n/a | 49 | n/a | n/a | 1 | n/a |
13 constants · 0 with regressions · 0 with improvements (|Δ| > 3.0% on any metric).
06e1a1d to
cbbad89
Compare
|
!benchmark zisk ooc |
|
| env/constant | check-time (main) | check-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|
InitStd |
9.461 s | 16.468 s | +74.1% (1.74× slower) |
9.41K | 5.41K | -42.5% (1.74× slower) |
1.90 GiB | 2.00 GiB | +5.3% (1.05× larger) |
Std.Tactic.BVDecide.BVExpr.bitblast.goCache_Inv_of_Inv._mutual |
6.390 s | 4.641 s | -27.4% (1.38× faster) 🟢 | 886.700 | 1.22K | +37.7% (1.38× faster) 🟢 | 1.92 GiB | 1.87 GiB | -2.4% |
Array.extract_append |
1.016 s | 767.5 ms | -24.5% (1.32× faster) 🟢 | 1.52K | 2.02K | +32.4% (1.32× faster) 🟢 | 1.25 GiB | 1.53 GiB | +23.1% (1.23× larger) |
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
528.2 ms | 531.4 ms | +0.6% | 5.11K | 5.08K | -0.6% | 1.09 GiB | 1.16 GiB | +6.2% (1.06× larger) |
Vector.extract_append._proof_2 |
1.012 s | 512.6 ms | -49.3% (1.97× faster) 🟢 | 1.29K | 2.55K | +97.4% (1.97× faster) 🟢 | 1.45 GiB | 1.43 GiB | -1.1% |
Char.ofOrdinal_le_of_le |
773.0 ms | 275.5 ms | -64.4% (2.81× faster) 🟢 | 3.44K | 9.65K | +180.5% (2.81× faster) 🟢 | 982.46 MiB | 1.28 GiB | +33.4% (1.33× larger) |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
764.2 ms | 265.3 ms | -65.3% (2.88× faster) 🟢 | 2.38K | 6.85K | +188.0% (2.88× faster) 🟢 | 1.37 GiB | 1.28 GiB | -6.6% (1.07× smaller) 🟢 |
String.split |
263.3 ms | 264.5 ms | +0.5% | 6.73K | 6.70K | -0.5% | 1.24 GiB | 1.26 GiB | +2.0% |
List.mergeSort |
261.0 ms | 262.0 ms | +0.4% | 5.57K | 5.55K | -0.4% | 966.89 MiB | 1.04 GiB | +9.7% (1.10× larger) |
Vector.append |
254.2 ms | 255.2 ms | +0.4% | 1.96K | 1.95K | -0.4% | 701.89 MiB | 841.38 MiB | +19.9% (1.20× larger) |
Nat.gcd_comm |
253.9 ms | 254.2 ms | +0.1% | 1.54K | 1.53K | -0.1% | 881.78 MiB | 841.38 MiB | -4.6% 🟢 |
String.append |
253.0 ms | 253.0 ms | +0.0% | 1.21K | 1.21K | -0.0% | 1.15 GiB | 1.23 GiB | +7.1% (1.07× larger) |
Int.gcd |
252.4 ms | 252.7 ms | +0.1% | 824.160 | 823.060 | -0.1% | 729.70 MiB | 679.06 MiB | -6.9% (1.07× smaller) 🟢 |
Nat.sub_le_of_le_add |
252.5 ms | 252.4 ms | -0.0% | 673.370 | 673.500 | +0.0% | 648.44 MiB | 594.73 MiB | -8.3% (1.09× smaller) 🟢 |
Nat.add_comm |
252.0 ms | 252.0 ms | -0.0% | 166.680 | 166.700 | +0.0% | 509.85 MiB | 462.18 MiB | -9.3% (1.10× smaller) 🟢 |
15 env/constants · 7 with regressions · 9 with improvements (|Δ| > 3.0% on any metric).
zisk · InitStd — main from: base run @ 7d99a71 (not on bencher)
| constant | execute-time (main) | execute-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% | cycles (main) | cycles (PR) | Δ% | constants (main) | constants (PR) | Δ% | shards (main) | shards (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
n/a | 42.342 s | n/a | n/a | 66 | n/a | n/a | 53.80 GiB | n/a | n/a | 18.72B | n/a | n/a | 2,785 | n/a | n/a | 33 | n/a |
Char.ofOrdinal_le_of_le |
n/a | 29.300 s | n/a | n/a | 95 | n/a | n/a | 53.43 GiB | n/a | n/a | 12.92B | n/a | n/a | 2,776 | n/a | n/a | 22 | n/a |
Array.extract_append |
n/a | 28.328 s | n/a | n/a | 57 | n/a | n/a | 70.54 GiB | n/a | n/a | 12.48B | n/a | n/a | 1,627 | n/a | n/a | 13 | n/a |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
n/a | 16.641 s | n/a | n/a | 114 | n/a | n/a | 53.01 GiB | n/a | n/a | 7.35B | n/a | n/a | 1,896 | n/a | n/a | 13 | n/a |
Vector.extract_append._proof_2 |
n/a | 16.227 s | n/a | n/a | 84 | n/a | n/a | 70.59 GiB | n/a | n/a | 7.03B | n/a | n/a | 1,367 | n/a | n/a | 8 | n/a |
String.split |
n/a | 14.494 s | n/a | n/a | 129 | n/a | n/a | 52.97 GiB | n/a | n/a | 6.42B | n/a | n/a | 1,867 | n/a | n/a | 11 | n/a |
List.mergeSort |
n/a | 11.006 s | n/a | n/a | 138 | n/a | n/a | 52.79 GiB | n/a | n/a | 4.91B | n/a | n/a | 1,517 | n/a | n/a | 9 | n/a |
Vector.append |
n/a | 2.414 s | n/a | n/a | 228 | n/a | n/a | 52.43 GiB | n/a | n/a | 1.10B | n/a | n/a | 550 | n/a | n/a | 3 | n/a |
Nat.gcd_comm |
n/a | 1.660 s | n/a | n/a | 249 | n/a | n/a | 52.09 GiB | n/a | n/a | 743.01M | n/a | n/a | 413 | n/a | n/a | 2 | n/a |
String.append |
n/a | 819.6 ms | n/a | n/a | 410 | n/a | n/a | 55.34 GiB | n/a | n/a | 360.85M | n/a | n/a | 336 | n/a | n/a | 1 | n/a |
Int.gcd |
n/a | 553.3 ms | n/a | n/a | 410 | n/a | n/a | 55.19 GiB | n/a | n/a | 245.40M | n/a | n/a | 227 | n/a | n/a | 1 | n/a |
Nat.sub_le_of_le_add |
n/a | 493.2 ms | n/a | n/a | 381 | n/a | n/a | 55.16 GiB | n/a | n/a | 222.50M | n/a | n/a | 188 | n/a | n/a | 1 | n/a |
Nat.add_comm |
n/a | 115.2 ms | n/a | n/a | 425 | n/a | n/a | 55.23 GiB | n/a | n/a | 31.53M | n/a | n/a | 49 | n/a | n/a | 1 | n/a |
13 constants · 0 with regressions · 0 with improvements (|Δ| > 3.0% on any metric).
a77f444 to
64bc041
Compare
|
!benchmark zisk ooc |
|
| env/constant | check-time (main) | check-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|
InitStd |
9.460 s | 16.967 s | +79.4% (1.79× slower) |
9.41K | 5.25K | -44.2% (1.79× slower) |
1.82 GiB | 1.98 GiB | +8.9% (1.09× larger) |
Std.Tactic.BVDecide.BVExpr.bitblast.goCache_Inv_of_Inv._mutual |
6.383 s | 4.643 s | -27.3% (1.37× faster) 🟢 | 887.650 | 1.22K | +37.5% (1.37× faster) 🟢 | 2.04 GiB | 1.81 GiB | -11.2% (1.13× smaller) 🟢 |
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
528.4 ms | 531.8 ms | +0.6% | 5.10K | 5.07K | -0.6% | 1.20 GiB | 1.16 GiB | -2.8% |
Array.extract_append |
1.016 s | 517.6 ms | -49.1% (1.96× faster) 🟢 | 1.52K | 2.99K | +96.4% (1.96× faster) 🟢 | 1.19 GiB | 1.48 GiB | +24.0% (1.24× larger) |
Vector.extract_append._proof_2 |
1.012 s | 512.6 ms | -49.3% (1.97× faster) 🟢 | 1.29K | 2.55K | +97.4% (1.97× faster) 🟢 | 1.52 GiB | 1.44 GiB | -5.2% (1.05× smaller) 🟢 |
Char.ofOrdinal_le_of_le |
773.1 ms | 276.6 ms | -64.2% (2.79× faster) 🟢 | 3.44K | 9.61K | +179.5% (2.79× faster) 🟢 | 1.12 GiB | 1.55 GiB | +38.6% (1.39× larger) |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
764.1 ms | 265.5 ms | -65.3% (2.88× faster) 🟢 | 2.38K | 6.85K | +187.8% (2.88× faster) 🟢 | 1.46 GiB | 1.55 GiB | +5.9% (1.06× larger) |
String.split |
263.7 ms | 264.9 ms | +0.4% | 6.72K | 6.69K | -0.4% | 1.30 GiB | 1.24 GiB | -4.8% (1.05× smaller) 🟢 |
List.mergeSort |
261.0 ms | 262.0 ms | +0.4% | 5.57K | 5.55K | -0.4% | 1.02 GiB | 1003.31 MiB | -3.6% 🟢 |
Vector.append |
255.6 ms | 255.4 ms | -0.1% | 1.95K | 1.95K | +0.1% | 885.11 MiB | 930.82 MiB | +5.2% (1.05× larger) |
Nat.gcd_comm |
253.8 ms | 254.3 ms | +0.2% | 1.54K | 1.53K | -0.2% | 885.11 MiB | 930.82 MiB | +5.2% (1.05× larger) |
String.append |
253.0 ms | 253.1 ms | +0.0% | 1.21K | 1.21K | -0.0% | 1.10 GiB | 1.19 GiB | +7.8% (1.08× larger) |
Int.gcd |
252.6 ms | 252.7 ms | +0.0% | 823.410 | 823.130 | -0.0% | 720.55 MiB | 724.12 MiB | +0.5% |
Nat.sub_le_of_le_add |
252.6 ms | 252.6 ms | +0.0% | 673.090 | 673.040 | -0.0% | 628.77 MiB | 609.14 MiB | -3.1% 🟢 |
Nat.add_comm |
252.0 ms | 252.1 ms | +0.0% | 166.660 | 166.630 | -0.0% | 490.19 MiB | 456.57 MiB | -6.9% (1.07× smaller) 🟢 |
15 env/constants · 7 with regressions · 9 with improvements (|Δ| > 3.0% on any metric).
zisk · InitStd — main from: base run @ 6e29ac9 (not on bencher)
| constant | execute-time (main) | execute-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% | cycles (main) | cycles (PR) | Δ% | constants (main) | constants (PR) | Δ% | shards (main) | shards (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
n/a | 41.586 s | n/a | n/a | 67 | n/a | n/a | 53.77 GiB | n/a | n/a | 18.69B | n/a | n/a | 2,785 | n/a | n/a | 33 | n/a |
Char.ofOrdinal_le_of_le |
n/a | 28.665 s | n/a | n/a | 97 | n/a | n/a | 53.59 GiB | n/a | n/a | 12.95B | n/a | n/a | 2,776 | n/a | n/a | 22 | n/a |
Array.extract_append |
n/a | 28.108 s | n/a | n/a | 58 | n/a | n/a | 70.63 GiB | n/a | n/a | 12.48B | n/a | n/a | 1,627 | n/a | n/a | 13 | n/a |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
n/a | 16.340 s | n/a | n/a | 116 | n/a | n/a | 53.00 GiB | n/a | n/a | 7.35B | n/a | n/a | 1,896 | n/a | n/a | 13 | n/a |
Vector.extract_append._proof_2 |
n/a | 15.866 s | n/a | n/a | 86 | n/a | n/a | 70.61 GiB | n/a | n/a | 7.03B | n/a | n/a | 1,367 | n/a | n/a | 8 | n/a |
String.split |
n/a | 14.243 s | n/a | n/a | 131 | n/a | n/a | 53.04 GiB | n/a | n/a | 6.42B | n/a | n/a | 1,867 | n/a | n/a | 11 | n/a |
List.mergeSort |
n/a | 10.813 s | n/a | n/a | 140 | n/a | n/a | 52.79 GiB | n/a | n/a | 4.91B | n/a | n/a | 1,517 | n/a | n/a | 9 | n/a |
Vector.append |
n/a | 2.397 s | n/a | n/a | 229 | n/a | n/a | 52.42 GiB | n/a | n/a | 1.10B | n/a | n/a | 550 | n/a | n/a | 3 | n/a |
Nat.gcd_comm |
n/a | 1.643 s | n/a | n/a | 251 | n/a | n/a | 52.08 GiB | n/a | n/a | 743.01M | n/a | n/a | 413 | n/a | n/a | 2 | n/a |
String.append |
n/a | 801.3 ms | n/a | n/a | 419 | n/a | n/a | 55.35 GiB | n/a | n/a | 360.85M | n/a | n/a | 336 | n/a | n/a | 1 | n/a |
Int.gcd |
n/a | 534.9 ms | n/a | n/a | 424 | n/a | n/a | 55.18 GiB | n/a | n/a | 245.40M | n/a | n/a | 227 | n/a | n/a | 1 | n/a |
Nat.sub_le_of_le_add |
n/a | 495.4 ms | n/a | n/a | 379 | n/a | n/a | 55.18 GiB | n/a | n/a | 222.50M | n/a | n/a | 188 | n/a | n/a | 1 | n/a |
Nat.add_comm |
n/a | 104.5 ms | n/a | n/a | 469 | n/a | n/a | 55.23 GiB | n/a | n/a | 31.53M | n/a | n/a | 49 | n/a | n/a | 1 | n/a |
13 constants · 0 with regressions · 0 with improvements (|Δ| > 3.0% on any metric).
Rebase of the sb/kernel-perf kernel stack onto main (the early workspace/backend/sharding commits of this branch were superseded by their evolved forms merged in #411/#503; this carries only the novel kernel work, reconciled with main's #473 declared-flag removal and is_rec_cache): - intern-assigned uids replace per-node blake3 content hashing: KExpr/ KUniv identity is a never-reused process-global u64; InternTable keys on shallow structural keys (variant tag + child uids + payload); cache keys cannot alias across intern-table clears (a stale key can only miss). ~20% of guest cycles on reduction-heavy constants came from content hashing (app_hash 22-33% cumulative). Design + collision analysis in docs/kernel_identity.md. - adversarial hardening of the uid design: fresh_uid aborts on counter exhaustion; literal structural-equality arms compare values as well as blob addresses; uid-accepting constructors privatized so a caller-supplied uid can never enter a node. - environment-machine WHNF (design in docs/env_machine_whnf.md): Phase A — whnf_core's App arm enters a Krivine-style machine when a beta fires; beta/zeta are O(1) environment pushes and substitution materializes only at machine exits (clo_subst readback), so a beta chain ending in another beta never materializes intermediate bodies. Phase B — closure-iota at the machine's recursor exit: only the major premise materializes on the main ctor-rule path; the rule RHS re-enters the machine with original closures, so unselected minors (dropped match/Decidable branches, the UTF-8 codec class) are never substituted and never read back. - memoized prim-family dispatch in the WHNF/def-eq reduction loops: classify each head once per iteration via an allocation-free app-chain walk + per-address memo (KEnv::prim_family_cache) instead of probing all five primitive recognizers per iteration. - compact symbolic Nat offsets: Nat.add base (Lit n) / Nat.div/mod base (Lit k) stay stuck in compact form (each keeps its own head, so offset def-eq cannot equate /- and +-derived forms); linear-rec collapse; offset-aware def-eq. - H-15 whnf probe pre-filter (allocation-free spine_head_and_len before the transient-nat probes) and H-12 output-size caps on native Nat arithmetic. - suffix-aware CtxAddr keys for the is_prop / nat_succ_stuck caches; NatSuccMode::Stuck whnf cache (proves ByteArray.utf8DecodeChar?_utf8EncodeChar_append). - ixon: per-constant address verification deferred to first materialization (LazyConstant::get checks pending_addr): constants shipped in a closure but never forced by the typechecker are never hashed; everything the kernel certifies is still verified when it is forced. Guest cycles: rbmap -9.5%, natgcdcomm -6.4%, stringappend -4.2%.
Standalone cargo examples over a .ixe env, bypassing the Lean/FFI layer, updated to main's steps-based shard cost model (block_step_cost / partition_for_cycle_cap / cycle_cap_for_ram): - shard_plan: profile → partition → .ixes manifest, with store-aware planning (--store-dir drops work items whose targets the proof store already covers, and excludes covered blocks from the partition hypergraph — a novel→covered edge is an assumption discharged at aggregation, not a cut to minimize); sizes N from machine RAM by default. - perf_check / check_one: native rerun of the guest check_const loop so IX_* perf-counter instrumentation can target a single expensive constant without re-checking its env. - heaviest_block / block_reduce_histo / shard_names / manifest_info: profiling forensics over blocks and manifests.
- zisk/scripts: prove-batch (sequential shard proving), mem-guard (MemAvailable watchdog that kills zisk-host before the OOM killer wedges the box), bench-cycles, mergesort-250k repro; reference logs. - sp1/scripts/prove-ix.sh + GPU logs (dev-only; runs with WITHOUT_VK_VERIFICATION=1). - Lean side: bench-compile-init lake exe (imports Init, empty main).
…pinning) The aggregate proof was weaker than "these subjects are well-typed": - The agg guest never read a child's committed failures word (slot 10) and hard-committed 0 for its own, so aggregation ERASED the failure bit — a kernel-rejected constant could appear under a failures=0 root, with only host-side courtesy checks in the way. Every child's failures word is now asserted 0 in-circuit. - vk pinning was not transitive: a child that is itself an aggregate was pinned only by its program vk (the shared AGG vk); its own allowed-vk set was never inspected. An agg-of-1 built against a rogue allowed set (wrapping an arbitrary program's "proof" with forged publics) would fold under an honest-looking root. The agg guest now requires every aggregate child (allowed-set index ≥ 1, by the new positional convention: index 0 = leaf vk, the rest agg vks) to commit THIS instance's vks id — the allowed set is uniform down the tree, so the pin is recursive. The convention's ordering is bound by the committed id hash, which external verifiers already check. - The host derived the allowed set FROM the untrusted child proofs (distinct_vks), so any proof admitted its own program, and a stale store folded silently under its old vk. The allowed set is now [shard_vk, agg_vk] derived from the embedded ELFs (GuestProgram::vk after ROM setup); freshly produced proofs are asserted to match; stored proofs with a different vk are skipped (re-proven); and the root's committed vks id is checked against — and printed for — external verifiers. - A manifest bisection tree whose leaf set differs from the shard id set silently dropped proven leaves from the fold while the pre-aggregation coverage check (counting proofs PRODUCED, not folded) still passed. ShardManifest::from_bytes now rejects such trees, and the host additionally checks post-fold that every env target is in the root's actual subject set.
64bc041 to
d392646
Compare
|
!benchmark zisk |
|
| constant | execute-time (main) | execute-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% | cycles (main) | cycles (PR) | Δ% | constants (main) | constants (PR) | Δ% | shards (main) | shards (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
1m 5.7s | 42.029 s | -36.0% (1.56× faster) 🟢 | 42 | 66 | +57.1% (1.57× faster) 🟢 | 70.51 GiB | 53.59 GiB | -24.0% (1.32× smaller) 🟢 | 33.86B | 18.67B | -44.8% (1.81× fewer) 🟢 | 2,785 | 2,785 | +0.0% | 34 | 33 | -2.9% |
Array.extract_append |
48.360 s | 29.011 s | -40.0% (1.67× faster) 🟢 | 34 | 56 | +64.7% (1.65× faster) 🟢 | 113.14 GiB | 70.54 GiB | -37.7% (1.60× smaller) 🟢 | 23.88B | 12.48B | -47.7% (1.91× fewer) 🟢 | 1,627 | 1,627 | +0.0% | 13 | 13 | +0.0% |
Char.ofOrdinal_le_of_le |
52.117 s | 28.884 s | -44.6% (1.80× faster) 🟢 | 53 | 96 | +81.1% (1.81× faster) 🟢 | 82.84 GiB | 53.47 GiB | -35.5% (1.55× smaller) 🟢 | 26.70B | 12.94B | -51.5% (2.06× fewer) 🟢 | 2,776 | 2,776 | +0.0% | 26 | 22 | -15.4% (1.18× fewer) 🟢 |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
34.894 s | 16.539 s | -52.6% (2.11× faster) 🟢 | 54 | 115 | +113.0% (2.13× faster) 🟢 | 99.26 GiB | 53.05 GiB | -46.6% (1.87× smaller) 🟢 | 17.71B | 7.35B | -58.5% (2.41× fewer) 🟢 | 1,896 | 1,896 | +0.0% | 15 | 13 | -13.3% (1.15× fewer) 🟢 |
Vector.extract_append._proof_2 |
27.931 s | 16.276 s | -41.7% (1.72× faster) 🟢 | 49 | 84 | +71.4% (1.71× faster) 🟢 | 113.07 GiB | 70.58 GiB | -37.6% (1.60× smaller) 🟢 | 13.62B | 7.03B | -48.4% (1.94× fewer) 🟢 | 1,367 | 1,367 | +0.0% | 8 | 8 | +0.0% |
String.split |
19.746 s | 14.465 s | -26.7% (1.37× faster) 🟢 | 95 | 129 | +35.8% (1.36× faster) 🟢 | 52.92 GiB | 53.04 GiB | +0.2% | 10.37B | 6.42B | -38.0% (1.61× fewer) 🟢 | 1,867 | 1,867 | +0.0% | 11 | 11 | +0.0% |
List.mergeSort |
15.633 s | 11.043 s | -29.4% (1.42× faster) 🟢 | 97 | 137 | +41.2% (1.41× faster) 🟢 | 52.78 GiB | 52.82 GiB | +0.1% | 8.19B | 4.91B | -40.1% (1.67× fewer) 🟢 | 1,517 | 1,517 | +0.0% | 9 | 9 | +0.0% |
Vector.append |
3.287 s | 2.432 s | -26.0% (1.35× faster) 🟢 | 167 | 226 | +35.3% (1.35× faster) 🟢 | 52.42 GiB | 52.43 GiB | +0.0% | 1.75B | 1.10B | -37.2% (1.59× fewer) 🟢 | 550 | 550 | +0.0% | 3 | 3 | +0.0% |
Nat.gcd_comm |
2.326 s | 1.698 s | -27.0% (1.37× faster) 🟢 | 178 | 243 | +36.5% (1.37× faster) 🟢 | 52.14 GiB | 52.09 GiB | -0.1% | 1.21B | 743.05M | -38.6% (1.63× fewer) 🟢 | 413 | 413 | +0.0% | 2 | 2 | +0.0% |
String.append |
1.142 s | 866.6 ms | -24.1% (1.32× faster) 🟢 | 294 | 388 | +32.0% (1.32× faster) 🟢 | 55.36 GiB | 55.35 GiB | -0.0% | 586.26M | 360.87M | -38.4% (1.62× fewer) 🟢 | 336 | 336 | +0.0% | 1 | 1 | +0.0% |
Int.gcd |
800.8 ms | 557.5 ms | -30.4% (1.44× faster) 🟢 | 283 | 407 | +43.8% (1.44× faster) 🟢 | 55.23 GiB | 55.19 GiB | -0.1% | 403.39M | 245.42M | -39.2% (1.64× fewer) 🟢 | 227 | 227 | +0.0% | 1 | 1 | +0.0% |
Nat.sub_le_of_le_add |
713.1 ms | 512.0 ms | -28.2% (1.39× faster) 🟢 | 264 | 367 | +39.0% (1.39× faster) 🟢 | 55.20 GiB | 55.17 GiB | -0.1% | 368.19M | 222.51M | -39.6% (1.65× fewer) 🟢 | 188 | 188 | +0.0% | 1 | 1 | +0.0% |
Nat.add_comm |
140.0 ms | 111.5 ms | -20.4% (1.26× faster) 🟢 | 350 | 439 | +25.4% (1.25× faster) 🟢 | 55.21 GiB | 55.22 GiB | +0.0% | 52.60M | 31.54M | -40.0% (1.67× fewer) 🟢 | 49 | 49 | +0.0% | 1 | 1 | +0.0% |
13 constants · 0 with regressions · 13 with improvements (|Δ| > 3.0% on any metric).
A 128+signal death was always recorded as an OOM row, so a zisk mem-planner segfault (exit 139) rendered as OOM and sent the investigation chasing RAM budgets instead of a heap-overflow bug. Split the kill statuses: explicit kills (137 KILL, 143 TERM) and allocator aborts (134) stay oom; any other signal death records status crash and renders as 💥 CRASH in the compare table.
The profiler counted whnf entries, def-eq entries, and limb-weighted Nat arithmetic per constant but dropped them at block aggregation, and nothing counted term-construction volume at all — leaving the shard cost model only heartbeats, subst, and bytes to predict guest steps from. Persist all four op counters per block (format v2) plus a new intern-table visit counter (a proxy for construction/memory traffic, bumped in intern_expr/intern_univ), and add a shard_features example that emits a per-shard feature CSV from a profile + manifest pair for calibrating the cost model against externally measured shard costs (ziskemu -X on dumped shard inputs).
--dump-input wrote only the first selected shard and exited, so dumping a 13-shard plan took 13 host invocations. Dump every selected shard in one run (multi-shard plans write <stem>-s<manifest index><ext>; --only-shard keeps the exact path), and skip client.setup when no proof store is involved — dump mode never runs the VM and needs the ROM setup (and thus the proving key) only to derive the shard vk for store filtering.
Replace the heartbeat-based guest-STEP model with one denominated in
ziskemu cost units (-X TOTAL: MAIN + OPCODES + MEMORY + PRECOMPILES +
BASE), so the packing target prices the axes that don't ride the main
trace — DMA/blake3 precompile area and memory ops. Calibration corpus:
118 InitStd shards across 13 constants, each measured with ziskemu -X on
inputs dumped via --dump-input.
cost = 293.6M + 196.6k*subst + 1.798M*whnf + 567.1k*def_eq
+ 28.4k*intern (+ 73.2k per cross-ingress byte)
MAPE 10.9%, worst under-prediction -33% (the profiler runs cold-cache per
work item, so intra-shard cache sharing is invisible to per-block
features); COST_MODEL_HEADROOM = 1.5 covers it inside cycle_cap_for_ram.
On this corpus cost/step is ~92.5 +/- 7% — blake3 is 0.6-2.4% of cost on
the uid-identity kernel; the intern term carries the memory-traffic/DMA
axis (residual correlation 0.91 with dma_memcpy counts).
Prover models refit on the same corpus. RAM comes from a guarded GPU
prove sweep measured as each prover's systemd-scope cgroup memory.peak —
the OOM-relevant metric CI's watchdog enforces, charging the whole
process tree plus the ASM trace shm (a VmRSS-summed sweep reads 2-8 GiB
low with the gap growing with cost): peak RAM 33.1 + 0.2845 GiB/B-cost
(was 50 + 33 per B-step), leaf prove time 29s + 2.25s/B-cost (419s
measured vs 411s predicted at the largest point).
Validation at --max-ram 108: the corpus re-plans 118 -> 55 shards
(instRxcHasSize_eq 13 -> 6), every packable shard's measured cost within
the actual-cost ceiling; the only violations are the two
INFEASIBLE-flagged atomic monster blocks (~310 B-cost = ~121 GiB
single-leaf), correctly flagged as not fitting the budget.
A whole-env ooc regression previously surfaced as one env-keyed number,
with drill-down only into the pre-chosen bench vectors. Now the anon
whole-env check attributes itself: check-rs --per-const <csv> records one
entry per work item (wall nanos, heartbeats, the op counters, and the
predicted Zisk cost via the shard model) from the check loop, and the CLI
joins Lean names from the env's named table (projection-name fallback for
anonymized Muts blocks) so entries survive PRs that shift content
addresses. An entry is ONE constant's (or Muts block's) own check — deps
are lazily ingressed and trusted, each checked in its own entry, with the
consulted closure slice's ingress charged to the entry — so entries sum
to the env total with no double counting. NOT the full-closure scope of
--consts measurements; documented at the recording site, the flag help,
the renderer, and in the rendered output.
The ooc bench cell writes the CSV as a <rows>.perconst.csv file next to
the results file (rotated with the local baseline), and ix bench compare
renders a drill-down when both sides carry one, split by evidence
quality — calibrated on a Mathlib A/A run (640K constants, twice through
one binary): wall time swings up to 2.8s from scheduling alone, while
the op counters drift only on a 0.7% tail (up to ~13% relative / 0.27e9
absolute; worker->item assignment varies uid blocks and uid-keyed hash
iteration order perturbs a few order-sensitive paths; --workers 1 is
exactly reproducible). Cost movers (|Dcost| >= 15% of the constant's own
cost OR >= 1e9 outright, both above the drift envelope) lead the
drill-down ranked by percent change, styled like the main table
('+95.5% (1.96x more)', warning/green emoji); cost-flat time movers are
quarantined in a labeled noise section capped at 5 rows. On the A/A run
this renders 0 cost movers, the truthful reading.
A multi-cell !benchmark comment stacked every cell's full table; long cells (a 40-constant zisk table) buried the verdicts. Each cell now leads with its one-line verdict (and any typecheck failures / empty-side warnings, which stay unconditionally visible), and the comparison table collapses into a <details> block when it has more than 5 rows — small cells (the ooc env row, few-constant runs) stay inline. The per-constant and phase drill-downs were already collapsible.
bencher.dev stores metric rows only, so the per-constant drill-down needs the attribution CSVs to travel beside the results files. bench-main caches the ooc cell's CSV by (SHA, cell) after its run; bench-pr restores the base SHA's entry, carries a base-run-produced CSV through the merge step (which previously renamed base.json into main.json and orphaned it), and pairs whichever CSV it has with the PR side's. The main side ends up with exactly two sources: bencher on FULL coverage (plus, for ooc, a cached attribution CSV), or a full local base-SHA rerun for anything less — base SHA not uploaded, partial coverage, an ooc attribution cache miss, or the fresh token. A rerun measures the full default selection (a BENCH_CONSTS override still narrows it) and its rows take priority; bencher-fetched rows only fill rows the rerun failed to produce, and the table's main-source label says which path ran. This retires the gap-filling machinery (--consts from missing.txt, the bencher-priority merge arm) — a full rerun is simpler and self-consistent, at the cost of re-measuring a cell when a PR adds constants.
Current zisk toolchains (1.0.0-alpha builds from 2026-07 on) embed the riscv64ima-zisk-zkvm-elf linker script in the target spec again, and passing the vendored copy on top double-defines the rom/ram memory regions. Both guest build scripts existed only to pass it — remove them and the script; the toolchain's embedded script is the single source of the memory layout.
Bump every zisk fork pin from blake3-precompile (e4057c4) to blake3-precompile-1.0.0-alpha (f376d85d), whose one commit on top grows the mem-planner offsets array before fill_padding pads the last page — the heap overflow behind the WAIT_PLAN_MEM_CPP hang + SIGSEGV that the bench recorded as instRxcHasSize_eq's phantom OOM. Validated here: the shard that crashed 4/4 on the old pin executes clean on the new one (634M cycles, failures=0), as does the full 13-shard plan on the locally-patched build the fix was developed against.
67f422a to
6c2f4a5
Compare
u32::try_from over as-truncation and u64::from over as-widening in shard_features; drop redundant std::sync:: qualifications; carry the PoisonError text instead of discarding it; collapse the texray if into a let-chain; contains() over iter().any() in the holed-work filter.
cargo clippy in the sp1 workspace failed on a clean checkout: sp1-build deliberately skips the guest compilation under clippy, but include_elf! still demanded the ELF bytes. Gate the embed (and its import) on cfg(not(clippy)) with an empty Elf::Static stand-in — nothing executes under clippy. Also collapse the texray if into a let-chain, matching the zisk host. A real release build of the host still works.
The root rust-test clippy never enters the standalone zkVM workspaces, so their warnings accumulated ungated. Add cargo clippy --release --all-targets -D warnings to both host jobs, after the build so the release dep artifacts are shared (and, for zisk, the guest ELFs its build scripts already produced).
ab47b56 to
4696435
Compare
Base-SHA compare runs mix the PR's orchestrator with the base's tools and toolchain, and the base at 7ff054b predates two of this branch's changes — droppable wholesale after the first green benchmark whose base includes this branch: - Re-pin the CI zisk toolchain to the zisk-1.0.0 artifact: the base's guests pass -T zisk.ld unconditionally, which only links against the non-embedding toolchain (the latest artifact embeds the script and double-defines the rom/ram regions — the base zisk run died there, n/a-ing the whole main side). Restore the vendored zisk.ld and the probing build.rs on the PR side so its guests build against either artifact. - Probe check-rs --help before passing --per-const: the base's check-rs dies on the unknown flag, which killed the whole-env ooc row (the n/a InitStd/Mathlib main rows).
|
!benchmark ooc fresh |
|
!benchmark ooc fresh BENCH_ENVS=Mathlib |
|
!benchmark zisk fresh |
⏳ Benchmark running…
Benchmarking |
⏳ Benchmark running…
Benchmarking |
This pull request implements Rust-kernel and ixon optimizations for the Zisk guest, measured against the base #411 as deterministic guest cycle counts (
ziskemu -m) over dumped shard inputs (zisk/scripts/bench-cycles.sh), with every counted run's committedfailurespublics word verified zero.Key Results
Int16.instRxcHasSize_eq: 5.70 B → 42.0 M guest steps (135.6×);Int32/Int64variants confirmed at the same magnitude (~42 M) — in-circuit cost is now integer-width-independentVector.extract_append._proof_1−32.4%; the Init Array/VectorExtractproof family −22% to −33% each (five multi-billion-step constants)Std.Tactic.BVDecide.BVExpr.bitblast.goCache_Inv_of_Inv._mutual(28.35 B steps, the most expensive constant measured in Init+Std): previously crashed the 512 MB guest (OOM-class null read) → now completes as a valid kernel pass — lazy closures cut peak RAM, not just cyclesdocs/kernel_identity.md), blob bytes verified at load in all deserializersFifteen Commits (oldest first)
bench: guest cycle harness + native single-constant check
bench-cycles.shsuite over dumped guest stdins with failures-word validation;check_oneexample mirrors the guest's reuse-mode check nativelykernel: keep symbolic Nat offsets compact (whnf stuck + offset def-eq)
Nat.add x lit/Nat.div|mod x kstay stuck as compact offsets instead of materializingsucc^n(x)chains or the division algorithm; bulk offset def-eq decides offset pairs directlyInt16.instRxcHasSize_eqcollapse (5.70 B → 56 M) and the UTF-8-codec-class fixkernel: intern-assigned uids replace per-node blake3 content hashing
kernel: memoized prim-family dispatch in the WHNF/def-eq reduction loops
ixon: defer per-constant address verification to first materialization
get(); blob bytes still verified eagerly at loadbench: add Int32/Int64 instRxcHasSize_eq to the cycle suite
docs: kernel uid identity vs Ixon content addressing
kernel: fix PrimFamily visibility/qualification warnings
kernel: port jcb/fixes H-15 whnf probe pre-filter + H-12 nat output caps
kernel+ixon: harden term identity against adversarial inputs
kernel: privatize uid-accepting constructors; document cross-shard uid story
docs: design for the environment-machine WHNF port
kernel: environment-machine WHNF (Phase A — lazy substitution on the beta path)
whnf_core's App arm enters a closure machine when a beta fires: beta/zeta are O(1) environment pushes; substitution materializes only at machine exits (clo_substreadback), so work is proportional to what the reduction consumeskernel: closure-iota at the machine's recursor exit (Phase B)
Decidablebranches) are never substituted and never read backdocs: env-machine WHNF design is implemented (Phases A+B)