@@ -4,6 +4,13 @@ use std::{
44 fmt:: { Display , Formatter } ,
55} ;
66
7+ use utils:: { build_poseidon16, build_poseidon24, pretty_integer} ;
8+
9+ use crate :: {
10+ DIMENSION , ExecutionResult , F , MAX_MEMORY_SIZE , Memory , PUBLIC_INPUT_START , RunnerError ,
11+ build_public_memory,
12+ } ;
13+
714pub mod operand;
815pub use operand:: * ;
916pub mod hint;
@@ -23,6 +30,151 @@ pub struct Bytecode {
2330 pub ending_pc : usize ,
2431}
2532
33+ impl Bytecode {
34+ #[ must_use]
35+ pub fn execute ( & self , public_input : & [ F ] , private_input : & [ F ] ) -> ExecutionResult {
36+ let mut std_out = String :: new ( ) ;
37+ let first = self
38+ . execute_internal (
39+ public_input,
40+ private_input,
41+ MAX_MEMORY_SIZE / 2 ,
42+ false ,
43+ & mut std_out,
44+ )
45+ . unwrap_or_else ( |err| {
46+ if !std_out. is_empty ( ) {
47+ print ! ( "{std_out}" ) ;
48+ }
49+ panic ! ( "Error during bytecode execution: {err}" ) ;
50+ } ) ;
51+
52+ self . execute_internal (
53+ public_input,
54+ private_input,
55+ first. no_vec_runtime_memory ,
56+ true ,
57+ & mut String :: new ( ) ,
58+ )
59+ . unwrap ( )
60+ }
61+
62+ pub ( crate ) fn execute_internal (
63+ & self ,
64+ public_input : & [ F ] ,
65+ private_input : & [ F ] ,
66+ no_vec_runtime_memory : usize ,
67+ final_execution : bool ,
68+ std_out : & mut String ,
69+ ) -> Result < ExecutionResult , RunnerError > {
70+ // TODO avoid rebuilding each time
71+ let ( p16, p24) = ( build_poseidon16 ( ) , build_poseidon24 ( ) ) ;
72+
73+ // set public memory
74+ let mut memory = Memory :: new ( build_public_memory ( public_input) ) ;
75+
76+ let public_memory_size = ( PUBLIC_INPUT_START + public_input. len ( ) ) . next_power_of_two ( ) ;
77+ let mut fp = public_memory_size;
78+
79+ private_input
80+ . iter ( )
81+ . copied ( )
82+ . enumerate ( )
83+ . try_for_each ( |( i, v) | memory. set ( fp + i, v) ) ?;
84+
85+ fp = ( fp + private_input. len ( ) ) . next_multiple_of ( DIMENSION ) ;
86+
87+ let initial_ap = fp + self . starting_frame_memory ;
88+ let initial_ap_vec =
89+ ( initial_ap + no_vec_runtime_memory) . next_multiple_of ( DIMENSION ) / DIMENSION ;
90+
91+ let ( mut pc, mut ap, mut ap_vec) = ( 0 , initial_ap, initial_ap_vec) ;
92+
93+ let mut poseidon16_calls = 0 ;
94+ let mut poseidon24_calls = 0 ;
95+ let mut dot_product_ext_ext_calls = 0 ;
96+ let mut dot_product_base_ext_calls = 0 ;
97+ let mut cpu_cycles = 0 ;
98+
99+ let mut last_checkpoint_cpu_cycles = 0 ;
100+ let mut checkpoint_ap = initial_ap;
101+ let mut checkpoint_ap_vec = ap_vec;
102+
103+ let mut pcs = Vec :: new ( ) ;
104+ let mut fps = Vec :: new ( ) ;
105+
106+ while pc != self . ending_pc {
107+ if pc >= self . instructions . len ( ) {
108+ return Err ( RunnerError :: PCOutOfBounds ) ;
109+ }
110+
111+ pcs. push ( pc) ;
112+ fps. push ( fp) ;
113+
114+ cpu_cycles += 1 ;
115+
116+ // hints (no PC change)
117+ for hint in self . hints . get ( & pc) . unwrap_or ( & vec ! [ ] ) {
118+ hint. execute (
119+ & mut memory,
120+ fp,
121+ & mut ap,
122+ & mut ap_vec,
123+ std_out,
124+ cpu_cycles,
125+ & mut last_checkpoint_cpu_cycles,
126+ & mut checkpoint_ap,
127+ & mut checkpoint_ap_vec,
128+ ) ?;
129+ }
130+
131+ // instruction
132+ self . instructions [ pc] . execute (
133+ & mut memory,
134+ & mut fp,
135+ & mut pc,
136+ & p16,
137+ & p24,
138+ & mut poseidon16_calls,
139+ & mut poseidon24_calls,
140+ & mut dot_product_ext_ext_calls,
141+ & mut dot_product_base_ext_calls,
142+ ) ?;
143+ }
144+
145+ debug_assert_eq ! ( pc, self . ending_pc) ;
146+ pcs. push ( pc) ;
147+ fps. push ( fp) ;
148+
149+ if final_execution {
150+ if !std_out. is_empty ( ) {
151+ print ! ( "{std_out}" ) ;
152+ }
153+ print_report (
154+ self ,
155+ public_input. len ( ) ,
156+ private_input. len ( ) ,
157+ cpu_cycles,
158+ & memory,
159+ initial_ap_vec,
160+ ap_vec,
161+ poseidon16_calls,
162+ poseidon24_calls,
163+ dot_product_ext_ext_calls,
164+ dot_product_base_ext_calls,
165+ ) ;
166+ }
167+
168+ Ok ( ExecutionResult {
169+ no_vec_runtime_memory : ap - initial_ap,
170+ public_memory_size,
171+ memory,
172+ pcs,
173+ fps,
174+ } )
175+ }
176+ }
177+
26178impl Display for Bytecode {
27179 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
28180 for ( pc, instruction) in self . instructions . iter ( ) . enumerate ( ) {
@@ -36,3 +188,62 @@ impl Display for Bytecode {
36188 Ok ( ( ) )
37189 }
38190}
191+
192+ fn print_report (
193+ bc : & Bytecode ,
194+ public_in_len : usize ,
195+ private_in_len : usize ,
196+ cycles : usize ,
197+ memory : & Memory ,
198+ initial_ap_vec : usize ,
199+ ap_vec : usize ,
200+ p16_calls : usize ,
201+ p24_calls : usize ,
202+ dp_ext_ext_calls : usize ,
203+ dp_base_ext_calls : usize ,
204+ ) {
205+ println ! ( "\n Bytecode size: {}" , pretty_integer( bc. instructions. len( ) ) ) ;
206+ println ! ( "Public input size: {}" , pretty_integer( public_in_len) ) ;
207+ println ! ( "Private input size: {}" , pretty_integer( private_in_len) ) ;
208+ println ! ( "Executed {} instructions" , pretty_integer( cycles) ) ;
209+
210+ let runtime_mem = memory. 0 . len ( ) - ( PUBLIC_INPUT_START + public_in_len) ;
211+ println ! (
212+ "Runtime memory: {} ({:.2}% vec)" ,
213+ pretty_integer( runtime_mem) ,
214+ ( DIMENSION * ( ap_vec - initial_ap_vec) ) as f64 / runtime_mem as f64 * 100.0
215+ ) ;
216+
217+ let total_poseidon = p16_calls + p24_calls;
218+ if total_poseidon > 0 {
219+ println ! (
220+ "Poseidon2_16 calls: {}, Poseidon2_24 calls: {} (1 poseidon per {} instructions)" ,
221+ pretty_integer( p16_calls) ,
222+ pretty_integer( p24_calls) ,
223+ cycles / total_poseidon
224+ ) ;
225+ }
226+ if dp_ext_ext_calls > 0 {
227+ println ! (
228+ "DotProductExtExt calls: {}" ,
229+ pretty_integer( dp_ext_ext_calls)
230+ ) ;
231+ }
232+ if dp_base_ext_calls > 0 {
233+ println ! (
234+ "DotProductBaseExt calls: {}" ,
235+ pretty_integer( dp_base_ext_calls)
236+ ) ;
237+ }
238+
239+ let used_cells = memory
240+ . 0
241+ . iter ( )
242+ . skip ( PUBLIC_INPUT_START + public_in_len)
243+ . filter ( |& & x| x. is_some ( ) )
244+ . count ( ) ;
245+ println ! (
246+ "Memory usage: {:.1}%" ,
247+ used_cells as f64 / runtime_mem as f64 * 100.0
248+ ) ;
249+ }
0 commit comments