Advanced
Execution Only
We recommend that during the development of large programs (> 1 million cycles) you do not generate proofs each time.
Instead, you should have your script only execute the program with the RISC-V runtime and read public_values
. Here is an example:
use sp1_sdk::{include_elf, utils, ProverClient, SP1Stdin};
/// The ELF we want to execute inside the zkVM.
const ELF: &[u8] = include_elf!("fibonacci-program");
fn main() {
// Setup logging.
utils::setup_logger();
// Create an input stream and write '500' to it.
let n = 500u32;
let mut stdin = SP1Stdin::new();
stdin.write(&n);
// Only execute the program and get a `SP1PublicValues` object.
let client = ProverClient::from_env();
let (mut public_values, execution_report) = client.execute(ELF, &stdin).run().unwrap();
// Print the total number of cycles executed and the full execution report with a breakdown of
// the RISC-V opcode and syscall counts.
println!(
"Executed program with {} cycles",
execution_report.total_instruction_count() + execution_report.total_syscall_count()
);
println!("Full execution report:\n{:?}", execution_report);
// Read and verify the output.
let _ = public_values.read::<u32>();
let a = public_values.read::<u32>();
let b = public_values.read::<u32>();
println!("a: {}", a);
println!("b: {}", b);
}
If the execution of your program succeeds, then proof generation should succeed as well! (Unless there is a bug in our zkVM implementation.)
Logging and Tracing Information
You can use utils::setup_logger()
to enable logging information respectively. You should only use one or the other of these functions.
Logging:
utils::setup_logger();
You must run your command with:
RUST_LOG=info cargo run --release
CPU Acceleration
To enable CPU acceleration, you can use the RUSTFLAGS
environment variable to enable the target-cpu=native
flag when running your script. This will enable the compiler to generate code that is optimized for your CPU.
RUSTFLAGS='-C target-cpu=native' cargo run --release
Currently there is support for AVX512 and NEON SIMD instructions. For NEON, you must also enable the sp1-sdk
feature neon
in your script crate's Cargo.toml
file.
sp1-sdk = { version = "...", features = ["neon"] }
Performance
For maximal performance, you should run proof generation with the following command and vary your shard_size
depending on your program's number of cycles.
SHARD_SIZE=4194304 RUST_LOG=info RUSTFLAGS='-C target-cpu=native' cargo run --release
Memory Usage
To reduce memory usage, set the SHARD_BATCH_SIZE
environment variable depending on how much RAM
your machine has. A higher number will use more memory, but will be faster.
SHARD_BATCH_SIZE=1 SHARD_SIZE=2097152 RUST_LOG=info RUSTFLAGS='-C target-cpu=native' cargo run --release
Advanced Allocator
SP1 programs use a simple bump allocator by default, which just increments a pointer to allocate memory. Although this works for many cases, some programs can still run out of memory in the SP1 zkVM. To address this, you can enable the embedded
allocator feature on the SP1 zkVM.
The embedded allocator uses the embedded-alloc
crate and offers more flexible memory management, albeit with extra cycle overhead.
To enable it, add the following to your sp1-zkvm
dependency in Cargo.toml
:
sp1-zkvm = { version = "...", features = ["embedded"] }
Once enabled, the embedded allocator replaces the default bump allocator.