Skip to content

Commit 2f3ea9d

Browse files
authored
support execute until segment (#1251)
1 parent 21ebf2b commit 2f3ea9d

File tree

1 file changed

+85
-51
lines changed

1 file changed

+85
-51
lines changed

crates/vm/src/arch/vm.rs

Lines changed: 85 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ pub struct VmExecutorResult<SC: StarkGenericConfig> {
7474
pub final_memory: Option<VmMemoryState<Val<SC>>>,
7575
}
7676

77+
pub struct VmExecutorNextSegmentState<F: PrimeField32> {
78+
pub memory: MemoryImage<F>,
79+
pub input: Streams<F>,
80+
pub pc: u32,
81+
pub segment_idx: usize,
82+
}
83+
84+
pub struct VmExecutorOneSegmentResult<F: PrimeField32, VC: VmConfig<F>> {
85+
pub segment: ExecutionSegment<F, VC>,
86+
pub next_state: Option<VmExecutorNextSegmentState<F>>,
87+
}
88+
7789
impl<F, VC> VmExecutor<F, VC>
7890
where
7991
F: PrimeField32,
@@ -110,70 +122,92 @@ where
110122
exe: impl Into<VmExe<F>>,
111123
input: impl Into<Streams<F>>,
112124
) -> Result<Vec<ExecutionSegment<F, VC>>, ExecutionError> {
125+
let mem_config = self.config.system().memory_config;
113126
let exe = exe.into();
114-
let streams = input.into();
127+
let mut streams = input.into();
115128
let mut segments = vec![];
116-
let mem_config = self.config.system().memory_config;
129+
let mut memory = AddressMap::from_iter(
130+
mem_config.as_offset,
131+
1 << mem_config.as_height,
132+
1 << mem_config.pointer_max_bits,
133+
exe.init_memory.clone(),
134+
);
135+
let mut pc = exe.pc_start;
136+
let mut segment_idx = 0;
137+
138+
loop {
139+
let mut one_segment_result =
140+
self.execute_until_segment(exe.clone(), memory, streams, segment_idx, pc)?;
141+
streams = one_segment_result.segment.chip_complex.take_streams();
142+
segments.push(one_segment_result.segment);
143+
if one_segment_result.next_state.is_none() {
144+
break;
145+
}
146+
let next_state = one_segment_result.next_state.unwrap();
147+
memory = next_state.memory;
148+
pc = next_state.pc;
149+
segment_idx = next_state.segment_idx;
150+
}
151+
tracing::debug!("Number of continuation segments: {}", segments.len());
152+
153+
Ok(segments)
154+
}
155+
156+
/// Executes a program until a segmentation happens.
157+
/// Returns the last segment and the vm state for next segment.
158+
/// This is so that the tracegen and proving of this segment can be immediately started (on a separate machine).
159+
pub fn execute_until_segment(
160+
&self,
161+
exe: impl Into<VmExe<F>>,
162+
memory: MemoryImage<F>,
163+
input: impl Into<Streams<F>>,
164+
segment_idx: usize,
165+
pc: u32,
166+
) -> Result<VmExecutorOneSegmentResult<F, VC>, ExecutionError> {
167+
let exe = exe.into();
168+
let streams = input.into();
117169
let mut segment = ExecutionSegment::new(
118170
&self.config,
119171
exe.program.clone(),
120172
streams,
121-
Some(AddressMap::from_iter(
122-
mem_config.as_offset,
123-
1 << mem_config.as_height,
124-
1 << mem_config.pointer_max_bits,
125-
exe.init_memory.clone(),
126-
)),
173+
Some(memory),
127174
exe.fn_bounds.clone(),
128175
);
129176
if let Some(overridden_heights) = self.overridden_heights.as_ref() {
130177
segment.set_override_trace_heights(overridden_heights.clone());
131178
}
132-
let mut pc = exe.pc_start;
133-
134-
loop {
135-
// Used to add `segment` label to metrics
136-
let _span = info_span!("execute_segment", segment = segments.len()).entered();
137-
let state = metrics_span("execute_time_ms", || segment.execute_from_pc(pc))?;
138-
pc = state.pc;
139-
140-
if state.is_terminated {
141-
break;
142-
}
143-
144-
assert!(
145-
self.continuation_enabled(),
146-
"multiple segments require to enable continuations"
147-
);
148-
149-
assert_eq!(
150-
pc,
151-
segment.chip_complex.connector_chip().boundary_states[1]
152-
.unwrap()
153-
.pc
154-
);
155-
156-
let final_memory = mem::take(&mut segment.final_memory)
157-
.expect("final memory should be set in continuations segment");
158-
let streams = segment.chip_complex.take_streams();
159-
160-
segments.push(segment);
161-
162-
segment = ExecutionSegment::new(
163-
&self.config,
164-
exe.program.clone(),
165-
streams,
166-
Some(final_memory),
167-
exe.fn_bounds.clone(),
168-
);
169-
if let Some(overridden_heights) = self.overridden_heights.as_ref() {
170-
segment.set_override_trace_heights(overridden_heights.clone());
171-
}
179+
let _span = info_span!("execute_segment", segment = segment_idx).entered();
180+
let state = metrics_span("execute_time_ms", || segment.execute_from_pc(pc))?;
181+
182+
if state.is_terminated {
183+
return Ok(VmExecutorOneSegmentResult {
184+
segment,
185+
next_state: None,
186+
});
172187
}
173-
segments.push(segment);
174-
tracing::debug!("Number of continuation segments: {}", segments.len());
175188

176-
Ok(segments)
189+
assert!(
190+
self.continuation_enabled(),
191+
"multiple segments require to enable continuations"
192+
);
193+
assert_eq!(
194+
state.pc,
195+
segment.chip_complex.connector_chip().boundary_states[1]
196+
.unwrap()
197+
.pc
198+
);
199+
let final_memory = mem::take(&mut segment.final_memory)
200+
.expect("final memory should be set in continuations segment");
201+
let streams = segment.chip_complex.take_streams();
202+
Ok(VmExecutorOneSegmentResult {
203+
segment,
204+
next_state: Some(VmExecutorNextSegmentState {
205+
memory: final_memory,
206+
input: streams,
207+
pc: state.pc,
208+
segment_idx: segment_idx + 1,
209+
}),
210+
})
177211
}
178212

179213
pub fn execute(

0 commit comments

Comments
 (0)