From e0eb5f04a5551d4b2b82546f0c8d1ca0a10f8c64 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Mon, 13 Apr 2026 11:04:45 -0300 Subject: [PATCH 01/15] Add per-phase timing profile script across program sizes --- scripts/bench_timing_profile.sh | 237 ++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100755 scripts/bench_timing_profile.sh diff --git a/scripts/bench_timing_profile.sh b/scripts/bench_timing_profile.sh new file mode 100755 index 000000000..671118662 --- /dev/null +++ b/scripts/bench_timing_profile.sh @@ -0,0 +1,237 @@ +#!/bin/bash +# Per-phase timing profile across program sizes. +# Shows how each proving phase and sub-operation scales with program size. +# +# Usage: bench_timing_profile.sh [--no-build] [--programs "1M 2M 4M 8M"] +# +# Requires: instruments feature. +# Timing is deterministic with instruments, so 1 run per size is enough. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +TMP_DIR="/tmp/bench_timing_profile" +ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm" + +GREEN='\033[0;32m' +BOLD='\033[1m' +NC='\033[0m' + +BUILD=true +PROGRAMS="500k 1M 2M 4M" + +while [[ $# -gt 0 ]]; do + case $1 in + --no-build) BUILD=false; shift ;; + --programs) PROGRAMS="$2"; shift 2 ;; + *) echo "Unknown arg: $1"; exit 1 ;; + esac +done + +suffix_to_steps() { + case $1 in + 160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;; + 500k) echo 500000 ;; 1M) echo 1000000 ;; 1200k) echo 1200000 ;; + 2M) echo 2000000 ;; 4M) echo 4000000 ;; 8M) echo 8000000 ;; + 16M) echo 16000000 ;; 32M) echo 32000000 ;; 64M) echo 64000000 ;; 128M) echo 128000000 ;; + *) echo "Unknown: $1" >&2; exit 1 ;; + esac +} + +rm -rf "$TMP_DIR" && mkdir -p "$TMP_DIR" + +if $BUILD; then + echo -e "${GREEN}Building CLI with instruments...${NC}" + cargo build --release -p cli --features instruments \ + --manifest-path "$ROOT_DIR/Cargo.toml" 2>&1 | tail -1 +fi +CLI="$ROOT_DIR/target/release/cli" + +# Parse instruments stderr into key=value pairs. +# Uses occurrence counting to disambiguate expand_pool_to_lde and commit (Merkle). +parse_timing() { + awk ' + BEGIN { lde_n = 0; merkle_n = 0 } + function secs( s) { + if (match($0, /[0-9]+\.[0-9]+s/)) { + s = substr($0, RSTART, RLENGTH - 1) + return s + } + return "" + } + /^ Execute / { v = secs(); if (v) print "execute=" v } + /^ Trace build/ { v = secs(); if (v) print "trace_build=" v } + /^ AIR construction/ { v = secs(); if (v) print "air=" v } + /^ Pre-pass/ { v = secs(); if (v) print "prepass=" v } + /^ Round 1 / { v = secs(); if (v) print "round1=" v } + /Main trace commits/ { v = secs(); if (v) print "main_commits=" v } + /Aux trace build/ { v = secs(); if (v) print "aux_build=" v } + /Aux trace commit/ { v = secs(); if (v) print "aux_commit=" v } + /Rounds 2/ { v = secs(); if (v) print "rounds24=" v } + /expand_pool_to_lde/ && !/R1 expand/ { + lde_n++; v = secs() + if (v && lde_n == 1) print "main_lde=" v + if (v && lde_n == 2) print "aux_lde=" v + } + /commit \(Merkle\)/ { + merkle_n++; v = secs() + if (v && merkle_n == 1) print "main_merkle=" v + if (v && merkle_n == 2) print "aux_merkle=" v + } + /R1 expand_pool_to_lde/ { v = secs(); if (v) print "r1_lde=" v } + /R2 evaluate/ { v = secs(); if (v) print "r2_evaluate=" v } + /R2 decompose/ { v = secs(); if (v) print "r2_decompose=" v } + /R2 commit_comp/ { v = secs(); if (v) print "r2_commit_comp=" v } + /R3 OOD/ { v = secs(); if (v) print "r3_ood=" v } + /R4 deep_comp/ { v = secs(); if (v) print "r4_deep_comp=" v } + /R4 interpolate/ { v = secs(); if (v) print "r4_interp=" v } + /R4 fri::commit/ { v = secs(); if (v) print "r4_fri_commit=" v } + /R4 queries/ { v = secs(); if (v) print "r4_queries=" v } + /^ Total FFT/ { v = secs(); if (v) print "total_fft=" v } + /^ Total Merkle/ { v = secs(); if (v) print "total_merkle=" v } + /^ TOTAL / { v = secs(); if (v) print "total=" v } + ' "$1" +} + +for size in $PROGRAMS; do + ELF="$ELF_DIR/fib_iterative_${size}.elf" + [ -f "$ELF" ] || { echo "Missing: $ELF"; continue; } + steps=$(suffix_to_steps "$size") + echo -e "${GREEN}Running fib_iterative_${size}...${NC}" + + STDERR="$TMP_DIR/${size}_stderr.txt" + "$CLI" prove "$ELF" -o "$TMP_DIR/proof.bin" 2>"$STDERR" >/dev/null + rm -f "$TMP_DIR/proof.bin" + + echo "steps=$steps" > "$TMP_DIR/${size}_data.txt" + parse_timing "$STDERR" >> "$TMP_DIR/${size}_data.txt" +done + +# --- Display --------------------------------------------------------------- + +get_val() { + grep "^${2}=" "$1" 2>/dev/null | cut -d= -f2 +} + +print_section() { + local title=$1; shift + + echo "" + echo -e " ${BOLD}${title}${NC}" + printf " %-30s" "" + for size in $PROGRAMS; do printf " %9s" "$size"; done + echo "" + printf " %-30s" "" + for size in $PROGRAMS; do printf " %9s" "─────────"; done + echo "" + + for spec in "$@"; do + local label="${spec%%:*}" + local key="${spec#*:}" + printf " %-30s" "$label" + for size in $PROGRAMS; do + local DATA="$TMP_DIR/${size}_data.txt" + local val + val=$(get_val "$DATA" "$key") + if [ -n "$val" ]; then + printf " %8.2fs" "$val" + else + printf " %9s" "-" + fi + done + echo "" + done +} + +echo "" +echo -e "${BOLD}=== TIMING PROFILE ACROSS SIZES ===${NC}" + +TABLE_K="${TABLE_PARALLELISM:-default (cores/3)}" +echo -e " TABLE_PARALLELISM=$TABLE_K" + +print_section "Phase (wall time)" \ + "TOTAL:total" \ + "Execute:execute" \ + "Trace build:trace_build" \ + "AIR construction:air" \ + "Pre-pass:prepass" \ + "Round 1:round1" \ + "Rounds 2-4:rounds24" + +print_section "Round 1 breakdown (CPU sum)" \ + "Main LDE:main_lde" \ + "Main Merkle:main_merkle" \ + "Aux build (wall):aux_build" \ + "Aux LDE:aux_lde" \ + "Aux Merkle:aux_merkle" + +print_section "Rounds 2-4 sub-ops (CPU sum)" \ + "R1 LDE (reconstruct):r1_lde" \ + "R2 decompose+extend:r2_decompose" \ + "R2 evaluate:r2_evaluate" \ + "R2 commit comp poly:r2_commit_comp" \ + "R3 OOD evaluation:r3_ood" \ + "R4 deep comp evals:r4_deep_comp" \ + "R4 interpolate+evaluate:r4_interp" \ + "R4 FRI commit:r4_fri_commit" \ + "R4 queries & openings:r4_queries" + +print_section "Cross-round totals (CPU sum)" \ + "Total FFT:total_fft" \ + "Total Merkle:total_merkle" + +# --- Growth rate ----------------------------------------------------------- + +echo "" +echo -e "${BOLD}=== GROWTH RATE (per 1M steps) ===${NC}" +echo "" + +for spec in \ + "TOTAL:total" \ + "Trace build:trace_build" \ + "Round 1:round1" \ + "Rounds 2-4:rounds24" \ + "Main LDE:main_lde" \ + "Aux LDE:aux_lde" \ + "R1 LDE (reconstruct):r1_lde" \ + "R2 decompose+extend:r2_decompose" \ + "R3 OOD evaluation:r3_ood" \ + "Total FFT:total_fft" \ + "Total Merkle:total_merkle" +do + label="${spec%%:*}" + key="${spec#*:}" + + PAIRS="" + for size in $PROGRAMS; do + DATA="$TMP_DIR/${size}_data.txt" + [ -f "$DATA" ] || continue + steps=$(get_val "$DATA" "steps") + val=$(get_val "$DATA" "$key") + [ -z "$val" ] && continue + steps_m=$(awk "BEGIN {printf \"%.2f\", $steps / 1000000}") + PAIRS="$PAIRS $steps_m $val" + done + + echo "$PAIRS" | awk -v label="$label" '{ + n = NF / 2 + if (n < 2) { printf " %-30s (insufficient data)\n", label; next } + for (i = 0; i < n; i++) { + x[i] = $(2*i+1); y[i] = $(2*i+2) + } + sx=0; sy=0; sxx=0; sxy=0 + for (i=0;i0) ? 1 - ss_res/ss_tot : 1 + printf " %-30s %+.2fs/M steps (base: %.2fs, R\xc2\xb2=%.3f)\n", label, b, a, r2 + }' +done + +echo "" +echo "Raw data in $TMP_DIR/" From d8f95f3022283c6cf7046d93f5e508a0039da295 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Mon, 13 Apr 2026 19:04:03 -0300 Subject: [PATCH 02/15] Convert bench programs to std and add env var scaling --- .../bench/bitwise_ops/.cargo/config.toml | 4 +- .../programs/bench/bitwise_ops/Cargo.lock | 324 ++++++++++++++++++ .../programs/bench/bitwise_ops/Cargo.toml | 1 + .../programs/bench/bitwise_ops/src/main.rs | 32 +- executor/programs/bench/keccak/src/main.rs | 17 +- .../bench/matrix_multiply/.cargo/config.toml | 4 +- .../programs/bench/matrix_multiply/Cargo.lock | 324 ++++++++++++++++++ .../programs/bench/matrix_multiply/Cargo.toml | 1 + .../bench/matrix_multiply/src/main.rs | 36 +- .../bench/modular_exp/.cargo/config.toml | 4 +- .../programs/bench/modular_exp/Cargo.lock | 324 ++++++++++++++++++ .../programs/bench/modular_exp/Cargo.toml | 1 + .../programs/bench/modular_exp/src/main.rs | 38 +- 13 files changed, 1056 insertions(+), 54 deletions(-) diff --git a/executor/programs/bench/bitwise_ops/.cargo/config.toml b/executor/programs/bench/bitwise_ops/.cargo/config.toml index debd9f441..ca99a3f45 100644 --- a/executor/programs/bench/bitwise_ops/.cargo/config.toml +++ b/executor/programs/bench/bitwise_ops/.cargo/config.toml @@ -1,5 +1,5 @@ [target.riscv64im-lambda-vm-elf] rustflags = [ - "-C", "link-arg=-e", - "-C", "link-arg=main" + "--cfg", "getrandom_backend=\"custom\"", + "-C", "passes=lower-atomic" ] diff --git a/executor/programs/bench/bitwise_ops/Cargo.lock b/executor/programs/bench/bitwise_ops/Cargo.lock index 5a0b821ed..b295da50b 100644 --- a/executor/programs/bench/bitwise_ops/Cargo.lock +++ b/executor/programs/bench/bitwise_ops/Cargo.lock @@ -2,6 +2,330 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "bitwise_ops" version = "0.1.0" +dependencies = [ + "lambda-vm-syscalls", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "lambda-vm-syscalls" +version = "0.1.0" +dependencies = [ + "embedded-alloc", + "getrandom 0.2.17", + "getrandom 0.3.4", + "lazy_static", + "rand", + "riscv", + "thiserror", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "riscv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05cfa3f7b30c84536a9025150d44d26b8e1cc20ddf436448d74cd9591eefb25" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d323d13972c1b104aa036bc692cd08b822c8bbf23d79a27c526095856499799" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "rlsf" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1646a59a9734b8b7a0ac51689388a60fe1625d4b956348e9de07591a1478457a" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "rustversion", + "svgbobdoc", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] diff --git a/executor/programs/bench/bitwise_ops/Cargo.toml b/executor/programs/bench/bitwise_ops/Cargo.toml index 0063e8ef0..671c062d9 100644 --- a/executor/programs/bench/bitwise_ops/Cargo.toml +++ b/executor/programs/bench/bitwise_ops/Cargo.toml @@ -6,3 +6,4 @@ version = "0.1.0" edition = "2024" [dependencies] +lambda-vm-syscalls = { path = "../../../../syscalls" } diff --git a/executor/programs/bench/bitwise_ops/src/main.rs b/executor/programs/bench/bitwise_ops/src/main.rs index c22e16fe6..622d59b8e 100644 --- a/executor/programs/bench/bitwise_ops/src/main.rs +++ b/executor/programs/bench/bitwise_ops/src/main.rs @@ -1,14 +1,21 @@ -#![no_std] -#![no_main] +use lambda_vm_syscalls as syscalls; -use core::panic::PanicInfo; - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -const ITERATIONS: usize = 286000; +const ITERATIONS: usize = { + const fn parse(s: &str) -> usize { + let b = s.as_bytes(); + let mut r = 0; + let mut i = 0; + while i < b.len() { + r = r * 10 + (b[i] - b'0') as usize; + i += 1; + } + r + } + match option_env!("ITERATIONS") { + Some(s) => parse(s), + None => 286000, + } +}; #[inline(never)] fn bitwise_mix(a: u32, b: u32) -> u32 { @@ -18,8 +25,7 @@ fn bitwise_mix(a: u32, b: u32) -> u32 { x.wrapping_add(y).wrapping_add(z) } -#[unsafe(no_mangle)] -pub fn main() -> u32 { +pub fn main() { let mut result = 0x12345678u32; let mut i = 0; @@ -30,5 +36,5 @@ pub fn main() -> u32 { i += 1; } - result + syscalls::syscalls::commit(&result.to_le_bytes()); } diff --git a/executor/programs/bench/keccak/src/main.rs b/executor/programs/bench/keccak/src/main.rs index 7b180a469..e497eb0e5 100644 --- a/executor/programs/bench/keccak/src/main.rs +++ b/executor/programs/bench/keccak/src/main.rs @@ -1,7 +1,22 @@ use lambda_vm_syscalls as syscalls; use tiny_keccak::Hasher; -const ITERATIONS: usize = 1000; +const ITERATIONS: usize = { + const fn parse(s: &str) -> usize { + let b = s.as_bytes(); + let mut r = 0; + let mut i = 0; + while i < b.len() { + r = r * 10 + (b[i] - b'0') as usize; + i += 1; + } + r + } + match option_env!("ITERATIONS") { + Some(s) => parse(s), + None => 1000, + } +}; pub fn main() { let mut output = [0u8; 32]; diff --git a/executor/programs/bench/matrix_multiply/.cargo/config.toml b/executor/programs/bench/matrix_multiply/.cargo/config.toml index debd9f441..ca99a3f45 100644 --- a/executor/programs/bench/matrix_multiply/.cargo/config.toml +++ b/executor/programs/bench/matrix_multiply/.cargo/config.toml @@ -1,5 +1,5 @@ [target.riscv64im-lambda-vm-elf] rustflags = [ - "-C", "link-arg=-e", - "-C", "link-arg=main" + "--cfg", "getrandom_backend=\"custom\"", + "-C", "passes=lower-atomic" ] diff --git a/executor/programs/bench/matrix_multiply/Cargo.lock b/executor/programs/bench/matrix_multiply/Cargo.lock index acb0bf52c..c8d6627db 100644 --- a/executor/programs/bench/matrix_multiply/Cargo.lock +++ b/executor/programs/bench/matrix_multiply/Cargo.lock @@ -2,6 +2,330 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "lambda-vm-syscalls" +version = "0.1.0" +dependencies = [ + "embedded-alloc", + "getrandom 0.2.17", + "getrandom 0.3.4", + "lazy_static", + "rand", + "riscv", + "thiserror", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + [[package]] name = "matrix_multiply" version = "0.1.0" +dependencies = [ + "lambda-vm-syscalls", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "riscv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05cfa3f7b30c84536a9025150d44d26b8e1cc20ddf436448d74cd9591eefb25" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d323d13972c1b104aa036bc692cd08b822c8bbf23d79a27c526095856499799" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "rlsf" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1646a59a9734b8b7a0ac51689388a60fe1625d4b956348e9de07591a1478457a" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "rustversion", + "svgbobdoc", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] diff --git a/executor/programs/bench/matrix_multiply/Cargo.toml b/executor/programs/bench/matrix_multiply/Cargo.toml index a44fff4da..ca898e450 100644 --- a/executor/programs/bench/matrix_multiply/Cargo.toml +++ b/executor/programs/bench/matrix_multiply/Cargo.toml @@ -6,3 +6,4 @@ version = "0.1.0" edition = "2024" [dependencies] +lambda-vm-syscalls = { path = "../../../../syscalls" } diff --git a/executor/programs/bench/matrix_multiply/src/main.rs b/executor/programs/bench/matrix_multiply/src/main.rs index b3309e0a9..b6e50ebcb 100644 --- a/executor/programs/bench/matrix_multiply/src/main.rs +++ b/executor/programs/bench/matrix_multiply/src/main.rs @@ -1,14 +1,21 @@ -#![no_std] -#![no_main] +use lambda_vm_syscalls as syscalls; -use core::panic::PanicInfo; - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -const SIZE: usize = 81; +const SIZE: usize = { + const fn parse(s: &str) -> usize { + let b = s.as_bytes(); + let mut r = 0; + let mut i = 0; + while i < b.len() { + r = r * 10 + (b[i] - b'0') as usize; + i += 1; + } + r + } + match option_env!("SIZE") { + Some(s) => parse(s), + None => 81, + } +}; #[inline(never)] fn matrix_multiply(a: &[[u32; SIZE]; SIZE], b: &[[u32; SIZE]; SIZE], result: &mut [[u32; SIZE]; SIZE]) { @@ -44,25 +51,20 @@ fn init_matrix(m: &mut [[u32; SIZE]; SIZE], seed: u32) { } } -#[unsafe(no_mangle)] -pub fn main() -> u32 { +pub fn main() { let mut a = [[0u32; SIZE]; SIZE]; let mut b = [[0u32; SIZE]; SIZE]; let mut result = [[0u32; SIZE]; SIZE]; - // Initialize matrices with pseudo-random values init_matrix(&mut a, 12345); init_matrix(&mut b, 67890); - - // Perform matrix multiplication matrix_multiply(&a, &b, &mut result); - // Return checksum: sum of diagonal elements let mut checksum = 0u32; let mut i = 0; while i < SIZE { checksum = checksum.wrapping_add(result[i][i]); i += 1; } - checksum + syscalls::syscalls::commit(&checksum.to_le_bytes()); } diff --git a/executor/programs/bench/modular_exp/.cargo/config.toml b/executor/programs/bench/modular_exp/.cargo/config.toml index debd9f441..ca99a3f45 100644 --- a/executor/programs/bench/modular_exp/.cargo/config.toml +++ b/executor/programs/bench/modular_exp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.riscv64im-lambda-vm-elf] rustflags = [ - "-C", "link-arg=-e", - "-C", "link-arg=main" + "--cfg", "getrandom_backend=\"custom\"", + "-C", "passes=lower-atomic" ] diff --git a/executor/programs/bench/modular_exp/Cargo.lock b/executor/programs/bench/modular_exp/Cargo.lock index e3da22ca0..623d222cd 100644 --- a/executor/programs/bench/modular_exp/Cargo.lock +++ b/executor/programs/bench/modular_exp/Cargo.lock @@ -2,6 +2,330 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "lambda-vm-syscalls" +version = "0.1.0" +dependencies = [ + "embedded-alloc", + "getrandom 0.2.17", + "getrandom 0.3.4", + "lazy_static", + "rand", + "riscv", + "thiserror", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + [[package]] name = "modular_exp" version = "0.1.0" +dependencies = [ + "lambda-vm-syscalls", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "riscv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05cfa3f7b30c84536a9025150d44d26b8e1cc20ddf436448d74cd9591eefb25" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d323d13972c1b104aa036bc692cd08b822c8bbf23d79a27c526095856499799" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "rlsf" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1646a59a9734b8b7a0ac51689388a60fe1625d4b956348e9de07591a1478457a" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "rustversion", + "svgbobdoc", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] diff --git a/executor/programs/bench/modular_exp/Cargo.toml b/executor/programs/bench/modular_exp/Cargo.toml index c4a7fb705..250a81e45 100644 --- a/executor/programs/bench/modular_exp/Cargo.toml +++ b/executor/programs/bench/modular_exp/Cargo.toml @@ -6,3 +6,4 @@ version = "0.1.0" edition = "2024" [dependencies] +lambda-vm-syscalls = { path = "../../../../syscalls" } diff --git a/executor/programs/bench/modular_exp/src/main.rs b/executor/programs/bench/modular_exp/src/main.rs index 0fd0fe8cc..6af21968e 100644 --- a/executor/programs/bench/modular_exp/src/main.rs +++ b/executor/programs/bench/modular_exp/src/main.rs @@ -1,14 +1,21 @@ -#![no_std] -#![no_main] - -use core::panic::PanicInfo; - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -const NUM_ITERATIONS: usize = 20600; +use lambda_vm_syscalls as syscalls; + +const NUM_ITERATIONS: usize = { + const fn parse(s: &str) -> usize { + let b = s.as_bytes(); + let mut r = 0; + let mut i = 0; + while i < b.len() { + r = r * 10 + (b[i] - b'0') as usize; + i += 1; + } + r + } + match option_env!("NUM_ITERATIONS") { + Some(s) => parse(s), + None => 20600, + } +}; #[inline(never)] fn mod_exp(base: u32, exp: u32, modulus: u32) -> u32 { @@ -32,27 +39,24 @@ fn mod_exp(base: u32, exp: u32, modulus: u32) -> u32 { result as u32 } -#[unsafe(no_mangle)] -pub fn main() -> u32 { +pub fn main() { let mut checksum = 0u32; let mut base = 2u32; let mut exp = 1000u32; - let mut modulus = 1000000007u32; // Large prime + let mut modulus = 1000000007u32; let mut i = 0; while i < NUM_ITERATIONS { let result = mod_exp(base, exp, modulus); checksum = checksum.wrapping_add(result); - // Vary the parameters for each iteration base = base.wrapping_mul(3).wrapping_add(1) % 1000; if base == 0 { base = 2; } exp = exp.wrapping_add(7) % 10000; if exp == 0 { exp = 1; } - // Keep modulus as large prime for meaningful computation i += 1; } - checksum + syscalls::syscalls::commit(&checksum.to_le_bytes()); } From f9fa8ac445ce61e620f71111c45210db35ce95f6 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Mon, 13 Apr 2026 19:04:16 -0300 Subject: [PATCH 03/15] Add script to build bench programs at different sizes --- scripts/build_bench_sizes.sh | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 scripts/build_bench_sizes.sh diff --git a/scripts/build_bench_sizes.sh b/scripts/build_bench_sizes.sh new file mode 100755 index 000000000..203d25f76 --- /dev/null +++ b/scripts/build_bench_sizes.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Build a bench program at multiple sizes via env var. +# Places ELFs in executor/program_artifacts/bench/ with size suffix. +# +# Usage: build_bench_sizes.sh +# Example: build_bench_sizes.sh modular_exp NUM_ITERATIONS 5000 10000 20000 + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +BENCH_DIR="$ROOT_DIR/executor/programs/bench" +ARTIFACTS_DIR="$ROOT_DIR/executor/program_artifacts/bench" +TARGET_SPEC="$ROOT_DIR/executor/programs/riscv64im-lambda-vm-elf.json" +SHARED_TARGET_DIR="$ROOT_DIR/executor/programs/target" + +program=$1; shift +env_var=$1; shift + +if [ ! -d "$BENCH_DIR/$program" ]; then + echo "Error: $BENCH_DIR/$program not found" >&2 + exit 1 +fi + +mkdir -p "$ARTIFACTS_DIR" + +for val in "$@"; do + echo "Building ${program} with ${env_var}=${val}..." + + cd "$BENCH_DIR/$program" + env CARGO_TARGET_DIR="$SHARED_TARGET_DIR" "${env_var}=${val}" \ + rustup run nightly-2026-02-01 cargo build --release \ + --target "$TARGET_SPEC" \ + -Z build-std=core,alloc,std,compiler_builtins,panic_abort \ + -Z build-std-features=compiler-builtins-mem \ + -Z json-target-spec 2>&1 | tail -1 + + cp "$SHARED_TARGET_DIR/riscv64im-lambda-vm-elf/release/$program" \ + "$ARTIFACTS_DIR/${program}_${val}.elf" + + echo " -> ${program}_${val}.elf" +done + +echo "Done." From f84e785f1baca98dd71e1471421d91ee4481cc16 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Mon, 13 Apr 2026 19:09:53 -0300 Subject: [PATCH 04/15] Add --program flag to timing and heap profile scripts --- scripts/bench_heap_profile.sh | 32 +++++++++++++++++++++++++------- scripts/bench_timing_profile.sh | 28 +++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/scripts/bench_heap_profile.sh b/scripts/bench_heap_profile.sh index d3add6782..abde5991b 100755 --- a/scripts/bench_heap_profile.sh +++ b/scripts/bench_heap_profile.sh @@ -2,7 +2,11 @@ # Per-phase heap profile across program sizes. # Shows where heap grows and how each phase scales with program size. # -# Usage: bench_heap_profile.sh [--no-build] [--programs "500k 1M 2M 4M"] +# Usage: bench_heap_profile.sh [--no-build] [--programs "500k 1M 2M 4M"] [--program fib_iterative] +# +# --program: which program to profile (default: fib_iterative) +# fib_iterative: uses asm/ ELFs, sizes like 500k/1M/2M +# modular_exp, bitwise_ops, matrix_multiply, keccak: uses bench/ ELFs, sizes are iteration counts # # Requires: instruments + jemalloc-stats features. # Peak heap is deterministic, so 1 run per size is enough. @@ -19,23 +23,37 @@ BOLD='\033[1m' NC='\033[0m' BUILD=true -PROGRAMS="500k 1M 2M 4M" +PROGRAM="fib_iterative" +PROGRAMS="" while [[ $# -gt 0 ]]; do case $1 in --no-build) BUILD=false; shift ;; + --program) PROGRAM="$2"; shift 2 ;; --programs) PROGRAMS="$2"; shift 2 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done +# Set defaults and ELF directory based on program +if [ "$PROGRAM" = "fib_iterative" ]; then + ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm" + [ -z "$PROGRAMS" ] && PROGRAMS="500k 1M 2M 4M" +else + ELF_DIR="$ROOT_DIR/executor/program_artifacts/bench" + if [ -z "$PROGRAMS" ]; then + echo "Error: --programs required for bench programs" >&2 + exit 1 + fi +fi + suffix_to_steps() { case $1 in 160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;; 500k) echo 500000 ;; 1M) echo 1000000 ;; 1200k) echo 1200000 ;; 2M) echo 2000000 ;; 4M) echo 4000000 ;; 8M) echo 8000000 ;; 16M) echo 16000000 ;; 32M) echo 32000000 ;; 64M) echo 64000000 ;; 128M) echo 128000000 ;; - *) echo "Unknown: $1" >&2; exit 1 ;; + *) echo "$1" ;; # bench programs: size is the iteration count esac } @@ -52,10 +70,10 @@ CLI="$ROOT_DIR/target/release/cli" PHASES="execute trace_build air pool_alloc main_commits aux_build aux_commit" for size in $PROGRAMS; do - ELF="$ELF_DIR/fib_iterative_${size}.elf" + ELF="$ELF_DIR/${PROGRAM}_${size}.elf" [ -f "$ELF" ] || { echo "Missing: $ELF"; continue; } steps=$(suffix_to_steps "$size") - echo -e "${GREEN}Running fib_iterative_${size}...${NC}" + echo -e "${GREEN}Running ${PROGRAM}_${size}...${NC}" STDERR="$TMP_DIR/${size}_stderr.txt" STDOUT="$TMP_DIR/${size}_stdout.txt" @@ -220,7 +238,7 @@ for size in $PROGRAMS; do PEAK_PAIRS="$PEAK_PAIRS $steps_m $peak" done -echo "$PEAK_PAIRS" | awk '{ +echo "$PEAK_PAIRS" | awk -v prog="$PROGRAM" '{ n = NF / 2 if (n < 2) { print " (insufficient data)"; next } for (i = 0; i < n; i++) { x[i] = $(2*i+1); y[i] = $(2*i+2) } @@ -242,7 +260,7 @@ echo "$PEAK_PAIRS" | awk '{ if (abs >= 1000000) lbl = sprintf("%gM", abs / 1000000) else if (abs >= 1000) lbl = sprintf("%gk", abs / 1000) else lbl = sprintf("%g", abs) - printf " fib_iterative_%-6s ~%.0f MB (~%.0f GB)\n", lbl, pred, pred/1024 + printf " %-20s ~%.0f MB (~%.0f GB)\n", prog "_" lbl, pred, pred/1024 } }' diff --git a/scripts/bench_timing_profile.sh b/scripts/bench_timing_profile.sh index 671118662..67f1e5278 100755 --- a/scripts/bench_timing_profile.sh +++ b/scripts/bench_timing_profile.sh @@ -2,7 +2,11 @@ # Per-phase timing profile across program sizes. # Shows how each proving phase and sub-operation scales with program size. # -# Usage: bench_timing_profile.sh [--no-build] [--programs "1M 2M 4M 8M"] +# Usage: bench_timing_profile.sh [--no-build] [--programs "1M 2M 4M 8M"] [--program fib_iterative] +# +# --program: which program to profile (default: fib_iterative) +# fib_iterative: uses asm/ ELFs, sizes like 500k/1M/2M +# modular_exp, bitwise_ops, matrix_multiply, keccak: uses bench/ ELFs, sizes are iteration counts # # Requires: instruments feature. # Timing is deterministic with instruments, so 1 run per size is enough. @@ -19,23 +23,37 @@ BOLD='\033[1m' NC='\033[0m' BUILD=true -PROGRAMS="500k 1M 2M 4M" +PROGRAM="fib_iterative" +PROGRAMS="" while [[ $# -gt 0 ]]; do case $1 in --no-build) BUILD=false; shift ;; + --program) PROGRAM="$2"; shift 2 ;; --programs) PROGRAMS="$2"; shift 2 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done +# Set defaults and ELF directory based on program +if [ "$PROGRAM" = "fib_iterative" ]; then + ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm" + [ -z "$PROGRAMS" ] && PROGRAMS="500k 1M 2M 4M" +else + ELF_DIR="$ROOT_DIR/executor/program_artifacts/bench" + if [ -z "$PROGRAMS" ]; then + echo "Error: --programs required for bench programs" >&2 + exit 1 + fi +fi + suffix_to_steps() { case $1 in 160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;; 500k) echo 500000 ;; 1M) echo 1000000 ;; 1200k) echo 1200000 ;; 2M) echo 2000000 ;; 4M) echo 4000000 ;; 8M) echo 8000000 ;; 16M) echo 16000000 ;; 32M) echo 32000000 ;; 64M) echo 64000000 ;; 128M) echo 128000000 ;; - *) echo "Unknown: $1" >&2; exit 1 ;; + *) echo "$1" ;; # bench programs: size is the iteration count esac } @@ -95,10 +113,10 @@ parse_timing() { } for size in $PROGRAMS; do - ELF="$ELF_DIR/fib_iterative_${size}.elf" + ELF="$ELF_DIR/${PROGRAM}_${size}.elf" [ -f "$ELF" ] || { echo "Missing: $ELF"; continue; } steps=$(suffix_to_steps "$size") - echo -e "${GREEN}Running fib_iterative_${size}...${NC}" + echo -e "${GREEN}Running ${PROGRAM}_${size}...${NC}" STDERR="$TMP_DIR/${size}_stderr.txt" "$CLI" prove "$ELF" -o "$TMP_DIR/proof.bin" 2>"$STDERR" >/dev/null From c68cffa60fd3fa8c6d99909ce720acc5f7cdf429 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 13:48:01 -0300 Subject: [PATCH 05/15] Bump regression precision for small iteration counts --- scripts/bench_timing_profile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bench_timing_profile.sh b/scripts/bench_timing_profile.sh index 67f1e5278..83f4cecd0 100755 --- a/scripts/bench_timing_profile.sh +++ b/scripts/bench_timing_profile.sh @@ -228,7 +228,7 @@ do steps=$(get_val "$DATA" "steps") val=$(get_val "$DATA" "$key") [ -z "$val" ] && continue - steps_m=$(awk "BEGIN {printf \"%.2f\", $steps / 1000000}") + steps_m=$(awk "BEGIN {printf \"%.6f\", $steps / 1000000}") PAIRS="$PAIRS $steps_m $val" done From bcbd0b279c3388a94872b49249cf4362fad48df3 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 14:37:51 -0300 Subject: [PATCH 06/15] Add profile_all script with per-program output subdirs --- scripts/bench_heap_profile.sh | 2 ++ scripts/bench_timing_profile.sh | 2 ++ scripts/profile_all.sh | 49 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100755 scripts/profile_all.sh diff --git a/scripts/bench_heap_profile.sh b/scripts/bench_heap_profile.sh index abde5991b..561b46ca3 100755 --- a/scripts/bench_heap_profile.sh +++ b/scripts/bench_heap_profile.sh @@ -47,6 +47,8 @@ else fi fi +TMP_DIR="$TMP_DIR/$PROGRAM" + suffix_to_steps() { case $1 in 160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;; diff --git a/scripts/bench_timing_profile.sh b/scripts/bench_timing_profile.sh index 83f4cecd0..0e84e4ab2 100755 --- a/scripts/bench_timing_profile.sh +++ b/scripts/bench_timing_profile.sh @@ -47,6 +47,8 @@ else fi fi +TMP_DIR="$TMP_DIR/$PROGRAM" + suffix_to_steps() { case $1 in 160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;; diff --git a/scripts/profile_all.sh b/scripts/profile_all.sh new file mode 100755 index 000000000..78eff2562 --- /dev/null +++ b/scripts/profile_all.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Run heap and timing profiles on all prepared bench programs. +# Output: +# /tmp/bench_heap_profile// +# /tmp/bench_timing_profile// + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# program env_var sizes +# env_var="-" means fib_iterative (prebuilt ELFs, no build step) +CONFIGS=( + "fib_iterative - 500k 1M 2M" + "keccak ITERATIONS 200 500 1000" + "modular_exp NUM_ITERATIONS 5000 10000 20000 40000" + "bitwise_ops ITERATIONS 50000 100000 200000 400000" + "matrix_multiply SIZE 20 40 60 80" +) + +GREEN='\033[0;32m' +NC='\033[0m' + +echo -e "${GREEN}Building CLI with jemalloc-stats + instruments...${NC}" +cargo build --release -p cli --features jemalloc-stats,instruments \ + --manifest-path "$ROOT_DIR/Cargo.toml" 2>&1 | tail -1 + +for config in "${CONFIGS[@]}"; do + read -r prog env_var sizes <<< "$config" + + echo "" + echo -e "${GREEN}=== $prog ===${NC}" + + if [ "$env_var" != "-" ]; then + bash "$SCRIPT_DIR/build_bench_sizes.sh" "$prog" "$env_var" $sizes + fi + + bash "$SCRIPT_DIR/bench_heap_profile.sh" --no-build \ + --program "$prog" --programs "$sizes" + + bash "$SCRIPT_DIR/bench_timing_profile.sh" --no-build \ + --program "$prog" --programs "$sizes" +done + +echo "" +echo "Results:" +echo " Heap: /tmp/bench_heap_profile//" +echo " Timing: /tmp/bench_timing_profile//" From f46188e6e26a6d677d1a6ef9e7561bdcb5d37c88 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 14:39:42 -0300 Subject: [PATCH 07/15] Add --no-heap and --no-timing flags to profile_all --- scripts/profile_all.sh | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/scripts/profile_all.sh b/scripts/profile_all.sh index 78eff2562..03ab90f22 100755 --- a/scripts/profile_all.sh +++ b/scripts/profile_all.sh @@ -3,12 +3,24 @@ # Output: # /tmp/bench_heap_profile// # /tmp/bench_timing_profile// +# +# Flags: --no-heap, --no-timing to skip either profile type. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +HEAP=true +TIMING=true +while [[ $# -gt 0 ]]; do + case $1 in + --no-heap) HEAP=false; shift ;; + --no-timing) TIMING=false; shift ;; + *) echo "Unknown arg: $1"; exit 1 ;; + esac +done + # program env_var sizes # env_var="-" means fib_iterative (prebuilt ELFs, no build step) CONFIGS=( @@ -22,8 +34,11 @@ CONFIGS=( GREEN='\033[0;32m' NC='\033[0m' -echo -e "${GREEN}Building CLI with jemalloc-stats + instruments...${NC}" -cargo build --release -p cli --features jemalloc-stats,instruments \ +FEATURES="instruments" +$HEAP && FEATURES="jemalloc-stats,instruments" + +echo -e "${GREEN}Building CLI with $FEATURES...${NC}" +cargo build --release -p cli --features "$FEATURES" \ --manifest-path "$ROOT_DIR/Cargo.toml" 2>&1 | tail -1 for config in "${CONFIGS[@]}"; do @@ -36,14 +51,18 @@ for config in "${CONFIGS[@]}"; do bash "$SCRIPT_DIR/build_bench_sizes.sh" "$prog" "$env_var" $sizes fi - bash "$SCRIPT_DIR/bench_heap_profile.sh" --no-build \ - --program "$prog" --programs "$sizes" + if $HEAP; then + bash "$SCRIPT_DIR/bench_heap_profile.sh" --no-build \ + --program "$prog" --programs "$sizes" + fi - bash "$SCRIPT_DIR/bench_timing_profile.sh" --no-build \ - --program "$prog" --programs "$sizes" + if $TIMING; then + bash "$SCRIPT_DIR/bench_timing_profile.sh" --no-build \ + --program "$prog" --programs "$sizes" + fi done echo "" echo "Results:" -echo " Heap: /tmp/bench_heap_profile//" -echo " Timing: /tmp/bench_timing_profile//" +$HEAP && echo " Heap: /tmp/bench_heap_profile//" +$TIMING && echo " Timing: /tmp/bench_timing_profile//" From 6bf41afded3a8dde275f9ac890e6b48bec10c243 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 14:40:36 -0300 Subject: [PATCH 08/15] Rename profile_all to profile_suite --- scripts/{profile_all.sh => profile_suite.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/{profile_all.sh => profile_suite.sh} (100%) diff --git a/scripts/profile_all.sh b/scripts/profile_suite.sh similarity index 100% rename from scripts/profile_all.sh rename to scripts/profile_suite.sh From 805db547f02151181fdb95539ee3defa845e29da Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 14:43:46 -0300 Subject: [PATCH 09/15] Add --program flag to profile_suite for single-program runs --- scripts/profile_suite.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/profile_suite.sh b/scripts/profile_suite.sh index 03ab90f22..399cd2072 100755 --- a/scripts/profile_suite.sh +++ b/scripts/profile_suite.sh @@ -4,7 +4,9 @@ # /tmp/bench_heap_profile// # /tmp/bench_timing_profile// # -# Flags: --no-heap, --no-timing to skip either profile type. +# Flags: +# --no-heap, --no-timing skip either profile type +# --program run only the given program (default: all) set -euo pipefail @@ -13,10 +15,12 @@ ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" HEAP=true TIMING=true +ONLY="" while [[ $# -gt 0 ]]; do case $1 in --no-heap) HEAP=false; shift ;; --no-timing) TIMING=false; shift ;; + --program) ONLY="$2"; shift 2 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done @@ -31,6 +35,19 @@ CONFIGS=( "matrix_multiply SIZE 20 40 60 80" ) +if [ -n "$ONLY" ]; then + filtered=() + for config in "${CONFIGS[@]}"; do + read -r prog _ <<< "$config" + [ "$prog" = "$ONLY" ] && filtered+=("$config") + done + if [ ${#filtered[@]} -eq 0 ]; then + echo "Error: unknown program '$ONLY'" >&2 + exit 1 + fi + CONFIGS=("${filtered[@]}") +fi + GREEN='\033[0;32m' NC='\033[0m' From 7b4318b4510ee26337d003984bf381250b24a84f Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Tue, 14 Apr 2026 15:05:18 -0300 Subject: [PATCH 10/15] Wipe tmp dirs in profile_suite to drop stale results --- scripts/profile_suite.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/profile_suite.sh b/scripts/profile_suite.sh index 399cd2072..728805ed4 100755 --- a/scripts/profile_suite.sh +++ b/scripts/profile_suite.sh @@ -54,6 +54,10 @@ NC='\033[0m' FEATURES="instruments" $HEAP && FEATURES="jemalloc-stats,instruments" +# Clear stale results so only the current run's data remains. +$HEAP && rm -rf /tmp/bench_heap_profile +$TIMING && rm -rf /tmp/bench_timing_profile + echo -e "${GREEN}Building CLI with $FEATURES...${NC}" cargo build --release -p cli --features "$FEATURES" \ --manifest-path "$ROOT_DIR/Cargo.toml" 2>&1 | tail -1 From 79f619c0c92227abfcc8ee005c6766ba20196420 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Wed, 15 Apr 2026 16:40:29 -0300 Subject: [PATCH 11/15] Reject unknown --program in profile scripts --- scripts/bench_heap_profile.sh | 5 +++++ scripts/bench_timing_profile.sh | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/scripts/bench_heap_profile.sh b/scripts/bench_heap_profile.sh index 561b46ca3..09e22d030 100755 --- a/scripts/bench_heap_profile.sh +++ b/scripts/bench_heap_profile.sh @@ -35,6 +35,11 @@ while [[ $# -gt 0 ]]; do esac done +case $PROGRAM in + fib_iterative|keccak|modular_exp|bitwise_ops|matrix_multiply) ;; + *) echo "Error: unknown --program '$PROGRAM'" >&2; exit 1 ;; +esac + # Set defaults and ELF directory based on program if [ "$PROGRAM" = "fib_iterative" ]; then ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm" diff --git a/scripts/bench_timing_profile.sh b/scripts/bench_timing_profile.sh index 0e84e4ab2..f767bc979 100755 --- a/scripts/bench_timing_profile.sh +++ b/scripts/bench_timing_profile.sh @@ -35,6 +35,11 @@ while [[ $# -gt 0 ]]; do esac done +case $PROGRAM in + fib_iterative|keccak|modular_exp|bitwise_ops|matrix_multiply) ;; + *) echo "Error: unknown --program '$PROGRAM'" >&2; exit 1 ;; +esac + # Set defaults and ELF directory based on program if [ "$PROGRAM" = "fib_iterative" ]; then ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm" From 08552da5f7963025c13a54d47c5d43f1c28db7c8 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Wed, 15 Apr 2026 16:40:29 -0300 Subject: [PATCH 12/15] Assert digit range in bench program const parse --- executor/programs/bench/bitwise_ops/src/main.rs | 1 + executor/programs/bench/keccak/src/main.rs | 1 + executor/programs/bench/modular_exp/src/main.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/executor/programs/bench/bitwise_ops/src/main.rs b/executor/programs/bench/bitwise_ops/src/main.rs index 622d59b8e..1bf0112ab 100644 --- a/executor/programs/bench/bitwise_ops/src/main.rs +++ b/executor/programs/bench/bitwise_ops/src/main.rs @@ -6,6 +6,7 @@ const ITERATIONS: usize = { let mut r = 0; let mut i = 0; while i < b.len() { + assert!(b[i] >= b'0' && b[i] <= b'9'); r = r * 10 + (b[i] - b'0') as usize; i += 1; } diff --git a/executor/programs/bench/keccak/src/main.rs b/executor/programs/bench/keccak/src/main.rs index e497eb0e5..71f2bad7f 100644 --- a/executor/programs/bench/keccak/src/main.rs +++ b/executor/programs/bench/keccak/src/main.rs @@ -7,6 +7,7 @@ const ITERATIONS: usize = { let mut r = 0; let mut i = 0; while i < b.len() { + assert!(b[i] >= b'0' && b[i] <= b'9'); r = r * 10 + (b[i] - b'0') as usize; i += 1; } diff --git a/executor/programs/bench/modular_exp/src/main.rs b/executor/programs/bench/modular_exp/src/main.rs index 6af21968e..e0057db05 100644 --- a/executor/programs/bench/modular_exp/src/main.rs +++ b/executor/programs/bench/modular_exp/src/main.rs @@ -6,6 +6,7 @@ const NUM_ITERATIONS: usize = { let mut r = 0; let mut i = 0; while i < b.len() { + assert!(b[i] >= b'0' && b[i] <= b'9'); r = r * 10 + (b[i] - b'0') as usize; i += 1; } From 1f019e168120b528a4b65572914b56d02ae71682 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Wed, 15 Apr 2026 16:40:29 -0300 Subject: [PATCH 13/15] Add stack overflow note and digit assert in matrix_multiply --- executor/programs/bench/matrix_multiply/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/executor/programs/bench/matrix_multiply/src/main.rs b/executor/programs/bench/matrix_multiply/src/main.rs index b6e50ebcb..7bc528b66 100644 --- a/executor/programs/bench/matrix_multiply/src/main.rs +++ b/executor/programs/bench/matrix_multiply/src/main.rs @@ -1,11 +1,14 @@ use lambda_vm_syscalls as syscalls; +// Three SIZE×SIZE u32 matrices live on the stack (~12·SIZE² bytes). +// SIZE ≲ 150 is safe; beyond that, expect stack overflow. const SIZE: usize = { const fn parse(s: &str) -> usize { let b = s.as_bytes(); let mut r = 0; let mut i = 0; while i < b.len() { + assert!(b[i] >= b'0' && b[i] <= b'9'); r = r * 10 + (b[i] - b'0') as usize; i += 1; } From 991ed401db2f4973d9597e8c913c6435f999a4ef Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Wed, 15 Apr 2026 17:30:48 -0300 Subject: [PATCH 14/15] Allow profile_suite.sh to take multiple --program flags --- scripts/profile_suite.sh | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/scripts/profile_suite.sh b/scripts/profile_suite.sh index 728805ed4..6b135590c 100755 --- a/scripts/profile_suite.sh +++ b/scripts/profile_suite.sh @@ -6,7 +6,8 @@ # # Flags: # --no-heap, --no-timing skip either profile type -# --program run only the given program (default: all) +# --program run only the given program; repeat to select several +# (default: all programs) set -euo pipefail @@ -15,12 +16,12 @@ ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" HEAP=true TIMING=true -ONLY="" +ONLY_LIST=() while [[ $# -gt 0 ]]; do case $1 in --no-heap) HEAP=false; shift ;; --no-timing) TIMING=false; shift ;; - --program) ONLY="$2"; shift 2 ;; + --program) ONLY_LIST+=("$2"); shift 2 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done @@ -35,16 +36,23 @@ CONFIGS=( "matrix_multiply SIZE 20 40 60 80" ) -if [ -n "$ONLY" ]; then +if [ ${#ONLY_LIST[@]} -gt 0 ]; then filtered=() - for config in "${CONFIGS[@]}"; do - read -r prog _ <<< "$config" - [ "$prog" = "$ONLY" ] && filtered+=("$config") + for only in "${ONLY_LIST[@]}"; do + found=false + for config in "${CONFIGS[@]}"; do + read -r prog _ <<< "$config" + if [ "$prog" = "$only" ]; then + filtered+=("$config") + found=true + break + fi + done + if ! $found; then + echo "Error: unknown program '$only'" >&2 + exit 1 + fi done - if [ ${#filtered[@]} -eq 0 ]; then - echo "Error: unknown program '$ONLY'" >&2 - exit 1 - fi CONFIGS=("${filtered[@]}") fi From b4f64cb74d0a4e0f4d9d13c0156c0e8efd53a70e Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Wed, 15 Apr 2026 17:30:48 -0300 Subject: [PATCH 15/15] Add /bench-suite PR command to run profile suite --- .github/workflows/benchmark-pr.yml | 129 +++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/.github/workflows/benchmark-pr.yml b/.github/workflows/benchmark-pr.yml index 9129a73d4..ed111c592 100644 --- a/.github/workflows/benchmark-pr.yml +++ b/.github/workflows/benchmark-pr.yml @@ -41,12 +41,14 @@ jobs: benchmark: runs-on: [self-hosted, bench] # Skip unless: push to main, workflow_dispatch, or "/bench" comment on a PR + # (but not "/bench-suite", which runs benchmark_suite below) if: >- github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/bench') && + !startsWith(github.event.comment.body, '/bench-suite') && contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association)) steps: - name: React to comment @@ -812,3 +814,130 @@ jobs: body }); } + + benchmark_suite: + runs-on: [self-hosted, bench] + # Triggered by "/bench-suite [prog ...]" PR comments. + # Programs default to the full suite; pass names to restrict. + if: >- + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + startsWith(github.event.comment.body, '/bench-suite') && + contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association) + steps: + - name: React to comment + uses: actions/github-script@v7 + with: + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'eyes' + }); + + - name: Get PR head ref + id: pr-ref + env: + GH_TOKEN: ${{ github.token }} + PR_NUM: ${{ github.event.issue.number }} + run: | + SHA=$(gh pr view "$PR_NUM" --repo "$GITHUB_REPOSITORY" --json headRefOid -q .headRefOid) + echo "sha=$SHA" >> "$GITHUB_OUTPUT" + + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ steps.pr-ref.outputs.sha }} + + - name: Parse program args + id: args + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + FIRST_LINE=$(printf '%s' "$COMMENT_BODY" | head -n 1 | tr -d '\r') + if ! echo "$FIRST_LINE" | grep -qE '^/bench-suite($|[[:space:]])'; then + echo "::error::Invalid command: '$FIRST_LINE'" + exit 1 + fi + REST=$(echo "$FIRST_LINE" | sed -n 's|^/bench-suite[[:space:]]*\(.*\)|\1|p') + FLAGS="" + if [ -n "$REST" ]; then + for p in $REST; do + case "$p" in + fib_iterative|keccak|modular_exp|bitwise_ops|matrix_multiply) + FLAGS="$FLAGS --program $p" + ;; + *) + echo "::error::Unknown program '$p' (allowed: fib_iterative, keccak, modular_exp, bitwise_ops, matrix_multiply)" + exit 1 + ;; + esac + done + fi + echo "flags=$FLAGS" >> "$GITHUB_OUTPUT" + + - name: Add cargo to PATH + run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + + - name: Compile fib_iterative ELFs + run: | + mkdir -p executor/program_artifacts/asm + for size in 500k 1M 2M; do + SRC="executor/programs/asm/fib_iterative_${size}.s" + OUT="executor/program_artifacts/asm/fib_iterative_${size}.elf" + if [ ! -f "$OUT" ] && [ -f "$SRC" ]; then + clang --target=riscv64 -march=rv64im -fuse-ld=lld -nostdlib -Wl,-e,main \ + "$SRC" -o "$OUT" + fi + done + + - name: Run profile suite + env: + FLAGS: ${{ steps.args.outputs.flags }} + run: | + set -o pipefail + bash scripts/profile_suite.sh $FLAGS 2>&1 | tee /tmp/suite_output.txt + + - name: Package artifacts + if: always() + run: | + mkdir -p /tmp/suite_artifact + [ -f /tmp/suite_output.txt ] && cp /tmp/suite_output.txt /tmp/suite_artifact/ + [ -d /tmp/bench_heap_profile ] && cp -r /tmp/bench_heap_profile /tmp/suite_artifact/ + [ -d /tmp/bench_timing_profile ] && cp -r /tmp/bench_timing_profile /tmp/suite_artifact/ + + - name: Upload artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: profile-suite-${{ steps.pr-ref.outputs.sha }} + path: /tmp/suite_artifact/ + retention-days: 30 + + - name: Post PR comment + if: success() + uses: actions/github-script@v7 + env: + ARTIFACT_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + with: + script: | + const fs = require('fs'); + let out = fs.readFileSync('/tmp/suite_output.txt', 'utf8'); + out = out.replace(/\x1b\[[0-9;]*m/g, ''); + const LIMIT = 58000; + const truncated = out.length > LIMIT; + const body = truncated ? out.slice(0, LIMIT) : out; + const artifactUrl = process.env.ARTIFACT_URL; + let comment = `## Profile suite\n\n\`\`\`text\n${body}\n\`\`\`\n`; + if (truncated) { + comment += `\n> Output truncated. Full output in [workflow artifacts](${artifactUrl}).\n`; + } else { + comment += `\nFull artifacts in [workflow run](${artifactUrl}).\n`; + } + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment, + });