1+ use alloy_primitives:: B256 ;
12use clap:: Parser ;
23use execution_events_example:: event_listener:: EventName ;
4+ use execution_events_example:: serializable_event:: SerializableExecEvent ;
35use execution_events_example:: { event_filter:: ClientMessage , server:: ServerMessage } ;
46use futures_util:: { SinkExt , StreamExt } ;
5- use std:: collections:: HashSet ;
7+ use std:: collections:: HashMap ;
68use tokio_tungstenite:: { connect_async, tungstenite:: Message } ;
79
810use tracing_subscriber:: { layer:: SubscriberExt , util:: SubscriberInitExt } ;
@@ -28,6 +30,30 @@ struct Cli {
2830 verbose_accesses : bool ,
2931}
3032
33+ macro_rules! log_event {
34+ // Entry: just message
35+ ( $msg: expr) => {
36+ tracing:: info!( "------> {}" , $msg)
37+ } ;
38+ // Entry: message with arbitrary number of key=value pairs
39+ ( $msg: expr, $( $key: ident = $value: expr) ,+ $( , ) ?) => { {
40+ let mut s = format!( "------> {}" , $msg) ;
41+ $(
42+ s. push_str( & format!( " {}={:?}" , stringify!( $key) , $value) ) ;
43+ ) *
44+ tracing:: info!( "{}" , s) ;
45+ } } ;
46+ }
47+
48+ #[ derive( Default ) ]
49+ struct ClientState {
50+ events_witnessed : usize ,
51+ block_start_ns : u64 ,
52+ txs_start_ns : HashMap < usize , ( B256 , u64 ) > ,
53+ block_txns_total_duration : std:: time:: Duration ,
54+ current_block_number : u64 ,
55+ }
56+
3157#[ tokio:: main]
3258async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
3359 // Initialize tracing subscriber
@@ -77,9 +103,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
77103
78104 // Read messages from the server
79105 let mut events_per_sec_interval = tokio:: time:: interval ( tokio:: time:: Duration :: from_secs ( 1 ) ) ;
80- let mut events_witnessed = 0 ;
81- let mut seen_block_starts: HashSet < u64 > = HashSet :: new ( ) ;
82- let mut seen_block_qcs: HashSet < u64 > = HashSet :: new ( ) ;
106+ let mut client_state = ClientState :: default ( ) ;
107+
83108 loop {
84109 tokio:: select! {
85110 msg = read. next( ) => {
@@ -92,29 +117,72 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
92117 Ok ( Message :: Text ( text) ) => {
93118 match serde_json:: from_str:: <ServerMessage >( & text) {
94119 Ok ( ServerMessage :: Events ( events) ) => {
95- // Check for duplicate BlockStart events
96120 for event in & events {
97- if event. event_name == EventName :: BlockStart {
98- if let Some ( block_number) = event. block_number {
99- if !seen_block_starts. insert( block_number) {
100- warn!( "Duplicate BlockStart event for block {}" , block_number) ;
101- }
121+ match event. event_name {
122+ EventName :: TxnPerfEvmEnter => {
123+ println!( "tx enter" ) ;
124+ }
125+ EventName :: TxnPerfEvmExit => {
126+ println!( "tx exit" ) ;
102127 }
128+ _ => ( )
103129 }
104- if event. event_name == EventName :: BlockQC {
105- if let Some ( block_number) = event. block_number {
106- if !seen_block_qcs. insert( block_number) {
107- warn!( "Duplicate BlockQC event for block {}" , block_number) ;
108- }
130+ match event. payload {
131+ SerializableExecEvent :: BlockStart { block_number, base_fee_per_gas, .. } => {
132+ log_event!( "BlockStart" , block_number = block_number, base_fee = base_fee_per_gas) ;
133+ client_state. current_block_number = u64 :: max( client_state. current_block_number, block_number) ;
109134 }
135+ SerializableExecEvent :: BlockPerfEvmEnter => {
136+ log_event!( "BlockPerfEvmEnter" ) ;
137+ client_state. block_start_ns = event. timestamp_ns;
138+ }
139+ SerializableExecEvent :: TxnHeaderStart { txn_hash, txn_index, .. } => {
140+ log_event!( "TxnHeaderStart" , txn_index = txn_index, txn_hash = txn_hash) ;
141+ client_state. txs_start_ns. insert( txn_index, ( txn_hash, event. timestamp_ns) ) ;
142+ } ,
143+ SerializableExecEvent :: TxnEvmOutput { txn_index, .. } => {
144+ if let Some ( ( txn_hash, txn_start_ns) ) = client_state. txs_start_ns. remove( & txn_index) {
145+ let txn_duration = std:: time:: Duration :: from_nanos( ( event. timestamp_ns - txn_start_ns) as u64 ) ;
146+ client_state. block_txns_total_duration += txn_duration;
147+
148+ log_event!( "TxnEvmOutput" , txn_index = txn_index, txn_hash = txn_hash, duration = txn_duration) ;
149+ } else {
150+ warn!( "TxnPerfEvmExit event received without TxnPerfEvmEnter event: {:?}" , txn_index) ;
151+ }
152+ } ,
153+ SerializableExecEvent :: BlockPerfEvmExit => {
154+ log_event!( "BlockPerfEvmExit" ) ;
155+ let block_duration = std:: time:: Duration :: from_nanos( ( event. timestamp_ns - client_state. block_start_ns) as u64 ) ;
156+ let parallel_execution_savings = client_state. block_txns_total_duration. checked_sub( block_duration) ;
157+ let savings_pct = if parallel_execution_savings. is_none( ) { // This only happens with really small/empty blocks
158+ error!( "Parallel execution savings is negative: txs={:?} block={:?} height={}" , client_state. block_txns_total_duration, block_duration, client_state. current_block_number) ;
159+ None
160+ } else {
161+ Some ( 100.0 * ( 1.0 - ( block_duration. as_nanos( ) as f64 / client_state. block_txns_total_duration. as_nanos( ) as f64 ) ) )
162+ } ;
163+
164+ log_event!( "BlockPerfEvmExit" , height = client_state. current_block_number, block_duration = block_duration, tx_total_duration = client_state. block_txns_total_duration, savings_pct = savings_pct) ;
165+
166+ client_state. block_txns_total_duration = std:: time:: Duration :: from_nanos( 0 ) ;
167+ } ,
168+ SerializableExecEvent :: BlockEnd { gas_used, .. } => {
169+ log_event!( "BlockEnd" , gas_used = gas_used, block_number = client_state. current_block_number) ;
170+ } ,
171+ SerializableExecEvent :: BlockQC { block_number, .. } => {
172+ log_event!( "BlockQC" , block_number = block_number) ;
173+ } ,
174+ SerializableExecEvent :: BlockFinalized { block_number, .. } => {
175+ log_event!( "BlockFinalized" , block_number = block_number) ;
176+ } ,
177+ _ => ( )
110178 }
111179 }
112180
113181 info!( "Received {} events" , events. len( ) ) ;
114182 if cli. verbose_events {
115183 info!( "Events: {:?}" , events) ;
116184 }
117- events_witnessed += events. len( ) ;
185+ client_state . events_witnessed += events. len( ) ;
118186 }
119187 Ok ( ServerMessage :: TopAccesses ( top_accesses) ) => {
120188 info!( "Received top accesses" ) ;
@@ -147,8 +215,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
147215 }
148216 }
149217 _ = events_per_sec_interval. tick( ) => {
150- info!( "Events per second: {}" , events_witnessed) ;
151- events_witnessed = 0 ;
218+ info!( "Events per second: {}" , client_state . events_witnessed) ;
219+ client_state . events_witnessed = 0 ;
152220 }
153221 }
154222 }
0 commit comments