Skip to content

Commit 8cce82e

Browse files
Yoichi Hiraisjudson
authored andcommitted
More efficient estimate of memory-checked RAM size (#616)
* More efficient estimate of memory-checked RAM size * Silence clippy * Use WORD_SIZE
1 parent 802054d commit 8cce82e

File tree

7 files changed

+75
-6
lines changed

7 files changed

+75
-6
lines changed

prover/src/machine.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,9 @@ impl<C: MachineChip + Sync> Machine<C> {
126126
) -> Result<Proof, ProvingError> {
127127
let num_steps = trace.get_num_steps();
128128
let program_len = view.get_program_memory().program.len();
129-
let memory_len = view.get_initial_memory().len()
130-
+ view.get_exit_code().len()
131-
+ view.get_public_output().len();
129+
let tracked_ram_size = view.view_tracked_ram_size();
132130

133-
// [memory_len + 4 * num_steps] is the union bound for the size of touched-or-initialized memory
134-
// The STARK trace needs to contain [num_steps], too, but it is never bigger than the above.
135-
let log_size = Self::max_log_size(&[program_len, memory_len + 4 * num_steps])
131+
let log_size = Self::max_log_size(&[num_steps, program_len, tracked_ram_size])
136132
.max(PreprocessedTraces::MIN_LOG_SIZE);
137133

138134
let extensions_iter = BASE_EXTENSIONS.iter().chain(extensions);

sdk/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ categories = { workspace = true }
1212
[dependencies]
1313
serde.workspace = true
1414

15+
nexus-common = { path = "../common" }
1516
nexus-core = { path = "../core" }
1617
nexus-sdk-macros = { path = "./macros" }
1718

sdk/src/traits.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crypto::digest::{Digest, OutputSizeUser};
22
use crypto_common::generic_array::{ArrayLength, GenericArray};
3+
use nexus_common::constants::WORD_SIZE;
34
use serde::{de::DeserializeOwned, Serialize};
45
use std::path::Path;
56

@@ -88,11 +89,15 @@ impl CheckedView for nexus_core::nvm::View {
8889
expected_public_output,
8990
);
9091

92+
let static_memory_size =
93+
(&expected_elf.rom_image.len() + &expected_elf.ram_image.len()) * WORD_SIZE;
94+
9195
Self::new(
9296
&Some(*memory_layout),
9397
&Vec::new(),
9498
&program_memory,
9599
&initial_memory,
100+
memory_layout.tracked_ram_size(static_memory_size),
96101
&exit_code,
97102
&output_memory,
98103
&expected_ad.to_vec(),

vm/src/emulator/executor.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,12 @@ impl Emulator for HarvardEmulator {
745745
Vec::new()
746746
};
747747

748+
let input_size = rom_iter.len() + self.static_ram_image.len() + public_input.len();
749+
let tracked_ram_size = self
750+
.memory_stats
751+
.get_tracked_ram_size(input_size as u32, output_memory.len() as u32)
752+
as usize;
753+
748754
View {
749755
memory_layout: None,
750756
debug_logs,
@@ -766,6 +772,7 @@ impl Emulator for HarvardEmulator {
766772
.chain(ram_iter)
767773
.chain(public_input)
768774
.collect(),
775+
tracked_ram_size,
769776
exit_code,
770777
output_memory,
771778
associated_data: Vec::new(),
@@ -1227,6 +1234,10 @@ impl Emulator for LinearEmulator {
12271234
)
12281235
.unwrap_or_default();
12291236

1237+
let tracked_ram_size = self
1238+
.memory_layout
1239+
.tracked_ram_size(self.initial_static_ram_image.len() + rom_initialization.len());
1240+
12301241
View {
12311242
memory_layout: Some(self.memory_layout),
12321243
debug_logs,
@@ -1256,6 +1267,7 @@ impl Emulator for LinearEmulator {
12561267
.chain(ram_iter)
12571268
.chain(public_input_iter)
12581269
.collect(),
1270+
tracked_ram_size,
12591271
exit_code,
12601272
output_memory,
12611273
associated_data,

vm/src/emulator/layout.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,38 @@ impl LinearMemoryLayout {
294294
pub fn stack_top(&self) -> u32 {
295295
self.stack_top - WORD_SIZE as u32
296296
}
297+
298+
pub fn tracked_ram_size(&self, static_memory_size: usize) -> usize {
299+
let stack_size: usize =
300+
self.stack_top
301+
.checked_sub(self.stack_bottom)
302+
.expect("stack top should be above stack bottom") as usize;
303+
let heap_size = self
304+
.heap
305+
.checked_sub(self.heap_start())
306+
.expect("heap should be above heap start") as usize;
307+
let public_input_size =
308+
self.public_input_end()
309+
.checked_sub(self.public_input_start())
310+
.expect("public input end should be above public input start") as usize;
311+
let public_output_size = self
312+
.public_output_end()
313+
.checked_sub(self.public_output_start())
314+
.expect("public output end should be above public output start")
315+
as usize;
316+
let exit_code_size = WORD_SIZE;
317+
// program, registers, and ad are not under RAM checking. omitted.
318+
let total = [
319+
static_memory_size,
320+
stack_size,
321+
heap_size,
322+
public_input_size,
323+
public_output_size,
324+
exit_code_size,
325+
]
326+
.iter()
327+
.try_fold(0usize, |acc, &val| acc.checked_add(val))
328+
.expect("overflow");
329+
total
330+
}
297331
}

vm/src/emulator/memory_stats.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ impl MemoryStats {
115115
ad_size,
116116
)
117117
}
118+
119+
/// Returns the total number of addresses under RAM memory checking.
120+
pub fn get_tracked_ram_size(&self, input_size: u32, output_size: u32) -> u32 {
121+
let heap_size = self.max_heap_access - self.heap_bottom;
122+
let stack_size = self.stack_top - self.min_stack_access;
123+
let total = [heap_size, stack_size, input_size, output_size]
124+
.iter()
125+
.try_fold(0u32, |acc, &val| acc.checked_add(val))
126+
.expect("overflow");
127+
total
128+
}
118129
}
119130

120131
#[cfg(test)]

vm/src/emulator/utils.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ pub struct View {
189189
pub(crate) debug_logs: Vec<Vec<u8>>,
190190
pub(crate) program_memory: ProgramInfo,
191191
pub(crate) initial_memory: Vec<MemoryInitializationEntry>,
192+
/// The number of all addresses under RAM memory checking
193+
pub(crate) tracked_ram_size: usize,
192194
pub(crate) exit_code: Vec<PublicOutputEntry>,
193195
pub(crate) output_memory: Vec<PublicOutputEntry>,
194196
// todo: incorporate into initial memory
@@ -197,11 +199,13 @@ pub struct View {
197199

198200
impl View {
199201
/// Construct a view out of its raw parts.
202+
#[allow(clippy::too_many_arguments)] // extra thought needed what's the best approach to reduce args
200203
pub fn new(
201204
memory_layout: &Option<LinearMemoryLayout>,
202205
debug_logs: &Vec<Vec<u8>>,
203206
program_memory: &ProgramInfo,
204207
initial_memory: &Vec<MemoryInitializationEntry>,
208+
tracked_ram_size: usize,
205209
exit_code: &Vec<PublicOutputEntry>,
206210
output_memory: &Vec<PublicOutputEntry>,
207211
associated_data: &Vec<u8>,
@@ -211,6 +215,7 @@ impl View {
211215
debug_logs: debug_logs.to_owned(),
212216
program_memory: program_memory.to_owned(),
213217
initial_memory: initial_memory.to_owned(),
218+
tracked_ram_size,
214219
exit_code: exit_code.to_owned(),
215220
output_memory: output_memory.to_owned(),
216221
associated_data: associated_data.to_owned(),
@@ -247,6 +252,11 @@ impl View {
247252
.map(|layout| io_entries_into_vec(layout.public_output_start(), &self.output_memory))
248253
}
249254

255+
/// Return the number of all addresses under RAM memory checking.
256+
pub fn view_tracked_ram_size(&self) -> usize {
257+
self.tracked_ram_size
258+
}
259+
250260
/// Return the raw bytes of the associated data, if any.
251261
pub fn view_associated_data(&self) -> Option<Vec<u8>> {
252262
if self.memory_layout.is_some() {

0 commit comments

Comments
 (0)