Basics
In this section, we'll cover some of the basics of optimizing the performance of your SP1 programs, with a focus on improving the end to end costs.
Program Optimization
- The first step to optimizing your program is to identify the performance bottlenecks. You can do this by profiling your application or using cycle tracking.
- Compiling your program with different settings can yield better performance characteristics.
- Set
lto
tothin
,true
, orfat
to enable link-time optimization. This can yield significant performance improvements. - Set
codegen-units
to1
to disable parallel codegen.
- Set
- Avoid copying or de(serializing) data unnecessarily.
Cryptographic Acceleration
If your program makes heavy use of cryptographic primitives (SHA-256, Keccak, etc.), SP1 supports accelerated "precompiles" for these operations.
Follow the instructions here to use them.
Prover Acceleration
SP1 supports both GPU (with CUDA) and CPU (with AVX on Intel and ARM) hardware acceleration for proving.
I/O Optimizations
If your program makes heavy use of (de)serializing data, you can make use of the following techniques to optimize performance of input reading and output writing.
Zero-Copy (De)serialization
Rather than using write
and read
to serialize and deserialize data in the zkVM context (which invokes bincode
serialization by default), you can use write_vec
and read_slice
to serialize and deserialize data in the zkVM context.
bincode
is a popular serialization library for Rust, but it is not optimized for the zkVM context and can be CPU intensive. Generally, we recommend using write_vec
and read_slice
in combination with zero-copy deserialization libraries like rkyv
.
For rkyv
, you can use the #[derive(Archive, Serialize, Deserialize)]
macro to automatically derive the Archive
, Serialize
, and Deserialize
traits for your structs.
use rkyv::{Archive, Serialize, Deserialize};
#[derive(Archive, Serialize, Deserialize)]
struct MyStruct {
field: u64,
}
You can then use rkyv::to_bytes
to serialize your structs in your script and rkyv::from_bytes
to deserialize them in your program.
use rkyv::rancor::Error;
let mut stdin = SP1Stdin::new();
let my_struct = MyStruct { field: 42 };
let bytes = rkyv::to_bytes::<Error>(&my_struct);
stdin.write_slice(&bytes);
use rkyv::rancor::Error;
let input = sp1_zkvm::io::read_vec();
let deserialized_struct = rkyv::from_bytes::<MyStruct, Error>(&input).unwrap();
Alternative Serialization Libraries
If rkyv
is difficult to integrate with your codebase, you can benchmark alternative serialization libraries or derive your own de(serialization) logic for better I/O performance.