Skip to content

Commit

Permalink
Stats
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-near committed Nov 4, 2023
1 parent 8fe8da5 commit 6220e84
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 25 deletions.
5 changes: 3 additions & 2 deletions chain/chain/src/flat_storage_creator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl FlatStorageShardCreator {
result_sender: Sender<u64>,
) {
let trie_storage = TrieDBStorage::new(store.clone(), shard_uid);
let trie = Trie::new(Rc::new(trie_storage), state_root, None);
let trie = Trie::new(Rc::new(trie_storage), state_root, None, shard_uid.shard_id());
let path_begin = trie.find_state_part_boundary(part_id.idx, part_id.total).unwrap();
let path_end = trie.find_state_part_boundary(part_id.idx + 1, part_id.total).unwrap();
let hex_path_begin = Self::nibbles_to_hex(&path_begin);
Expand Down Expand Up @@ -198,7 +198,8 @@ impl FlatStorageShardCreator {
let trie_storage = TrieDBStorage::new(store, shard_uid);
let state_root =
*chain_store.get_chunk_extra(&block_hash, &shard_uid)?.state_root();
let trie = Trie::new(Rc::new(trie_storage), state_root, None);
let trie =
Trie::new(Rc::new(trie_storage), state_root, None, shard_uid.shard_id());
let root_node = trie.retrieve_root_node().unwrap();
let num_state_parts =
root_node.memory_usage / STATE_PART_MEMORY_LIMIT.as_u64() + 1;
Expand Down
81 changes: 81 additions & 0 deletions core/store/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,87 @@ pub static CHUNK_CACHE_HITS: Lazy<IntCounterVec> = Lazy::new(|| {
.unwrap()
});

pub static NUM_MEMTRIE_LOOKUPS: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_memtrie_lookups",
"Number of memtrie lookups",
&["shard_id"],
)
.unwrap()
});

pub static NUM_MEMTRIE_LOOKUPS_WITH_INLINED_VALUE: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_memtrie_lookups_with_inlined_value",
"Number of memtrie lookups with inlined value",
&["shard_id"],
)
.unwrap()
});

pub static NUM_FLAT_STORAGE_LOOKUPS: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_flat_storage_lookups",
"Number of flat storage lookups",
&["shard_id"],
)
.unwrap()
});

pub static NUM_ON_DISK_TRIE_LOOKUPS: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_on_disk_trie_lookups",
"Number of on-disk trie lookups",
&["shard_id"],
)
.unwrap()
});

pub static NUM_FLAT_LOOKUPS_WITH_INLINED_VALUE: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_flat_lookups_with_inlined_value",
"Number of flat storage lookups with inlined value",
&["shard_id"],
)
.unwrap()
});

pub static NUM_TRIE_DEREFS_WITH_INLINED_VALUE: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_trie_derefs_with_inlined_value",
"Number of trie derefs with inlined value",
&["shard_id"],
)
.unwrap()
});

pub static NUM_TRIE_DEREFS_REQUIRING_ON_DISK_LOOKUP: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_trie_derefs_requiring_on_disk_lookup",
"Number of trie derefs requiring on-disk lookup",
&["shard_id"],
)
.unwrap()
});

pub static NUM_CALLS_TO_TRIE_GET: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_calls_to_trie_get",
"Number of calls to trie get",
&["shard_id"],
)
.unwrap()
});

pub static NUM_CALLS_TO_TRIE_GET_OPTIMIZED_REF: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"near_num_calls_to_trie_get_optimized_ref",
"Number of calls to trie get optimized ref",
&["shard_id"],
)
.unwrap()
});

