diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index 7739fe152..894b2cece 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -748,7 +748,8 @@ impl Rocks { } fn write(&self, batch: RWriteBatch) -> Result<()> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.db.write(batch); if is_perf_context_enabled { report_write_perf_context(rocksdb_metric_header!( @@ -2001,6 +2002,11 @@ pub struct LedgerColumnOptions { // Determine the way to compress column families which are eligible for // compression. pub compression_type: BlockstoreCompressionType, + + // Control how often RocksDB read/write performance samples are collected. + // If the value is greater than 0, then RocksDB read/write perf sample + // will be collected once for every `rocks_perf_sample_interval` ops. + pub rocks_perf_sample_interval: usize, } impl Default for LedgerColumnOptions { @@ -2008,6 +2014,7 @@ impl Default for LedgerColumnOptions { Self { shred_storage_type: ShredStorageType::RocksLevel, compression_type: BlockstoreCompressionType::default(), + rocks_perf_sample_interval: 0, } } } @@ -2177,7 +2184,8 @@ where C: Column + ColumnName + ColumnMetrics, { pub fn get_bytes(&self, key: C::Index) -> Result>> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.get_cf(self.handle(), &C::key(key)); if is_perf_context_enabled { report_read_perf_context(C::rocksdb_get_perf_metric_header(&self.column_options)); @@ -2252,7 +2260,8 @@ where } pub fn put_bytes(&self, key: C::Index, value: &[u8]) -> Result<()> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.put_cf(self.handle(), &C::key(key), value); if is_perf_context_enabled { report_write_perf_context(C::rocksdb_put_perf_metric_header(&self.column_options)); @@ -2279,32 +2288,16 @@ mod rocks_metrics_utils { }, std::cell::RefCell, }; - const METRIC_SAMPLES_1K: i32 = 1000; - // The default number of rocksdb perf samples in 1K - const ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K_DEFAULT: i32 = 0; - lazy_static! { - // The number of RocksDB performance counter samples in 1000. - static ref ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K: i32 = - std::env::var("SOLANA_METRICS_ROCKSDB_PERF_SAMPLES_IN_1K") - .map(|x| { - x.parse().expect("Failed to parse SOLANA_METRICS_ROCKSDB_PERF_SAMPLES_IN_1K") - - }).unwrap_or(ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K_DEFAULT); - - } // Thread local instance of RocksDB's PerfContext. thread_local! {static PER_THREAD_ROCKS_PERF_CONTEXT: RefCell = RefCell::new(PerfContext::default());} - /// The function enables RocksDB's PerfContext in N out of 1000 - /// where N is ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K. - /// /// Returns true if the PerfContext is enabled. - pub fn maybe_collect_perf_context() -> bool { - if *ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K <= 0 { + pub(crate) fn maybe_collect_perf_context(sample_interval: usize) -> bool { + if sample_interval == 0 { return false; } - if thread_rng().gen_range(0, METRIC_SAMPLES_1K) > *ROCKSDB_PERF_CONTEXT_SAMPLES_IN_1K { + if thread_rng().gen_range(0, sample_interval) > 0 { return false; } set_perf_stats(PerfStatsLevel::EnableTime); @@ -2316,7 +2309,7 @@ mod rocks_metrics_utils { /// Reports the collected PerfContext and disables the PerfContext after /// reporting. - pub fn report_read_perf_context(metric_header: &'static str) { + pub(crate) fn report_read_perf_context(metric_header: &'static str) { PER_THREAD_ROCKS_PERF_CONTEXT.with(|perf_context_cell| { set_perf_stats(PerfStatsLevel::Disable); let perf_context = perf_context_cell.borrow(); @@ -2570,7 +2563,8 @@ where { pub fn get(&self, key: C::Index) -> Result> { let mut result = Ok(None); - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); if let Some(serialized_value) = self.backend.get_cf(self.handle(), &C::key(key))? { let value = deserialize(&serialized_value)?; @@ -2584,7 +2578,8 @@ where } pub fn put(&self, key: C::Index, value: &C::Type) -> Result<()> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let serialized_value = serialize(value)?; let result = self @@ -2598,7 +2593,8 @@ where } pub fn delete(&self, key: C::Index) -> Result<()> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.delete_cf(self.handle(), &C::key(key)); if is_perf_context_enabled { report_write_perf_context(C::rocksdb_delete_perf_metric_header(&self.column_options)); @@ -2615,7 +2611,8 @@ where &self, key: C::Index, ) -> Result> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.get_cf(self.handle(), &C::key(key)); if is_perf_context_enabled { report_read_perf_context(C::rocksdb_get_perf_metric_header(&self.column_options)); @@ -2633,7 +2630,8 @@ where } pub fn get_protobuf(&self, key: C::Index) -> Result> { - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.get_cf(self.handle(), &C::key(key)); if is_perf_context_enabled { report_read_perf_context(C::rocksdb_get_perf_metric_header(&self.column_options)); @@ -2650,7 +2648,8 @@ where let mut buf = Vec::with_capacity(value.encoded_len()); value.encode(&mut buf)?; - let is_perf_context_enabled = maybe_collect_perf_context(); + let is_perf_context_enabled = + maybe_collect_perf_context(self.column_options.rocks_perf_sample_interval); let result = self.backend.put_cf(self.handle(), &C::key(key), &buf); if is_perf_context_enabled { report_write_perf_context(C::rocksdb_put_perf_metric_header(&self.column_options)); diff --git a/validator/src/main.rs b/validator/src/main.rs index fa2ef12b0..e04e44082 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -1029,6 +1029,18 @@ pub fn main() { transaction status data. \ Turning on compression can save ~10% of the ledger size."), ) + .arg( + Arg::with_name("rocksdb_perf_sample_interval") + .hidden(true) + .long("rocksdb-perf-sample-interval") + .value_name("ROCKS_PERF_SAMPLE_INTERVAL") + .takes_value(true) + .validator(is_parsable::) + .default_value("0") + .help("Controls how often RocksDB read/write performance sample is collected. \ + Reads/writes perf samples are collected in 1 / ROCKS_PERF_SAMPLE_INTERVAL sampling rate."), + + ) .arg( Arg::with_name("skip_poh_verify") .long("skip-poh-verify") @@ -2726,6 +2738,11 @@ pub fn main() { ), }, }, + rocks_perf_sample_interval: value_t_or_exit!( + matches, + "rocksdb_perf_sample_interval", + usize + ), }; if matches.is_present("halt_on_known_validators_accounts_hash_mismatch") {