(LedgerStore) Hidden validator argument for RocksDB perf samples (#24682)
#### Problem Currently, the number of RocksDB perf samples is controlled by an env arg which is later handled using a lazy_static variable. However, there is a known performance overhead of using lazy_static as mentioned in https://github.com/solana-labs/solana/pull/6472. #### Summary of Changes Instead, this PR uses a hidden validator argument, --rocksdb-perf-sample-interval, for controlling how often RocksDB read/write performance sample is collected.
This commit is contained in:
parent
cb501807ca
commit
b56c091b37
|
@ -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<Option<Vec<u8>>> {
|
||||
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<PerfContext> = 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<Option<C::Type>> {
|
||||
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<Option<C::Type>> {
|
||||
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<Option<C::Type>> {
|
||||
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));
|
||||
|
|
|
@ -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::<usize>)
|
||||
.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") {
|
||||
|
|
Loading…
Reference in New Issue