diff --git a/src/tx_dependency.rs b/src/tx_dependency.rs index 256c91d..0d3edb5 100644 --- a/src/tx_dependency.rs +++ b/src/tx_dependency.rs @@ -4,6 +4,8 @@ use std::{ cmp::{max, min, Reverse}, collections::{BTreeMap, BTreeSet, BinaryHeap, VecDeque}, }; +use std::fs::File; +use std::io::{BufWriter, Write}; pub(crate) type DependentTxsVec = SmallVec<[TxId; 1]>; @@ -35,6 +37,7 @@ pub(crate) struct TxDependency { pub round: Option, pub block_height: u64, + tx_states: SharedTxStates, } impl TxDependency { @@ -46,6 +49,7 @@ impl TxDependency { tx_weight: None, round: None, block_height: 0, + tx_states: Default::default(), } } @@ -64,6 +68,7 @@ impl TxDependency { last_write_tx.insert(location.clone(), txid); } } + self.tx_states = tx_states; } /// Retrieve the optimal partitions based on the dependency relationships between transactions. @@ -224,12 +229,14 @@ impl TxDependency { counter!("grevm.total_block_cnt").increment(1); } let mut subgraph = BTreeSet::new(); + let mut two = false; if let Some((_, groups)) = weighted_group.last_key_value() { if self.round.is_none() { let largest_ratio = groups[0].len() as f64 / num_remaining as f64; histogram!("grevm.large_graph_ratio").record(largest_ratio); if groups[0].len() >= num_remaining / 2 { counter!("grevm.low_parallelism_cnt").increment(1); + two = true; } } if groups[0].len() >= num_remaining / 3 { @@ -240,6 +247,7 @@ impl TxDependency { return; } + let mut longest_chain: Vec = vec![]; // ChainLength -> ChainNumber let mut chains = BTreeMap::new(); let mut visited = HashSet::new(); @@ -247,9 +255,11 @@ impl TxDependency { if !visited.contains(txid) { let mut txid = *txid; let mut chain_len = 0; + let mut curr_chain = vec![]; while !visited.contains(&txid) { chain_len += 1; visited.insert(txid); + curr_chain.push(txid); let dep: BTreeSet = self.tx_dependency[txid - num_finality_txs].clone().into_iter().collect(); for dep_id in dep.into_iter().rev() { @@ -259,6 +269,9 @@ impl TxDependency { } } } + if curr_chain.len() > longest_chain.len() { + longest_chain = curr_chain; + } let chain_num = chains.get(&chain_len).cloned().unwrap_or(0) + 1; chains.insert(chain_len, chain_num); } @@ -282,6 +295,47 @@ impl TxDependency { counter!("grevm.large_graph", "type" => chain_type, "tip" => tip.clone()).increment(1); if self.round.is_none() { info!("Block({}) has large subgraph, type={}", self.block_height, chain_type); + if two && chain_type == "chain" { + self.draw_dag(weighted_group, longest_chain); + } + } + } + } + + fn draw_dag(&self, weighted_group: &BTreeMap>, longest_chain: Vec) { + let file = File::create(format!("dag/block{}.info", self.block_height)).unwrap(); + let mut writer = BufWriter::new(file); + writeln!(writer, "[dag]").unwrap(); + + for txid in (0..self.tx_dependency.len()).rev() { + let deps: BTreeSet = self.tx_dependency[txid].clone().into_iter().collect(); + for dep_id in deps.into_iter().rev() { + writeln!(writer, "tx{}->tx{}", txid, dep_id).unwrap(); + } + } + writeln!(writer, "").unwrap(); + + let mut locations: HashSet = HashSet::new(); + info!("Block({}) has large subgraph, longest chain: {:?}", self.block_height, longest_chain); + for index in 0..longest_chain.len() - 1 { + let txid = longest_chain[index]; + let dep_id = longest_chain[index + 1]; + let rs = self.tx_states[txid].read_set.clone(); + let ws = self.tx_states[dep_id].write_set.clone(); + let mut intersection = HashSet::new(); + for l in ws { + if rs.contains_key(&l) { + intersection.insert(l); + } + } + if locations.is_empty() { + locations = intersection; + } else { + let join: HashSet = locations.intersection(&intersection).cloned().collect(); + if join.is_empty() { + info!("Block({}) has large subgraph, ==> tx{}: {:?}", self.block_height, txid, locations); + } + locations = join; } } }