@@ -74,6 +74,18 @@ pub struct VmExecutorResult<SC: StarkGenericConfig> {
74
74
pub final_memory : Option < VmMemoryState < Val < SC > > > ,
75
75
}
76
76
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
+
77
89
impl < F , VC > VmExecutor < F , VC >
78
90
where
79
91
F : PrimeField32 ,
@@ -110,70 +122,92 @@ where
110
122
exe : impl Into < VmExe < F > > ,
111
123
input : impl Into < Streams < F > > ,
112
124
) -> Result < Vec < ExecutionSegment < F , VC > > , ExecutionError > {
125
+ let mem_config = self . config . system ( ) . memory_config ;
113
126
let exe = exe. into ( ) ;
114
- let streams = input. into ( ) ;
127
+ let mut streams = input. into ( ) ;
115
128
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 ( ) ;
117
169
let mut segment = ExecutionSegment :: new (
118
170
& self . config ,
119
171
exe. program . clone ( ) ,
120
172
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) ,
127
174
exe. fn_bounds . clone ( ) ,
128
175
) ;
129
176
if let Some ( overridden_heights) = self . overridden_heights . as_ref ( ) {
130
177
segment. set_override_trace_heights ( overridden_heights. clone ( ) ) ;
131
178
}
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
+ } ) ;
172
187
}
173
- segments. push ( segment) ;
174
- tracing:: debug!( "Number of continuation segments: {}" , segments. len( ) ) ;
175
188
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
+ } )
177
211
}
178
212
179
213
pub fn execute (
0 commit comments