reth_bench/bench/
output.rs1use reth_primitives_traits::constants::GIGAGAS;
5use serde::{ser::SerializeStruct, Serialize};
6use std::time::Duration;
7
8pub(crate) const GAS_OUTPUT_SUFFIX: &str = "total_gas.csv";
10
11pub(crate) const COMBINED_OUTPUT_SUFFIX: &str = "combined_latency.csv";
13
14pub(crate) const NEW_PAYLOAD_OUTPUT_SUFFIX: &str = "new_payload_latency.csv";
16
17#[derive(Debug)]
20pub(crate) struct NewPayloadResult {
21 pub(crate) gas_used: u64,
23 pub(crate) latency: Duration,
25}
26
27impl NewPayloadResult {
28 pub(crate) fn gas_per_second(&self) -> f64 {
30 self.gas_used as f64 / self.latency.as_secs_f64()
31 }
32}
33
34impl std::fmt::Display for NewPayloadResult {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 write!(
37 f,
38 "New payload processed at {:.4} Ggas/s, used {} total gas. Latency: {:?}",
39 self.gas_per_second() / GIGAGAS as f64,
40 self.gas_used,
41 self.latency
42 )
43 }
44}
45
46impl Serialize for NewPayloadResult {
49 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50 where
51 S: serde::ser::Serializer,
52 {
53 let time = self.latency.as_micros();
55 let mut state = serializer.serialize_struct("NewPayloadResult", 3)?;
56 state.serialize_field("gas_used", &self.gas_used)?;
57 state.serialize_field("latency", &time)?;
58 state.end()
59 }
60}
61
62#[derive(Debug)]
66pub(crate) struct CombinedResult {
67 pub(crate) block_number: u64,
69 pub(crate) new_payload_result: NewPayloadResult,
71 pub(crate) fcu_latency: Duration,
73 pub(crate) total_latency: Duration,
75}
76
77impl CombinedResult {
78 pub(crate) fn combined_gas_per_second(&self) -> f64 {
80 self.new_payload_result.gas_used as f64 / self.total_latency.as_secs_f64()
81 }
82}
83
84impl std::fmt::Display for CombinedResult {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(
87 f,
88 "Payload {} processed at {:.4} Ggas/s, used {} total gas. Combined gas per second: {:.4} Ggas/s. fcu latency: {:?}, newPayload latency: {:?}",
89 self.block_number,
90 self.new_payload_result.gas_per_second() / GIGAGAS as f64,
91 self.new_payload_result.gas_used,
92 self.combined_gas_per_second() / GIGAGAS as f64,
93 self.fcu_latency,
94 self.new_payload_result.latency
95 )
96 }
97}
98
99impl Serialize for CombinedResult {
102 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
103 where
104 S: serde::ser::Serializer,
105 {
106 let fcu_latency = self.fcu_latency.as_micros();
108 let new_payload_latency = self.new_payload_result.latency.as_micros();
109 let total_latency = self.total_latency.as_micros();
110 let mut state = serializer.serialize_struct("CombinedResult", 5)?;
111
112 state.serialize_field("block_number", &self.block_number)?;
114 state.serialize_field("gas_used", &self.new_payload_result.gas_used)?;
115 state.serialize_field("new_payload_latency", &new_payload_latency)?;
116 state.serialize_field("fcu_latency", &fcu_latency)?;
117 state.serialize_field("total_latency", &total_latency)?;
118 state.end()
119 }
120}
121
122#[derive(Debug)]
124pub(crate) struct TotalGasRow {
125 #[allow(dead_code)]
127 pub(crate) block_number: u64,
128 pub(crate) gas_used: u64,
130 pub(crate) time: Duration,
132}
133
134#[derive(Debug)]
136pub(crate) struct TotalGasOutput {
137 pub(crate) total_gas_used: u64,
139 pub(crate) total_duration: Duration,
141 pub(crate) total_gas_per_second: f64,
143 pub(crate) blocks_processed: u64,
145}
146
147impl TotalGasOutput {
148 pub(crate) fn new(rows: Vec<TotalGasRow>) -> Self {
150 let total_duration =
152 rows.last().map(|row| row.time).expect("the row has at least one element");
153 let blocks_processed = rows.len() as u64;
154 let total_gas_used: u64 = rows.into_iter().map(|row| row.gas_used).sum();
155 let total_gas_per_second = total_gas_used as f64 / total_duration.as_secs_f64();
156
157 Self { total_gas_used, total_duration, total_gas_per_second, blocks_processed }
158 }
159
160 pub(crate) fn total_gigagas_per_second(&self) -> f64 {
162 self.total_gas_per_second / GIGAGAS as f64
163 }
164}
165
166impl Serialize for TotalGasRow {
170 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171 where
172 S: serde::ser::Serializer,
173 {
174 let time = self.time.as_micros();
176 let mut state = serializer.serialize_struct("TotalGasRow", 3)?;
177 state.serialize_field("block_number", &self.block_number)?;
178 state.serialize_field("gas_used", &self.gas_used)?;
179 state.serialize_field("time", &time)?;
180 state.end()
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use csv::Writer;
188 use std::io::BufRead;
189
190 #[test]
191 fn test_write_total_gas_row_csv() {
192 let row = TotalGasRow { block_number: 1, gas_used: 1_000, time: Duration::from_secs(1) };
193
194 let mut writer = Writer::from_writer(vec![]);
195 writer.serialize(row).unwrap();
196 let result = writer.into_inner().unwrap();
197
198 let mut result = result.as_slice().lines();
200
201 let expected_first_line = "block_number,gas_used,time";
203 let first_line = result.next().unwrap().unwrap();
204 assert_eq!(first_line, expected_first_line);
205
206 let expected_second_line = "1,1000,1000000";
207 let second_line = result.next().unwrap().unwrap();
208 assert_eq!(second_line, expected_second_line);
209 }
210}