2021-12-03 09:00:31 -08:00
|
|
|
use {
|
2023-01-12 19:14:04 -08:00
|
|
|
solana_ledger::{blockstore::Blockstore, blockstore_meta::PerfSampleV2},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_runtime::bank_forks::BankForks,
|
|
|
|
std::{
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc, RwLock,
|
|
|
|
},
|
|
|
|
thread::{self, sleep, Builder, JoinHandle},
|
|
|
|
time::{Duration, Instant},
|
2020-09-22 12:26:32 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const SAMPLE_INTERVAL: u64 = 60;
|
|
|
|
const SLEEP_INTERVAL: u64 = 500;
|
|
|
|
|
|
|
|
pub struct SamplePerformanceService {
|
|
|
|
thread_hdl: JoinHandle<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SamplePerformanceService {
|
|
|
|
pub fn new(
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2023-08-03 14:10:25 -07:00
|
|
|
blockstore: Arc<Blockstore>,
|
2023-06-01 17:25:48 -07:00
|
|
|
exit: Arc<AtomicBool>,
|
2020-09-22 12:26:32 -07:00
|
|
|
) -> Self {
|
|
|
|
let bank_forks = bank_forks.clone();
|
|
|
|
|
|
|
|
info!("Starting SamplePerformance service");
|
|
|
|
let thread_hdl = Builder::new()
|
|
|
|
.name("sample-performance".to_string())
|
|
|
|
.spawn(move || {
|
2023-02-14 19:01:23 -08:00
|
|
|
Self::run(bank_forks, blockstore, exit);
|
2020-09-22 12:26:32 -07:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
Self { thread_hdl }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2023-02-14 19:01:23 -08:00
|
|
|
blockstore: Arc<Blockstore>,
|
2020-09-22 12:26:32 -07:00
|
|
|
exit: Arc<AtomicBool>,
|
|
|
|
) {
|
2023-02-14 19:01:23 -08:00
|
|
|
let mut snapshot = StatsSnapshot::from_forks(&bank_forks);
|
2020-09-22 12:26:32 -07:00
|
|
|
|
|
|
|
let mut now = Instant::now();
|
|
|
|
loop {
|
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let elapsed = now.elapsed();
|
|
|
|
|
|
|
|
if elapsed.as_secs() >= SAMPLE_INTERVAL {
|
|
|
|
now = Instant::now();
|
2023-02-14 19:01:23 -08:00
|
|
|
let new_snapshot = StatsSnapshot::from_forks(&bank_forks);
|
|
|
|
|
|
|
|
let (num_transactions, num_non_vote_transactions, num_slots) =
|
|
|
|
new_snapshot.diff_since(&snapshot);
|
2023-01-12 19:14:04 -08:00
|
|
|
|
2023-02-14 19:01:23 -08:00
|
|
|
// Store the new snapshot to compare against in the next iteration of the loop.
|
|
|
|
snapshot = new_snapshot;
|
2023-01-12 19:14:04 -08:00
|
|
|
|
|
|
|
let perf_sample = PerfSampleV2 {
|
2023-02-15 09:02:53 -08:00
|
|
|
// Note: since num_slots is computed from the highest slot and not the bank
|
|
|
|
// slot, this value should not be used in conjunction with num_transactions or
|
|
|
|
// num_non_vote_transactions to draw any conclusions about number of
|
|
|
|
// transactions per slot.
|
2023-01-12 19:14:04 -08:00
|
|
|
num_slots,
|
|
|
|
num_transactions,
|
|
|
|
num_non_vote_transactions,
|
2020-09-22 12:26:32 -07:00
|
|
|
sample_period_secs: elapsed.as_secs() as u16,
|
|
|
|
};
|
|
|
|
|
2023-02-14 19:01:23 -08:00
|
|
|
let highest_slot = snapshot.highest_slot;
|
2020-09-22 12:26:32 -07:00
|
|
|
if let Err(e) = blockstore.write_perf_sample(highest_slot, &perf_sample) {
|
|
|
|
error!("write_perf_sample failed: slot {:?} {:?}", highest_slot, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sleep(Duration::from_millis(SLEEP_INTERVAL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn join(self) -> thread::Result<()> {
|
|
|
|
self.thread_hdl.join()
|
|
|
|
}
|
|
|
|
}
|
2023-02-14 19:01:23 -08:00
|
|
|
|
|
|
|
struct StatsSnapshot {
|
|
|
|
pub num_transactions: u64,
|
|
|
|
pub num_non_vote_transactions: u64,
|
|
|
|
pub highest_slot: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StatsSnapshot {
|
|
|
|
fn from_forks(forks: &RwLock<BankForks>) -> Self {
|
|
|
|
let forks = forks.read().unwrap();
|
|
|
|
let bank = forks.root_bank();
|
|
|
|
Self {
|
|
|
|
num_transactions: bank.transaction_count(),
|
|
|
|
num_non_vote_transactions: bank.non_vote_transaction_count_since_restart(),
|
|
|
|
highest_slot: forks.highest_slot(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn diff_since(&self, predecessor: &Self) -> (u64, u64, u64) {
|
|
|
|
(
|
|
|
|
self.num_transactions
|
|
|
|
.saturating_sub(predecessor.num_transactions),
|
|
|
|
self.num_non_vote_transactions
|
|
|
|
.saturating_sub(predecessor.num_non_vote_transactions),
|
|
|
|
self.highest_slot.saturating_sub(predecessor.highest_slot),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|