Skip to content

Commit 258dfbb

Browse files
authored
Merge branch 'main' into minor_improvements_precompile
2 parents f9c0a6c + cecd808 commit 258dfbb

File tree

15 files changed

+629
-24
lines changed

15 files changed

+629
-24
lines changed

.github/workflows/manual_docker_performance_publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Publish Docker
1+
name: Publish Performance tag Docker
22

33
on:
44
workflow_dispatch:

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/ethrex_replay/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ eyre.workspace = true
3030
tokio = { workspace = true, features = ["full"] }
3131
clap.workspace = true
3232
charming = { version = "0.4.0", features = ["ssr"] }
33+
rkyv.workspace = true
3334

3435
jemallocator = { version = "0.5.4", optional = true }
3536

cmd/ethrex_replay/src/cache.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
use ethrex_common::types::blobs_bundle;
22
use ethrex_common::types::{Block, block_execution_witness::ExecutionWitnessResult};
3+
use eyre::Context;
4+
use rkyv::rancor::Error;
5+
use rkyv::{Archive, Deserialize as RDeserialize, Serialize as RSerialize};
36
use serde::{Deserialize, Serialize};
47
use serde_with::serde_as;
5-
use std::{
6-
fs::File,
7-
io::{BufReader, BufWriter},
8-
};
8+
use std::io::Write;
9+
use std::{fs::File, io::BufWriter};
910

1011
#[serde_as]
11-
#[derive(Serialize, Deserialize)]
12+
#[derive(Serialize, Deserialize, RSerialize, RDeserialize, Archive)]
1213
pub struct L2Fields {
1314
#[serde_as(as = "[_; 48]")]
1415
pub blob_commitment: blobs_bundle::Commitment,
1516
#[serde_as(as = "[_; 48]")]
1617
pub blob_proof: blobs_bundle::Proof,
1718
}
1819

19-
#[derive(Serialize, Deserialize)]
20+
#[derive(Serialize, Deserialize, RSerialize, RDeserialize, Archive)]
2021
pub struct Cache {
2122
pub blocks: Vec<Block>,
2223
pub witness: ExecutionWitnessResult,
@@ -36,14 +37,18 @@ impl Cache {
3637
}
3738

3839
pub fn load_cache(file_name: &str) -> eyre::Result<Cache> {
39-
let file = BufReader::new(File::open(file_name)?);
40-
Ok(serde_json::from_reader(file)?)
40+
let file_data = std::fs::read(file_name)?;
41+
let cache =
42+
rkyv::from_bytes::<Cache, Error>(&file_data).wrap_err("Failed to deserialize with rkyv")?;
43+
Ok(cache)
4144
}
4245

4346
pub fn write_cache(cache: &Cache, file_name: &str) -> eyre::Result<()> {
4447
if cache.blocks.is_empty() {
4548
return Err(eyre::Error::msg("cache can't be empty"));
4649
}
47-
let file = BufWriter::new(File::create(file_name)?);
48-
Ok(serde_json::to_writer_pretty(file, cache)?)
50+
let mut file = BufWriter::new(File::create(file_name)?);
51+
let bytes = rkyv::to_bytes::<Error>(cache).wrap_err("Failed to serialize with rkyv")?;
52+
file.write_all(&bytes)
53+
.wrap_err("Failed to write binary data")
4954
}

cmd/ethrex_replay/src/cli.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,103 @@ impl SubcommandProve {
488488
}
489489
}
490490

