sp1_core_executor/
opts.rs1use crate::{
2 cost_and_height_per_syscall, rv64im_costs, utils::trunc_32, RetainedEventsPreset, RiscvAirId,
3 SyscallCode, BYTE_NUM_ROWS, RANGE_NUM_ROWS,
4};
5use enum_map::EnumMap;
6use serde::{Deserialize, Serialize};
7use std::{collections::HashSet, env};
8
9const MAX_SHARD_SIZE: usize = 1 << 24;
10
11pub const ELEMENT_THRESHOLD: u64 = (1 << 28) + (1 << 27);
13pub const HEIGHT_THRESHOLD: u64 = 1 << 22;
15pub const MINIMAL_TRACE_CHUNK_THRESHOLD: u64 =
17 2147483648 / std::mem::size_of::<sp1_jit::MemValue>() as u64;
18pub const DEFAULT_TRACE_CHUNK_SLOTS: usize = 5;
20pub const DEFAULT_MEMORY_LIMIT: u64 = 24 * 1024 * 1024 * 1024;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29pub struct ShardingThreshold {
30 pub element_threshold: u64,
32 pub height_threshold: u64,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct SP1CoreOpts {
39 pub minimal_trace_chunk_threshold: u64,
41 pub trace_chunk_slots: usize,
43 pub memory_limit: u64,
45 pub shard_size: usize,
47 pub sharding_threshold: ShardingThreshold,
49 pub retained_events_presets: HashSet<RetainedEventsPreset>,
51 pub global_dependencies_opt: bool,
53}
54
55impl Default for SP1CoreOpts {
56 fn default() -> Self {
57 let minimal_trace_chunk_threshold = env::var("MINIMAL_TRACE_CHUNK_THRESHOLD").map_or_else(
58 |_| MINIMAL_TRACE_CHUNK_THRESHOLD,
59 |s| s.parse::<u64>().unwrap_or(MINIMAL_TRACE_CHUNK_THRESHOLD),
60 );
61
62 let trace_chunk_slots = env::var("TRACE_CHUNK_SLOTS").map_or_else(
63 |_| DEFAULT_TRACE_CHUNK_SLOTS,
64 |s| s.parse::<usize>().unwrap_or(DEFAULT_TRACE_CHUNK_SLOTS),
65 );
66
67 let memory_limit = env::var("MEMORY_LIMIT").map_or_else(
68 |_| DEFAULT_MEMORY_LIMIT,
69 |s| s.parse::<u64>().unwrap_or(DEFAULT_MEMORY_LIMIT),
70 );
71
72 let shard_size = env::var("SHARD_SIZE")
73 .map_or_else(|_| MAX_SHARD_SIZE, |s| s.parse::<usize>().unwrap_or(MAX_SHARD_SIZE));
74
75 let element_threshold = env::var("ELEMENT_THRESHOLD")
76 .map_or_else(|_| ELEMENT_THRESHOLD, |s| s.parse::<u64>().unwrap_or(ELEMENT_THRESHOLD));
77
78 let height_threshold = env::var("HEIGHT_THRESHOLD")
79 .map_or_else(|_| HEIGHT_THRESHOLD, |s| s.parse::<u64>().unwrap_or(HEIGHT_THRESHOLD));
80
81 let sharding_threshold = ShardingThreshold { element_threshold, height_threshold };
82
83 let mut retained_events_presets = HashSet::new();
84 retained_events_presets.insert(RetainedEventsPreset::Bls12381Field);
85 retained_events_presets.insert(RetainedEventsPreset::Bn254Field);
86 retained_events_presets.insert(RetainedEventsPreset::Sha256);
87 retained_events_presets.insert(RetainedEventsPreset::Poseidon2);
88 retained_events_presets.insert(RetainedEventsPreset::U256Ops);
89
90 Self {
91 minimal_trace_chunk_threshold,
92 trace_chunk_slots,
93 memory_limit,
94 shard_size,
95 sharding_threshold,
96 retained_events_presets,
97 global_dependencies_opt: false,
98 }
99 }
100}
101
102#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
104pub struct SplitOpts {
105 pub pack_trace_threshold: u64,
108 pub combine_memory_threshold: usize,
111 pub combine_page_prot_threshold: usize,
114 pub syscall_threshold: EnumMap<SyscallCode, usize>,
116 pub memory: usize,
118 pub page_prot: usize,
120}
121
122impl SplitOpts {
123 #[must_use]
125 pub fn new(opts: &SP1CoreOpts, program_size: usize, page_protect_allowed: bool) -> Self {
126 assert!(!page_protect_allowed, "page protection is turned off");
127
128 let costs = rv64im_costs();
129
130 let mut available_trace_area = opts.sharding_threshold.element_threshold;
131 let mut fixed_trace_area = 0;
132 fixed_trace_area += program_size.next_multiple_of(32) * costs[&RiscvAirId::Program];
133 fixed_trace_area += BYTE_NUM_ROWS as usize * costs[&RiscvAirId::Byte];
134 fixed_trace_area += RANGE_NUM_ROWS as usize * costs[&RiscvAirId::Range];
135
136 assert!(
137 available_trace_area >= fixed_trace_area as u64,
138 "SP1CoreOpts's element threshold is too low"
139 );
140
141 available_trace_area -= fixed_trace_area as u64;
142
143 let max_height = opts.sharding_threshold.height_threshold;
144
145 let syscall_threshold = EnumMap::from_fn(|syscall_code: SyscallCode| {
146 if syscall_code.should_send() == 0 || syscall_code.as_air_id().is_none() {
147 return 0;
148 }
149
150 let (cost_per_syscall, max_height_per_syscall) =
151 cost_and_height_per_syscall(syscall_code, &costs, page_protect_allowed);
152 let element_threshold = trunc_32(available_trace_area as usize / cost_per_syscall);
153 let height_threshold = trunc_32(max_height as usize / max_height_per_syscall);
154
155 element_threshold.min(height_threshold)
156 });
157
158 let cost_per_memory = costs[&RiscvAirId::MemoryGlobalInit] + costs[&RiscvAirId::Global];
159 let memory = trunc_32(
160 (available_trace_area as usize / cost_per_memory).min(max_height as usize) / 2,
161 );
162
163 let pack_trace_threshold = 2 * opts.sharding_threshold.element_threshold / 3;
165 let combine_memory_threshold =
167 trunc_32(3 * opts.sharding_threshold.element_threshold as usize / cost_per_memory / 20);
168
169 Self {
170 pack_trace_threshold,
171 combine_memory_threshold,
172 combine_page_prot_threshold: 0,
173 syscall_threshold,
174 memory,
175 page_prot: 0,
176 }
177 }
178}