reth_bench/bench/
output.rsuse reth_primitives_traits::constants::GIGAGAS;
use serde::{ser::SerializeStruct, Serialize};
use std::time::Duration;
pub(crate) const GAS_OUTPUT_SUFFIX: &str = "total_gas.csv";
pub(crate) const COMBINED_OUTPUT_SUFFIX: &str = "combined_latency.csv";
pub(crate) const NEW_PAYLOAD_OUTPUT_SUFFIX: &str = "new_payload_latency.csv";
#[derive(Debug)]
pub(crate) struct NewPayloadResult {
pub(crate) gas_used: u64,
pub(crate) latency: Duration,
}
impl NewPayloadResult {
pub(crate) fn gas_per_second(&self) -> f64 {
self.gas_used as f64 / self.latency.as_secs_f64()
}
}
impl std::fmt::Display for NewPayloadResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"New payload processed at {:.4} Ggas/s, used {} total gas. Latency: {:?}",
self.gas_per_second() / GIGAGAS as f64,
self.gas_used,
self.latency
)
}
}
impl Serialize for NewPayloadResult {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let time = self.latency.as_micros();
let mut state = serializer.serialize_struct("NewPayloadResult", 3)?;
state.serialize_field("gas_used", &self.gas_used)?;
state.serialize_field("latency", &time)?;
state.end()
}
}
#[derive(Debug)]
pub(crate) struct CombinedResult {
pub(crate) block_number: u64,
pub(crate) new_payload_result: NewPayloadResult,
pub(crate) fcu_latency: Duration,
pub(crate) total_latency: Duration,
}
impl CombinedResult {
pub(crate) fn combined_gas_per_second(&self) -> f64 {
self.new_payload_result.gas_used as f64 / self.total_latency.as_secs_f64()
}
}
impl std::fmt::Display for CombinedResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Payload {} processed at {:.4} Ggas/s, used {} total gas. Combined gas per second: {:.4} Ggas/s. fcu latency: {:?}, newPayload latency: {:?}",
self.block_number,
self.new_payload_result.gas_per_second() / GIGAGAS as f64,
self.new_payload_result.gas_used,
self.combined_gas_per_second() / GIGAGAS as f64,
self.fcu_latency,
self.new_payload_result.latency
)
}
}
impl Serialize for CombinedResult {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let fcu_latency = self.fcu_latency.as_micros();
let new_payload_latency = self.new_payload_result.latency.as_micros();
let total_latency = self.total_latency.as_micros();
let mut state = serializer.serialize_struct("CombinedResult", 5)?;
state.serialize_field("block_number", &self.block_number)?;
state.serialize_field("gas_used", &self.new_payload_result.gas_used)?;
state.serialize_field("new_payload_latency", &new_payload_latency)?;
state.serialize_field("fcu_latency", &fcu_latency)?;
state.serialize_field("total_latency", &total_latency)?;
state.end()
}
}
#[derive(Debug)]
pub(crate) struct TotalGasRow {
#[allow(dead_code)]
pub(crate) block_number: u64,
pub(crate) gas_used: u64,
pub(crate) time: Duration,
}
#[derive(Debug)]
pub(crate) struct TotalGasOutput {
pub(crate) total_gas_used: u64,
pub(crate) total_duration: Duration,
pub(crate) total_gas_per_second: f64,
pub(crate) blocks_processed: u64,
}
impl TotalGasOutput {
pub(crate) fn new(rows: Vec<TotalGasRow>) -> Self {
let total_duration =
rows.last().map(|row| row.time).expect("the row has at least one element");
let blocks_processed = rows.len() as u64;
let total_gas_used: u64 = rows.into_iter().map(|row| row.gas_used).sum();
let total_gas_per_second = total_gas_used as f64 / total_duration.as_secs_f64();
Self { total_gas_used, total_duration, total_gas_per_second, blocks_processed }
}
pub(crate) fn total_gigagas_per_second(&self) -> f64 {
self.total_gas_per_second / GIGAGAS as f64
}
}
impl Serialize for TotalGasRow {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let time = self.time.as_micros();
let mut state = serializer.serialize_struct("TotalGasRow", 3)?;
state.serialize_field("block_number", &self.block_number)?;
state.serialize_field("gas_used", &self.gas_used)?;
state.serialize_field("time", &time)?;
state.end()
}
}
#[cfg(test)]
mod tests {
use super::*;
use csv::Writer;
use std::io::BufRead;
#[test]
fn test_write_total_gas_row_csv() {
let row = TotalGasRow { block_number: 1, gas_used: 1_000, time: Duration::from_secs(1) };
let mut writer = Writer::from_writer(vec![]);
writer.serialize(row).unwrap();
let result = writer.into_inner().unwrap();
let mut result = result.as_slice().lines();
let expected_first_line = "block_number,gas_used,time";
let first_line = result.next().unwrap().unwrap();
assert_eq!(first_line, expected_first_line);
let expected_second_line = "1,1000,1000000";
let second_line = result.next().unwrap().unwrap();
assert_eq!(second_line, expected_second_line);
}
}