491+
#[derive(Subcommand)]
492+
enum SubcommandCache {
493+
#[command(about = "Cache a single block.")]
494+
Block {
495+
#[arg(help = "Block to use. Uses the latest if not specified.")]
496+
block: Option<usize>,
497+
#[arg(long, env = "RPC_URL", required = true)]
498+
rpc_url: Url,
499+
#[arg(
500+
long,
501+
help = "Name of the network or genesis file. Supported: mainnet, holesky, sepolia, hoodi. Default: mainnet",
502+
value_parser = clap::value_parser!(Network),
503+
default_value_t = Network::default(),
504+
)]
505+
network: Network,
506+
},
507+
#[command(about = "Cache multiple blocks.")]
508+
Blocks {
509+
#[arg(help = "List of blocks to execute.", num_args = 1.., value_delimiter = ',')]
510+
blocks: Vec<u64>,
511+
#[arg(long, env = "RPC_URL", required = true)]
512+
rpc_url: Url,
513+
#[arg(
514+
long,
515+
help = "Name of the network or genesis file. Supported: mainnet, holesky, sepolia, hoodi. Default: mainnet",
516+
value_parser = clap::value_parser!(Network),
517+
default_value_t = Network::default(),
518+
)]
519+
network: Network,
520+
},
521+
#[command(about = "Cache a range of blocks")]
522+
BlockRange {
523+
#[arg(help = "Starting block. (Inclusive)")]
524+
start: usize,
525+
#[arg(help = "Ending block. (Inclusive)")]
526+
end: usize,
527+
#[arg(long, env = "RPC_URL", required = true)]
528+
rpc_url: Url,
529+
#[arg(
530+
long,
531+
help = "Name of the network or genesis file. Supported: mainnet, holesky, sepolia, hoodi. Default: mainnet",
532+
value_parser = clap::value_parser!(Network),
533+
default_value_t = Network::default(),
534+
)]
535+
network: Network,
536+
},
537+
}
538+
539+
impl SubcommandCache {
540+
pub async fn run(self) -> eyre::Result<()> {
541+
match self {
542+
SubcommandCache::Block {
543+
block,
544+
rpc_url,
545+
network,
546+
} => {
547+
let eth_client = EthClient::new(rpc_url.as_ref())?;
548+
let block_identifier = or_latest(block)?;
549+
let _ = get_blockdata(eth_client, network.clone(), block_identifier).await?;
550+
if let Some(block_number) = block {
551+
info!("Block {block_number} data cached successfully.");
552+
} else {
553+
info!("Latest block data cached successfully.");
554+
}
555+
}
556+
SubcommandCache::Blocks {
557+
mut blocks,
558+
rpc_url,
559+
network,
560+
} => {
561+
blocks.sort();
562+
let eth_client = EthClient::new(rpc_url.as_ref())?;
563+
for block_number in blocks {
564+
let _ = get_blockdata(
565+
eth_client.clone(),
566+
network.clone(),
567+
BlockIdentifier::Number(block_number),
568+
)
569+
.await?;
570+
}
571+
info!("Blocks data cached successfully.");
572+
}
573+
SubcommandCache::BlockRange {
574+
start,
575+
end,
576+
rpc_url,
577+
network,
578+
} => {
579+
let eth_client = EthClient::new(rpc_url.as_ref())?;
580+
let _ = get_rangedata(eth_client, network, start, end).await?;
581+
info!("Block from {start} to {end} data cached successfully.");
582+
}
583+
}
584+
Ok(())
585+
}
586+
}
587+
491588
#[derive(Subcommand)]
492589
enum EthrexReplayCommand {
493590
#[command(
@@ -516,6 +613,11 @@ enum EthrexReplayCommand {
516613
)]
517614
network: Network,
518615
},
616+
#[command(
617+
subcommand,
618+
about = "Store the state prior to the execution of the block"
619+
)]
620+
Cache(SubcommandCache),
519621
}
520622

521623
pub async fn start() -> eyre::Result<()> {
@@ -539,6 +641,7 @@ pub async fn start() -> eyre::Result<()> {
539641
let cache = get_rangedata(eth_client, network, start, end).await?;
540642
plot(cache).await?;
541643
}
644+
EthrexReplayCommand::Cache(cmd) => cmd.run().await?,
542645
};
543646
Ok(())
544647
}