// TODO(#9054): Rename the metric to be consistent with "accounting cache".
pub static CHUNK_CACHE_MISSES: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
Expand Down
76 changes: 71 additions & 5 deletions core/store/src/trie/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub use crate::trie::trie_storage::{TrieCache, TrieCachingStorage, TrieDBStorage
use crate::StorageError;
use borsh::{BorshDeserialize, BorshSerialize};
pub use from_flat::construct_trie_from_flat;
use near_o11y::metrics::prometheus;
use near_o11y::metrics::prometheus::core::GenericCounter;
use near_primitives::challenge::PartialState;
use near_primitives::hash::{hash, CryptoHash};
pub use near_primitives::shard_layout::ShardUId;
Expand All @@ -27,7 +29,7 @@ use near_primitives::state_record::StateRecord;
use near_primitives::trie_key::trie_key_parsers::parse_account_id_prefix;
use near_primitives::trie_key::TrieKey;
pub use near_primitives::types::TrieNodesCount;
use near_primitives::types::{AccountId, StateRoot, StateRootNode};
use near_primitives::types::{AccountId, ShardId, StateRoot, StateRootNode};
use near_vm_runner::ContractCode;
pub use raw_node::{Children, RawTrieNode, RawTrieNodeWithSize};
use std::cell::RefCell;
Expand Down Expand Up @@ -354,6 +356,49 @@ pub struct Trie {
/// what, and lookups done via get_ref with `KeyLookupMode::Trie` will
/// also charge gas no matter what.
charge_gas_for_trie_node_access: bool,

shard_id: ShardId,
metrics: TrieMetrics,
}

struct TrieMetrics {
memtrie_lookups: GenericCounter<prometheus::core::AtomicU64>,
memtrie_lookups_with_inlined_value: GenericCounter<prometheus::core::AtomicU64>,
flat_storage_lookups: GenericCounter<prometheus::core::AtomicU64>,
on_disk_trie_lookups: GenericCounter<prometheus::core::AtomicU64>,
flat_lookups_with_inlined_value: GenericCounter<prometheus::core::AtomicU64>,
trie_derefs_with_inlined_value: GenericCounter<prometheus::core::AtomicU64>,
trie_derefs_requiring_on_disk_lookup: GenericCounter<prometheus::core::AtomicU64>,
calls_to_trie_get: GenericCounter<prometheus::core::AtomicU64>,
calls_to_trie_get_optimized_ref: GenericCounter<prometheus::core::AtomicU64>,
}

impl TrieMetrics {
fn new(shard_id: ShardId) -> Self {
let shard_id_str = shard_id.to_string();
let metrics_labels = [shard_id_str.as_str()];
Self {
memtrie_lookups: crate::metrics::NUM_MEMTRIE_LOOKUPS.with_label_values(&metrics_labels),
memtrie_lookups_with_inlined_value:
crate::metrics::NUM_MEMTRIE_LOOKUPS_WITH_INLINED_VALUE
.with_label_values(&metrics_labels),
flat_storage_lookups: crate::metrics::NUM_FLAT_STORAGE_LOOKUPS
.with_label_values(&metrics_labels),
on_disk_trie_lookups: crate::metrics::NUM_ON_DISK_TRIE_LOOKUPS
.with_label_values(&metrics_labels),
flat_lookups_with_inlined_value: crate::metrics::NUM_FLAT_LOOKUPS_WITH_INLINED_VALUE
.with_label_values(&metrics_labels),
trie_derefs_with_inlined_value: crate::metrics::NUM_TRIE_DEREFS_WITH_INLINED_VALUE
.with_label_values(&metrics_labels),
trie_derefs_requiring_on_disk_lookup:
crate::metrics::NUM_TRIE_DEREFS_REQUIRING_ON_DISK_LOOKUP
.with_label_values(&metrics_labels),
calls_to_trie_get: crate::metrics::NUM_CALLS_TO_TRIE_GET
.with_label_values(&metrics_labels),
calls_to_trie_get_optimized_ref: crate::metrics::NUM_CALLS_TO_TRIE_GET_OPTIMIZED_REF
.with_label_values(&metrics_labels),
}
}
}

/// Trait for reading data from a trie.
Expand Down Expand Up @@ -621,15 +666,17 @@ impl Trie {
storage: Rc<dyn TrieStorage>,
root: StateRoot,
flat_storage_chunk_view: Option<FlatStorageChunkView>,
shard_id: ShardId,
) -> Self {
Self::new_with_memtries(storage, None, root, flat_storage_chunk_view)
Self::new_with_memtries(storage, None, root, flat_storage_chunk_view, shard_id)
}

pub fn new_with_memtries(
storage: Rc<dyn TrieStorage>,
memtries: Option<Arc<RwLock<MemTries>>>,
root: StateRoot,
flat_storage_chunk_view: Option<FlatStorageChunkView>,
shard_id: ShardId,
) -> Self {
let accounting_cache = match storage.as_caching_storage() {
Some(caching_storage) => RefCell::new(TrieAccountingCache::new(Some((
Expand All @@ -646,6 +693,8 @@ impl Trie {
flat_storage_chunk_view,
accounting_cache,
recorder: None,
shard_id,
metrics: TrieMetrics::new(shard_id),
}
}

Expand All @@ -657,6 +706,7 @@ impl Trie {
self.memtries.clone(),
self.root,
self.flat_storage_chunk_view.clone(),
self.shard_id,
);
trie.recorder = Some(RefCell::new(TrieRecorder::new()));
trie
Expand All @@ -679,11 +729,12 @@ impl Trie {
partial_storage: PartialStorage,
root: StateRoot,
flat_storage_used: bool,
shard_id: ShardId,
) -> Self {
let PartialState::TrieValues(nodes) = partial_storage.nodes;
let recorded_storage = nodes.into_iter().map(|value| (hash(&value), value)).collect();
let storage = Rc::new(TrieMemoryPartialStorage::new(recorded_storage));
let mut trie = Self::new(storage, root, None);
let mut trie = Self::new(storage, root, None, shard_id);
trie.charge_gas_for_trie_node_access = !flat_storage_used;
trie
}
Expand Down Expand Up @@ -1164,6 +1215,7 @@ impl Trie {
&self,
key: &[u8],
) -> Result<Option<OptimizedValueRef>, StorageError> {
self.metrics.flat_storage_lookups.inc();
let flat_storage_chunk_view = self.flat_storage_chunk_view.as_ref().unwrap();
let value = flat_storage_chunk_view.get_value(key)?;
if self.recorder.is_some() {
Expand All @@ -1176,6 +1228,9 @@ impl Trie {
&value.as_ref().map(|value| value.to_value_ref())
);
}
if let Some(FlatStateValue::Inlined(_)) = &value {
self.metrics.flat_lookups_with_inlined_value.inc();
}
Ok(value.map(OptimizedValueRef::from_flat_value))
}

Expand All @@ -1190,6 +1245,7 @@ impl Trie {
mut key: NibbleSlice<'_>,
charge_gas_for_trie_node_access: bool,
) -> Result<Option<ValueRef>, StorageError> {
self.metrics.on_disk_trie_lookups.inc();
let mut hash = self.root;
loop {
let node = match self.retrieve_raw_node(&hash, charge_gas_for_trie_node_access)? {
Expand Down Expand Up @@ -1261,6 +1317,7 @@ impl Trie {
key: &[u8],
charge_gas_for_trie_node_access: bool,
) -> Result<Option<OptimizedValueRef>, StorageError> {
self.metrics.memtrie_lookups.inc();
if self.root == Self::EMPTY_ROOT {
return Ok(None);
}
Expand All @@ -1286,6 +1343,9 @@ impl Trie {
recorder.borrow_mut().record(&node_hash, serialized_node);
}
}
if let Some(FlatStateValue::Inlined(_)) = &result {
self.metrics.memtrie_lookups_with_inlined_value.inc();
}
Ok(result.map(OptimizedValueRef::from_flat_value))
}

Expand Down Expand Up @@ -1379,6 +1439,7 @@ impl Trie {
key: &[u8],
mode: KeyLookupMode,
) -> Result<Option<OptimizedValueRef>, StorageError> {
self.metrics.calls_to_trie_get_optimized_ref.inc();
let charge_gas_for_trie_node_access =
mode == KeyLookupMode::Trie || self.charge_gas_for_trie_node_access;
if self.memtries.is_some() {
Expand All @@ -1404,8 +1465,12 @@ impl Trie {
optimized_value_ref: &OptimizedValueRef,
) -> Result<Vec<u8>, StorageError> {
match optimized_value_ref {
OptimizedValueRef::Ref(value_ref) => self.retrieve_value(&value_ref.hash),
OptimizedValueRef::Ref(value_ref) => {
self.metrics.trie_derefs_requiring_on_disk_lookup.inc();
self.retrieve_value(&value_ref.hash)
}
OptimizedValueRef::AvailableValue(ValueAccessToken { value }) => {
self.metrics.trie_derefs_with_inlined_value.inc();
let value_hash = hash(value);
let arc_value: Arc<[u8]> = value.clone().into();
self.accounting_cache
Expand All @@ -1421,6 +1486,7 @@ impl Trie {

/// Retrieves the full value for the given key.
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, StorageError> {
self.metrics.calls_to_trie_get.inc();
match self.get_optimized_ref(key, KeyLookupMode::FlatStorage)? {
Some(optimized_ref) => Ok(Some(self.deref_optimized(&optimized_ref)?)),
None => Ok(None),
Expand Down Expand Up @@ -1862,7 +1928,7 @@ mod tests {
trie2.get(b"horse").unwrap();
let partial_storage = trie2.recorded_storage();

let trie3 = Trie::from_recorded_storage(partial_storage.unwrap(), root, false);
let trie3 = Trie::from_recorded_storage(partial_storage.unwrap(), root, false, 0);

assert_eq!(trie3.get(b"dog"), Ok(Some(b"puppy".to_vec())));
assert_eq!(trie3.get(b"horse"), Ok(Some(b"stallion".to_vec())));
Expand Down
8 changes: 6 additions & 2 deletions core/store/src/trie/prefetching_trie_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,12 @@ impl PrefetchApi {
// Note that the constructor of `Trie` is trivial, and
// the clone only clones a few `Arc`s, so the performance
// hit is small.
let prefetcher_trie =
Trie::new(Rc::new(prefetcher_storage.clone()), trie_root, None);
let prefetcher_trie = Trie::new(
Rc::new(prefetcher_storage.clone()),
trie_root,
None,
shard_uid.shard_id(),
);
let storage_key = trie_key.to_vec();
metric_prefetch_sent.inc();
if let Ok(_maybe_value) = prefetcher_trie.get(&storage_key) {
Expand Down
4 changes: 2 additions & 2 deletions core/store/src/trie/shard_tries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl ShardTries {
));
let flat_storage_chunk_view = block_hash
.and_then(|block_hash| self.0.flat_storage_manager.chunk_view(shard_uid, block_hash));
Trie::new_with_memtries(storage, self.get_mem_tries(shard_uid), state_root, flat_storage_chunk_view)
Trie::new_with_memtries(storage, self.get_mem_tries(shard_uid), state_root, flat_storage_chunk_view, shard_uid.shard_id())
}

pub fn get_trie_for_shard(&self, shard_uid: ShardUId, state_root: StateRoot) -> Trie {
Expand All @@ -165,7 +165,7 @@ impl ShardTries {
let storage = Rc::new(TrieCachingStorage::new(store, cache, shard_uid, true, None));
let flat_storage_chunk_view = flat_storage_manager.chunk_view(shard_uid, *block_hash);

Ok(Trie::new(storage, state_root, flat_storage_chunk_view))
Ok(Trie::new(storage, state_root, flat_storage_chunk_view, shard_uid.shard_id()))
}

pub fn get_trie_with_block_hash_for_shard(
Expand Down
16 changes: 11 additions & 5 deletions core/store/src/trie/state_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,12 @@ impl Trie {
let local_trie_creation_timer = metrics::GET_STATE_PART_CREATE_TRIE_ELAPSED
.with_label_values(&[&shard_id.to_string()])
.start_timer();
let local_state_part_trie =
Trie::new(Rc::new(TrieMemoryPartialStorage::default()), StateRoot::new(), None);
let local_state_part_trie = Trie::new(
Rc::new(TrieMemoryPartialStorage::default()),
StateRoot::new(),
None,
shard_id,
);
let local_state_part_nodes =
local_state_part_trie.update(all_state_part_items.into_iter())?.insertions;
let local_trie_creation_duration = local_trie_creation_timer.stop_and_record();
Expand All @@ -264,7 +268,7 @@ impl Trie {
.map(|entry| (*entry.hash(), entry.payload().to_vec().into())),
);
let final_trie =
Trie::new(Rc::new(TrieMemoryPartialStorage::new(all_nodes)), self.root, None);
Trie::new(Rc::new(TrieMemoryPartialStorage::new(all_nodes)), self.root, None, shard_id);

final_trie.visit_nodes_for_state_part(part_id)?;
let final_trie_storage = final_trie.storage.as_partial_storage().unwrap();
Expand Down Expand Up @@ -429,6 +433,7 @@ impl Trie {
PartialStorage { nodes: partial_state },
*state_root,
false,
0,
);

trie.visit_nodes_for_state_part(part_id)?;
Expand All @@ -454,7 +459,8 @@ impl Trie {
contract_codes: vec![],
});
}
let trie = Trie::from_recorded_storage(PartialStorage { nodes: part }, *state_root, false);
let trie =
Trie::from_recorded_storage(PartialStorage { nodes: part }, *state_root, false, 0);
let path_begin = trie.find_state_part_boundary(part_id.idx, part_id.total)?;
let path_end = trie.find_state_part_boundary(part_id.idx + 1, part_id.total)?;
let mut iterator = trie.iter()?;
Expand Down Expand Up @@ -621,7 +627,7 @@ mod tests {
.cloned()
.collect(),
);
let trie = Trie::from_recorded_storage(PartialStorage { nodes }, *state_root, false);
let trie = Trie::from_recorded_storage(PartialStorage { nodes }, *state_root, false, 0);
let mut insertions = <HashMap<CryptoHash, (Vec<u8>, u32)>>::new();
trie.traverse_all_nodes(|hash| {
if let Some((_bytes, rc)) = insertions.get_mut(hash) {
Expand Down
Loading

0 comments on commit 6220e84

Please sign in to comment.