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,132 @@ 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.
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 module_id. address ( ) == & AccountAddress :: ONE {
151+ return true ;
152+ }
153+ if let Some ( frame) = self . frames . last ( ) {
154+ if let FrameName :: Function { module_id : current_module_id, .. } = & frame. name {
155+ return current_module_id == module_id;
156+ }
157+ }
158+ false
159+ }
160+
161+ // Add a method to get the total gas usage for a module
162+ pub fn get_module_gas_usage ( & self , module_id : & ModuleId ) -> InternalGas {
163+ * self . module_gas_usage . get ( module_id) . unwrap_or ( & InternalGas :: zero ( ) )
164+ }
165+
166+ fn charge_call_with_metering (
167+ & mut self ,
168+ module_id : & ModuleId ,
169+ func_name : & str ,
170+ args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
171+ num_locals : NumArgs ,
172+ ) -> PartialVMResult < ( ) > {
173+ let is_intra_module = self . is_intra_module_call ( module_id) ;
174+ let base_cost = if is_intra_module {
175+ InternalGas :: new ( 0 )
176+ } else {
177+ InternalGas :: new ( 20 )
178+ } ;
179+
180+ let ( cost, res) = self . delegate_charge ( |base| {
181+ base. charge_call ( module_id, func_name, args, num_locals)
182+ } ) ;
183+ let total_cost = cost + base_cost;
184+
185+ // if !is_intra_module {
186+ // print!("Inter module call\n");
187+ // print!("Old cost: {}\n", cost);
188+ // print!("New Cost: {}\n", cost+base_cost);
189+ // }
190+ // println!("Module ID: {:?}, Total Cost: {:?}", module_id, total_cost);
191+
192+ // Record gas usage for the current module
193+ * self . module_gas_usage . entry ( module_id. clone ( ) ) . or_insert ( InternalGas :: zero ( ) ) += total_cost;
194+ // Push the current gas cost onto the stack
195+ self . gas_cost_stack . push ( self . base . balance_internal ( ) ) ;
196+ self . record_bytecode ( Opcodes :: CALL , cost + base_cost) ;
197+ self . frames . push ( CallFrame :: new_function (
198+ module_id. clone ( ) ,
199+ Identifier :: new ( func_name) . unwrap ( ) ,
200+ vec ! [ ] ,
201+ ) ) ;
202+
203+ res
204+ }
205+
206+ fn charge_call_generic_with_metering (
207+ & mut self ,
208+ module_id : & ModuleId ,
209+ func_name : & str ,
210+ ty_args : impl ExactSizeIterator < Item = impl TypeView > + Clone ,
211+ args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
212+ num_locals : NumArgs ,
213+ ) -> PartialVMResult < ( ) > {
214+ let is_intra_module = self . is_intra_module_call ( module_id) ;
215+ let base_cost = if is_intra_module {
216+ InternalGas :: new ( 0 )
217+ } else {
218+ InternalGas :: new ( 20 )
219+ } ;
220+
221+ let ty_tags = ty_args
222+ . clone ( )
223+ . map ( |ty| ty. to_type_tag ( ) )
224+ . collect :: < Vec < _ > > ( ) ;
225+
226+ let ( cost, res) = self . delegate_charge ( |base| {
227+ base. charge_call_generic ( module_id, func_name, ty_args, args, num_locals)
228+ } ) ;
229+
230+ let total_cost = cost + base_cost;
231+
232+ if !is_intra_module {
233+ print ! ( "Inter module call\n " ) ;
234+ print ! ( "Old cost: {}\n " , cost) ;
235+ print ! ( "New Cost: {}\n " , cost + base_cost) ;
236+ }
237+ // println!("Module ID: {:?}, Total Cost: {:?}", module_id, total_cost);
238+ // Record gas usage for the current module
239+ * self . module_gas_usage . entry ( module_id. clone ( ) ) . or_insert ( InternalGas :: zero ( ) ) += total_cost;
240+ // Push the current gas cost onto the stack
241+ self . gas_cost_stack . push ( self . base . balance_internal ( ) ) ;
242+ self . record_bytecode ( Opcodes :: CALL_GENERIC , cost + base_cost) ;
243+ self . frames . push ( CallFrame :: new_function (
244+ module_id. clone ( ) ,
245+ Identifier :: new ( func_name) . unwrap ( ) ,
246+ ty_tags,
247+ ) ) ;
248+
249+ res
250+ }
251+
129252 fn active_event_stream ( & mut self ) -> & mut Vec < ExecutionGasEvent > {
130253 & mut self . frames . last_mut ( ) . unwrap ( ) . events
131254 }
@@ -399,7 +522,16 @@ where
399522 if matches ! ( instr, SimpleInstruction :: Ret ) && self . frames . len ( ) > 1 {
400523 let cur_frame = self . frames . pop ( ) . expect ( "frame must exist" ) ;
401524 let last_frame = self . frames . last_mut ( ) . expect ( "frame must exist" ) ;
402- last_frame. events . push ( ExecutionGasEvent :: Call ( cur_frame) ) ;
525+ last_frame. events . push ( ExecutionGasEvent :: Call ( cur_frame. clone ( ) ) ) ;
526+ // Pop the gas cost from the stack and calculate the difference
527+ let start_gas = self . gas_cost_stack . pop ( ) . expect ( "stack must not be empty" ) ;
528+ let end_gas = self . base . balance_internal ( ) ;
529+ let function_cost = start_gas. checked_sub ( end_gas) . expect ( "gas cost must be non-negative" ) ;
530+
531+ // Print the function name and cost
532+ if let FrameName :: Function { name, .. } = & cur_frame. name {
533+ println ! ( "Function: {}, Cost: {:?}" , name, function_cost) ;
534+ }
403535 }
404536
405537 res
@@ -412,17 +544,7 @@ where
412544 args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
413545 num_locals : NumArgs ,
414546 ) -> 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
547+ self . charge_call_with_metering ( module_id, func_name, args, num_locals)
426548 }
427549
428550 fn charge_call_generic (
@@ -433,23 +555,7 @@ where
433555 args : impl ExactSizeIterator < Item = impl ValueView > + Clone ,
434556 num_locals : NumArgs ,
435557 ) -> 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
558+ self . charge_call_generic_with_metering ( module_id, func_name, ty_args, args, num_locals)
453559 }
454560
455561 fn charge_load_resource (
@@ -668,6 +774,8 @@ where
668774 G : AptosGasMeter ,
669775{
670776 pub fn finish ( mut self ) -> TransactionGasLog {
777+ // Print the module_gas_usage hash table
778+ self . print_module_gas_usage ( ) ;
671779 while self . frames . len ( ) > 1 {
672780 let cur = self . frames . pop ( ) . expect ( "frame must exist" ) ;
673781 let last = self . frames . last_mut ( ) . expect ( "frame must exist" ) ;
0 commit comments