cmd/ethrex_replay/src/fetcher.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub async fn get_blockdata(
3232

3333
let chain_config = network.get_genesis()?.config;
3434

35-
let file_name = format!("cache_{network}_{requested_block_number}.json");
35+
let file_name = format!("cache_{network}_{requested_block_number}.bin");
3636

3737
if let Ok(cache) = load_cache(&file_name).inspect_err(|e| warn!("Failed to load cache: {e}")) {
3838
info!("Getting block {requested_block_number} data from cache");
@@ -194,7 +194,7 @@ pub async fn get_rangedata(
194194
) -> eyre::Result<Cache> {
195195
let chain_config = network.get_genesis()?.config;
196196

197-
let file_name = format!("cache_{network}_{from}-{to}.json");
197+
let file_name = format!("cache_{network}_{from}-{to}.bin");
198198

199199
if let Ok(cache) = load_cache(&file_name) {
200200
info!("Getting block range data from cache");
@@ -215,7 +215,7 @@ pub async fn get_batchdata(
215215
chain_config: ChainConfig,
216216
batch_number: u64,
217217
) -> eyre::Result<Cache> {
218-
let file_name = format!("cache_batch_{batch_number}.json");
218+
let file_name = format!("cache_batch_{batch_number}.bin");
219219
if let Ok(cache) = load_cache(&file_name) {
220220
info!("Getting batch data from cache");
221221
return Ok(cache);

crates/blockchain/metrics/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ serde.workspace = true
1515
ethrex-common.workspace = true
1616

1717

18-
prometheus = { version = "0.13.4", optional = true }
18+
prometheus = { version = "0.13.4", features = ["process"], optional = true }
1919
axum = { workspace = true, optional = true }
2020
tracing-subscriber.workspace = true
2121

crates/blockchain/metrics/api.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use axum::{Router, routing::get};
22

33
use crate::profiling::gather_profiling_metrics;
44

5-
use crate::{MetricsApiError, metrics_blocks::METRICS_BLOCKS, metrics_transactions::METRICS_TX};
5+
use crate::{
6+
MetricsApiError, metrics_blocks::METRICS_BLOCKS, metrics_process::METRICS_PROCESS,
7+
metrics_transactions::METRICS_TX,
8+
};
69

710
pub async fn start_prometheus_metrics_api(
811
address: String,
@@ -47,5 +50,11 @@ pub(crate) async fn get_metrics() -> String {
4750
}
4851
}
4952

53+
ret_string.push('\n');
54+
match METRICS_PROCESS.gather_metrics() {
55+
Ok(s) => ret_string.push_str(&s),
56+
Err(_) => tracing::error!("Failed to register METRICS_PROCESS"),
57+
};
58+
5059
ret_string
5160
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use prometheus::{Encoder, Registry, TextEncoder};
2+
use std::sync::LazyLock;
3+
4+
use crate::MetricsError;
5+
6+
pub static METRICS_PROCESS: LazyLock<MetricsProcess> = LazyLock::new(MetricsProcess::default);
7+
8+
#[derive(Debug, Clone)]
9+
pub struct MetricsProcess;
10+
11+
impl Default for MetricsProcess {
12+
fn default() -> Self {
13+
Self::new()
14+
}
15+
}
16+
17+
impl MetricsProcess {
18+
pub fn new() -> Self {
19+
MetricsProcess
20+
}
21+
22+
/// The Process collector gathers standard process metrics (CPU time, RSS, VSZ, FDs, threads, start_time).
23+
/// But it only works on Linux. This is an initial implementation.
24+
pub fn gather_metrics(&self) -> Result<String, MetricsError> {
25+
let r = Registry::new();
26+
27+
// Register Prometheus' built-in Linux process metrics
28+
#[cfg(target_os = "linux")]
29+
{
30+
use prometheus::process_collector::ProcessCollector;
31+
r.register(Box::new(ProcessCollector::for_self()))
32+
.map_err(|e| {
33+
MetricsError::PrometheusErr(format!(
34+
"Failed to register process collector: {}",
35+
e
36+
))
37+
})?;
38+
}
39+
40+
let encoder = TextEncoder::new();
41+
let metric_families = r.gather();
42+
43+
let mut buffer = Vec::new();
44+
encoder
45+
.encode(&metric_families, &mut buffer)
46+
.map_err(|e| MetricsError::PrometheusErr(e.to_string()))?;
47+
48+
let res = String::from_utf8(buffer)?;
49+
Ok(res)
50+
}
51+
}

crates/blockchain/metrics/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub mod api;
44
pub mod l2;
55
#[cfg(any(feature = "api", feature = "metrics"))]
66
pub mod metrics_blocks;
7+
#[cfg(any(feature = "api", feature = "metrics"))]
8+
pub mod metrics_process;
79
#[cfg(any(feature = "api", feature = "transactions"))]
810
pub mod metrics_transactions;
911
#[cfg(feature = "api")]

0 commit comments

Comments
 (0)