11// Copyright © Aptos Foundation
22// SPDX-License-Identifier: Apache-2.0
33
4+ use std:: collections:: HashMap ;
45use crate :: log:: {
56 CallFrame , Dependency , EventStorage , EventTransient , ExecutionAndIOCosts , ExecutionGasEvent ,
67 FrameName , StorageFees , TransactionGasLog , WriteOpType , WriteStorage , WriteTransient ,
@@ -41,6 +42,8 @@ pub struct GasProfiler<G> {
4142 events_transient : Vec < EventTransient > ,
4243 write_set_transient : Vec < WriteTransient > ,
4344 storage_fees : Option < StorageFees > ,
45+ module_gas_usage : HashMap < ModuleId , InternalGas > ,
46+ gas_cost_stack : Vec < InternalGas >
4447}
4548
4649// TODO: consider switching to a library like https://docs.rs/delegate/latest/delegate/.
@@ -98,6 +101,8 @@ impl<G> GasProfiler<G> {
98101 events_transient : vec ! [ ] ,
99102 write_set_transient : vec ! [ ] ,
100103 storage_fees : None ,
104+ module_gas_usage : HashMap :: new ( ) ,
105+ gas_cost_stack : vec ! [ ]
101106 }
102107 }
103108
@@ -118,14 +123,129 @@ impl<G> GasProfiler<G> {
118123 events_transient : vec ! [ ] ,
119124 write_set_transient : vec ! [ ] ,
120125 storage_fees : None ,
126+ module_gas_usage : HashMap :: new ( ) ,
127+ gas_cost_stack : vec ! [ ]
121128 }
122129 }
123130}
124131
132+ // 0 -> 800 -> 1500 -> 2000 -> 2500
133+ // A::Foo() { Bar()}
134+ // B::Bar() { Barz()}
135+ // C::Barz() {}
136+ // TODO: add a new value if it is intermodule call, also think about return intermodule. call to 0x1 should be ignored.
137+
125138impl < G > GasProfiler < G >
126139where
127140 G : AptosGasMeter ,
128141{
142+ // Method to print the module_gas_usage hash table
143+ pub fn print_module_gas_usage ( & self ) {
144+ for ( module_id, gas) in & self . module_gas_usage {
145+ println ! ( "Module: {:?}, Gas Used: {:?}" , module_id, gas) ;
146+ }
147+ }
148+
149+ fn is_intra_module_call ( & self , module_id : & ModuleId ) -> bool {
150+ if let Some ( frame) = self . frames . last ( ) {
151+ if let FrameName :: Function { module_id : current_module_id, .. } = & frame. name {
152+ return current_module_id == module_id;
153+ }
154+ }
155+ false
156+ }
157+
158+ // Add a method to get the total gas usage for a module
159+ pub fn get_module_gas_usage ( & self , module_id : & ModuleId ) -> InternalGas {
160+ * self . module_gas_usage . get ( module_id) . unwrap_or ( & InternalGas :: zero ( ) )
161+ }
162+
163+ fn charge_call_with_metering (
164+ & mut self ,
165+ module_id : & ModuleId ,
166+ func_name : & str ,
167+ args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
168+ num_locals : NumArgs ,
169+ ) -> PartialVMResult < ( ) > {
170+ let is_intra_module = self . is_intra_module_call ( module_id) ;
171+ let base_cost = if is_intra_module {
172+ InternalGas :: new ( 0 )
173+ } else {
174+ InternalGas :: new ( 20 )
175+ } ;
176+
177+ let ( cost, res) = self . delegate_charge ( |base| {
178+ base. charge_call ( module_id, func_name, args, num_locals)
179+ } ) ;
180+ let total_cost = cost + base_cost;
181+
182+ // if !is_intra_module {
183+ // print!("Inter module call\n");
184+ // print!("Old cost: {}\n", cost);
185+ // print!("New Cost: {}\n", cost+base_cost);
186+ // }
187+ // println!("Module ID: {:?}, Total Cost: {:?}", module_id, total_cost);
188+
189+ // Record gas usage for the current module
190+ * self . module_gas_usage . entry ( module_id. clone ( ) ) . or_insert ( InternalGas :: zero ( ) ) += total_cost;
191+ // Push the current gas cost onto the stack
192+ self . gas_cost_stack . push ( self . base . balance_internal ( ) ) ;
193+ self . record_bytecode ( Opcodes :: CALL , cost + base_cost) ;
194+ self . frames . push ( CallFrame :: new_function (
195+ module_id. clone ( ) ,
196+ Identifier :: new ( func_name) . unwrap ( ) ,
197+ vec ! [ ] ,
198+ ) ) ;
199+
200+ res
201+ }
202+
203+ fn charge_call_generic_with_metering (
204+ & mut self ,
205+ module_id : & ModuleId ,
206+ func_name : & str ,
207+ ty_args : impl ExactSizeIterator < Item = impl TypeView > + Clone ,
208+ args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
209+ num_locals : NumArgs ,
210+ ) -> PartialVMResult < ( ) > {
211+ let is_intra_module = self . is_intra_module_call ( module_id) ;
212+ let base_cost = if is_intra_module {
213+ InternalGas :: new ( 0 )
214+ } else {
215+ InternalGas :: new ( 20 )
216+ } ;
217+
218+ let ty_tags = ty_args
219+ . clone ( )
220+ . map ( |ty| ty. to_type_tag ( ) )
221+ . collect :: < Vec < _ > > ( ) ;
222+
223+ let ( cost, res) = self . delegate_charge ( |base| {
224+ base. charge_call_generic ( module_id, func_name, ty_args, args, num_locals)
225+ } ) ;
226+
227+ let total_cost = cost + base_cost;
228+
229+ if !is_intra_module {
230+ print ! ( "Inter module call\n " ) ;
231+ print ! ( "Old cost: {}\n " , cost) ;
232+ print ! ( "New Cost: {}\n " , cost + base_cost) ;
233+ }
234+ // println!("Module ID: {:?}, Total Cost: {:?}", module_id, total_cost);
235+ // Record gas usage for the current module
236+ * self . module_gas_usage . entry ( module_id. clone ( ) ) . or_insert ( InternalGas :: zero ( ) ) += total_cost;
237+ // Push the current gas cost onto the stack
238+ self . gas_cost_stack . push ( self . base . balance_internal ( ) ) ;
239+ self . record_bytecode ( Opcodes :: CALL_GENERIC , cost + base_cost) ;
240+ self . frames . push ( CallFrame :: new_function (
241+ module_id. clone ( ) ,
242+ Identifier :: new ( func_name) . unwrap ( ) ,
243+ ty_tags,
244+ ) ) ;
245+
246+ res
247+ }
248+
129249 fn active_event_stream ( & mut self ) -> & mut Vec < ExecutionGasEvent > {
130250 & mut self . frames . last_mut ( ) . unwrap ( ) . events
131251 }
@@ -399,7 +519,16 @@ where
399519 if matches ! ( instr, SimpleInstruction :: Ret ) && self . frames . len ( ) > 1 {
400520 let cur_frame = self . frames . pop ( ) . expect ( "frame must exist" ) ;
401521 let last_frame = self . frames . last_mut ( ) . expect ( "frame must exist" ) ;
402- last_frame. events . push ( ExecutionGasEvent :: Call ( cur_frame) ) ;
522+ last_frame. events . push ( ExecutionGasEvent :: Call ( cur_frame. clone ( ) ) ) ;
523+ // Pop the gas cost from the stack and calculate the difference
524+ let start_gas = self . gas_cost_stack . pop ( ) . expect ( "stack must not be empty" ) ;
525+ let end_gas = self . base . balance_internal ( ) ;
526+ let function_cost = start_gas. checked_sub ( end_gas) . expect ( "gas cost must be non-negative" ) ;
527+
528+ // Print the function name and cost
529+ if let FrameName :: Function { name, .. } = & cur_frame. name {
530+ println ! ( "Function: {}, Cost: {:?}" , name, function_cost) ;
531+ }
403532 }
404533
405534 res
@@ -412,17 +541,7 @@ where
412541 args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
413542 num_locals : NumArgs ,
414543 ) -> PartialVMResult < ( ) > {
415- let ( cost, res) =
416- self . delegate_charge ( |base| base. charge_call ( module_id, func_name, args, num_locals) ) ;
417-
418- self . record_bytecode ( Opcodes :: CALL , cost) ;
419- self . frames . push ( CallFrame :: new_function (
420- module_id. clone ( ) ,
421- Identifier :: new ( func_name) . unwrap ( ) ,
422- vec ! [ ] ,
423- ) ) ;
424-
425- res
544+ self . charge_call_with_metering ( module_id, func_name, args, num_locals)
426545 }
427546
428547 fn charge_call_generic (
@@ -433,23 +552,7 @@ where
433552 args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
434553 num_locals : NumArgs ,
435554 ) -> PartialVMResult < ( ) > {
436- let ty_tags = ty_args
437- . clone ( )
438- . map ( |ty| ty. to_type_tag ( ) )
439- . collect :: < Vec < _ > > ( ) ;
440-
441- let ( cost, res) = self . delegate_charge ( |base| {
442- base. charge_call_generic ( module_id, func_name, ty_args, args, num_locals)
443- } ) ;
444-
445- self . record_bytecode ( Opcodes :: CALL_GENERIC , cost) ;
446- self . frames . push ( CallFrame :: new_function (
447- module_id. clone ( ) ,
448- Identifier :: new ( func_name) . unwrap ( ) ,
449- ty_tags,
450- ) ) ;
451-
452- res
555+ self . charge_call_generic_with_metering ( module_id, func_name, ty_args, args, num_locals)
453556 }
454557
455558 fn charge_load_resource (
@@ -668,6 +771,8 @@ where
668771 G : AptosGasMeter ,
669772{
670773 pub fn finish ( mut self ) -> TransactionGasLog {
774+ // Print the module_gas_usage hash table
775+ self . print_module_gas_usage ( ) ;
671776 while self . frames . len ( ) > 1 {
672777 let cur = self . frames . pop ( ) . expect ( "frame must exist" ) ;
673778 let last = self . frames . last_mut ( ) . expect ( "frame must exist" ) ;
0 commit comments