Skip to main content
Version: 4.0.0

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.