Move register_entry_id() call out of write stage (#1253)

* Move register_entry_id() call out of write stage

- Write stage is MIPS intensive and has become a bottleneck for
  TPU pipeline
- This will reduce the MIPS requirements for the stage

* Fix rust format issues
This commit is contained in:
Pankaj Garg
2018-09-18 11:42:25 -07:00
parent d81eaf69db
commit 8f0648e8fc
3 changed files with 45 additions and 28 deletions

View File

@ -5,11 +5,14 @@
//! Transaction, the latest hash, and the number of hashes since the last transaction. //! Transaction, the latest hash, and the number of hashes since the last transaction.
//! The resulting stream of entries represents ordered transactions in time. //! The resulting stream of entries represents ordered transactions in time.
use bank::Bank;
use counter::Counter;
use entry::Entry; use entry::Entry;
use hash::Hash; use log::Level;
use recorder::Recorder; use recorder::Recorder;
use service::Service; use service::Service;
use std::sync::mpsc::{channel, Receiver, RecvError, Sender, TryRecvError}; use std::sync::mpsc::{channel, Receiver, RecvError, Sender, TryRecvError};
use std::sync::Arc;
use std::thread::{self, Builder, JoinHandle}; use std::thread::{self, Builder, JoinHandle};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use transaction::Transaction; use transaction::Transaction;
@ -27,18 +30,15 @@ pub struct RecordStage {
impl RecordStage { impl RecordStage {
/// A background thread that will continue tagging received Transaction messages and /// A background thread that will continue tagging received Transaction messages and
/// sending back Entry messages until either the receiver or sender channel is closed. /// sending back Entry messages until either the receiver or sender channel is closed.
pub fn new( pub fn new(signal_receiver: Receiver<Signal>, bank: Arc<Bank>) -> (Self, Receiver<Vec<Entry>>) {
signal_receiver: Receiver<Signal>,
start_hash: &Hash,
) -> (Self, Receiver<Vec<Entry>>) {
let (entry_sender, entry_receiver) = channel(); let (entry_sender, entry_receiver) = channel();
let start_hash = *start_hash; let start_hash = bank.last_id();
let thread_hdl = Builder::new() let thread_hdl = Builder::new()
.name("solana-record-stage".to_string()) .name("solana-record-stage".to_string())
.spawn(move || { .spawn(move || {
let mut recorder = Recorder::new(start_hash); let mut recorder = Recorder::new(start_hash);
let _ = Self::process_signals(&mut recorder, &signal_receiver, &entry_sender); let _ = Self::process_signals(&mut recorder, &signal_receiver, bank, &entry_sender);
}).unwrap(); }).unwrap();
(RecordStage { thread_hdl }, entry_receiver) (RecordStage { thread_hdl }, entry_receiver)
@ -47,11 +47,11 @@ impl RecordStage {
/// Same as `RecordStage::new`, but will automatically produce entries every `tick_duration`. /// Same as `RecordStage::new`, but will automatically produce entries every `tick_duration`.
pub fn new_with_clock( pub fn new_with_clock(
signal_receiver: Receiver<Signal>, signal_receiver: Receiver<Signal>,
start_hash: &Hash, bank: Arc<Bank>,
tick_duration: Duration, tick_duration: Duration,
) -> (Self, Receiver<Vec<Entry>>) { ) -> (Self, Receiver<Vec<Entry>>) {
let (entry_sender, entry_receiver) = channel(); let (entry_sender, entry_receiver) = channel();
let start_hash = *start_hash; let start_hash = bank.last_id();
let thread_hdl = Builder::new() let thread_hdl = Builder::new()
.name("solana-record-stage".to_string()) .name("solana-record-stage".to_string())
@ -64,6 +64,7 @@ impl RecordStage {
start_time, start_time,
tick_duration, tick_duration,
&signal_receiver, &signal_receiver,
bank.clone(),
&entry_sender, &entry_sender,
).is_err() ).is_err()
{ {
@ -78,6 +79,7 @@ impl RecordStage {
fn process_signal( fn process_signal(
signal: Signal, signal: Signal,
bank: &Arc<Bank>,
recorder: &mut Recorder, recorder: &mut Recorder,
sender: &Sender<Vec<Entry>>, sender: &Sender<Vec<Entry>>,
) -> Result<(), ()> { ) -> Result<(), ()> {
@ -87,6 +89,14 @@ impl RecordStage {
vec![] vec![]
}; };
let entries = recorder.record(txs); let entries = recorder.record(txs);
for entry in entries.iter() {
if !entry.has_more {
bank.register_entry_id(&entry.id);
}
}
let entries_len = entries.len();
sender.send(entries).or(Err(()))?; sender.send(entries).or(Err(()))?;
Ok(()) Ok(())
} }
@ -94,11 +104,12 @@ impl RecordStage {
fn process_signals( fn process_signals(
recorder: &mut Recorder, recorder: &mut Recorder,
receiver: &Receiver<Signal>, receiver: &Receiver<Signal>,
bank: Arc<Bank>,
sender: &Sender<Vec<Entry>>, sender: &Sender<Vec<Entry>>,
) -> Result<(), ()> { ) -> Result<(), ()> {
loop { loop {
match receiver.recv() { match receiver.recv() {
Ok(signal) => Self::process_signal(signal, recorder, sender)?, Ok(signal) => Self::process_signal(signal, &bank, recorder, sender)?,
Err(RecvError) => return Err(()), Err(RecvError) => return Err(()),
} }
} }
@ -109,6 +120,7 @@ impl RecordStage {
start_time: Instant, start_time: Instant,
tick_duration: Duration, tick_duration: Duration,
receiver: &Receiver<Signal>, receiver: &Receiver<Signal>,
bank: Arc<Bank>,
sender: &Sender<Vec<Entry>>, sender: &Sender<Vec<Entry>>,
) -> Result<(), ()> { ) -> Result<(), ()> {
loop { loop {
@ -116,7 +128,7 @@ impl RecordStage {
sender.send(vec![entry]).or(Err(()))?; sender.send(vec![entry]).or(Err(()))?;
} }
match receiver.try_recv() { match receiver.try_recv() {
Ok(signal) => Self::process_signal(signal, recorder, sender)?, Ok(signal) => Self::process_signal(signal, &bank, recorder, sender)?,
Err(TryRecvError::Empty) => return Ok(()), Err(TryRecvError::Empty) => return Ok(()),
Err(TryRecvError::Disconnected) => return Err(()), Err(TryRecvError::Disconnected) => return Err(()),
}; };
@ -137,16 +149,21 @@ impl Service for RecordStage {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use bank::Bank;
use ledger::Block; use ledger::Block;
use mint::Mint;
use signature::{Keypair, KeypairUtil}; use signature::{Keypair, KeypairUtil};
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread::sleep; use std::thread::sleep;
#[test] #[test]
fn test_historian() { fn test_historian() {
let (tx_sender, tx_receiver) = channel(); let (tx_sender, tx_receiver) = channel();
let zero = Hash::default(); let mint = Mint::new(1234);
let (record_stage, entry_receiver) = RecordStage::new(tx_receiver, &zero); let bank = Arc::new(Bank::new(&mint));
let zero = bank.last_id();
let (record_stage, entry_receiver) = RecordStage::new(tx_receiver, bank);
tx_sender.send(Signal::Tick).unwrap(); tx_sender.send(Signal::Tick).unwrap();
sleep(Duration::new(0, 1_000_000)); sleep(Duration::new(0, 1_000_000));
@ -171,8 +188,10 @@ mod tests {
#[test] #[test]
fn test_historian_closed_sender() { fn test_historian_closed_sender() {
let (tx_sender, tx_receiver) = channel(); let (tx_sender, tx_receiver) = channel();
let zero = Hash::default(); let mint = Mint::new(1234);
let (record_stage, entry_receiver) = RecordStage::new(tx_receiver, &zero); let bank = Arc::new(Bank::new(&mint));
let zero = bank.last_id();
let (record_stage, entry_receiver) = RecordStage::new(tx_receiver, bank);
drop(entry_receiver); drop(entry_receiver);
tx_sender.send(Signal::Tick).unwrap(); tx_sender.send(Signal::Tick).unwrap();
assert_eq!(record_stage.thread_hdl.join().unwrap(), ()); assert_eq!(record_stage.thread_hdl.join().unwrap(), ());
@ -181,8 +200,10 @@ mod tests {
#[test] #[test]
fn test_transactions() { fn test_transactions() {
let (tx_sender, signal_receiver) = channel(); let (tx_sender, signal_receiver) = channel();
let zero = Hash::default(); let mint = Mint::new(1234);
let (_record_stage, entry_receiver) = RecordStage::new(signal_receiver, &zero); let bank = Arc::new(Bank::new(&mint));
let zero = bank.last_id();
let (_record_stage, entry_receiver) = RecordStage::new(signal_receiver, bank);
let alice_keypair = Keypair::new(); let alice_keypair = Keypair::new();
let bob_pubkey = Keypair::new().pubkey(); let bob_pubkey = Keypair::new().pubkey();
let tx0 = Transaction::new(&alice_keypair, bob_pubkey, 1, zero); let tx0 = Transaction::new(&alice_keypair, bob_pubkey, 1, zero);
@ -198,9 +219,11 @@ mod tests {
#[test] #[test]
fn test_clock() { fn test_clock() {
let (tx_sender, tx_receiver) = channel(); let (tx_sender, tx_receiver) = channel();
let zero = Hash::default(); let mint = Mint::new(1234);
let bank = Arc::new(Bank::new(&mint));
let zero = bank.last_id();
let (_record_stage, entry_receiver) = let (_record_stage, entry_receiver) =
RecordStage::new_with_clock(tx_receiver, &zero, Duration::from_millis(20)); RecordStage::new_with_clock(tx_receiver, bank, Duration::from_millis(20));
sleep(Duration::from_millis(900)); sleep(Duration::from_millis(900));
tx_sender.send(Signal::Tick).unwrap(); tx_sender.send(Signal::Tick).unwrap();
drop(tx_sender); drop(tx_sender);

View File

@ -75,9 +75,9 @@ impl Tpu {
let (record_stage, entry_receiver) = match tick_duration { let (record_stage, entry_receiver) = match tick_duration {
Some(tick_duration) => { Some(tick_duration) => {
RecordStage::new_with_clock(signal_receiver, &bank.last_id(), tick_duration) RecordStage::new_with_clock(signal_receiver, bank.clone(), tick_duration)
} }
None => RecordStage::new(signal_receiver, &bank.last_id()), None => RecordStage::new(signal_receiver, bank.clone()),
}; };
let (write_stage, blob_receiver) = WriteStage::new( let (write_stage, blob_receiver) = WriteStage::new(

View File

@ -30,7 +30,6 @@ impl WriteStage {
/// continuosly broadcast blobs of entries out /// continuosly broadcast blobs of entries out
pub fn write_and_send_entries( pub fn write_and_send_entries(
crdt: &Arc<RwLock<Crdt>>, crdt: &Arc<RwLock<Crdt>>,
bank: &Arc<Bank>,
ledger_writer: &mut LedgerWriter, ledger_writer: &mut LedgerWriter,
blob_sender: &BlobSender, blob_sender: &BlobSender,
blob_recycler: &BlobRecycler, blob_recycler: &BlobRecycler,
@ -43,11 +42,7 @@ impl WriteStage {
ledger_writer.write_entries(entries.clone())?; ledger_writer.write_entries(entries.clone())?;
for entry in &entries { inc_new_counter_info!("write_stage-write_entries", entries.len());
if !entry.has_more {
bank.register_entry_id(&entry.id);
}
}
//TODO(anatoly): real stake based voting needs to change this //TODO(anatoly): real stake based voting needs to change this
//leader simply votes if the current set of validators have voted //leader simply votes if the current set of validators have voted
@ -94,7 +89,6 @@ impl WriteStage {
loop { loop {
if let Err(e) = Self::write_and_send_entries( if let Err(e) = Self::write_and_send_entries(
&crdt, &crdt,
&bank,
&mut ledger_writer, &mut ledger_writer,
&blob_sender, &blob_sender,
&blob_recycler, &blob_recycler,