1use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
22
23pub struct StateUsageStats {
25 started: std::time::Instant,
26 reads: AtomicU64,
27 bytes_read: AtomicU64,
28 writes: AtomicU64,
29 bytes_written: AtomicU64,
30 writes_nodes: AtomicU64,
31 bytes_written_nodes: AtomicU64,
32 removed_nodes: AtomicU64,
33 bytes_removed_nodes: AtomicU64,
34 reads_cache: AtomicU64,
35 bytes_read_cache: AtomicU64,
36}
37
38impl StateUsageStats {
39 pub fn new() -> Self {
41 Self {
42 started: std::time::Instant::now(),
43 reads: 0.into(),
44 bytes_read: 0.into(),
45 writes: 0.into(),
46 bytes_written: 0.into(),
47 writes_nodes: 0.into(),
48 bytes_written_nodes: 0.into(),
49 removed_nodes: 0.into(),
50 bytes_removed_nodes: 0.into(),
51 reads_cache: 0.into(),
52 bytes_read_cache: 0.into(),
53 }
54 }
55
56 pub fn tally_read(&self, data_bytes: u64, cache: bool) {
58 self.reads.fetch_add(1, AtomicOrdering::Relaxed);
59 self.bytes_read.fetch_add(data_bytes, AtomicOrdering::Relaxed);
60 if cache {
61 self.reads_cache.fetch_add(1, AtomicOrdering::Relaxed);
62 self.bytes_read_cache.fetch_add(data_bytes, AtomicOrdering::Relaxed);
63 }
64 }
65
66 pub fn tally_key_read(&self, key: &[u8], val: Option<&Vec<u8>>, cache: bool) {
68 self.tally_read(
69 key.len() as u64 + val.as_ref().map(|x| x.len() as u64).unwrap_or(0),
70 cache,
71 );
72 }
73
74 pub fn tally_child_key_read(
76 &self,
77 key: &(Vec<u8>, Vec<u8>),
78 val: Option<Vec<u8>>,
79 cache: bool,
80 ) -> Option<Vec<u8>> {
81 let bytes = key.0.len() + key.1.len() + val.as_ref().map(|x| x.len()).unwrap_or(0);
82 self.tally_read(bytes as u64, cache);
83 val
84 }
85
86 pub fn tally_writes_nodes(&self, ops: u64, data_bytes: u64) {
88 self.writes_nodes.fetch_add(ops, AtomicOrdering::Relaxed);
89 self.bytes_written_nodes.fetch_add(data_bytes, AtomicOrdering::Relaxed);
90 }
91
92 pub fn tally_removed_nodes(&self, ops: u64, data_bytes: u64) {
94 self.removed_nodes.fetch_add(ops, AtomicOrdering::Relaxed);
95 self.bytes_removed_nodes.fetch_add(data_bytes, AtomicOrdering::Relaxed);
96 }
97
98 pub fn tally_writes(&self, ops: u64, data_bytes: u64) {
100 self.writes.fetch_add(ops, AtomicOrdering::Relaxed);
101 self.bytes_written.fetch_add(data_bytes, AtomicOrdering::Relaxed);
102 }
103
104 pub fn merge_sm(&self, info: sp_state_machine::UsageInfo) {
106 self.reads.fetch_add(info.reads.ops, AtomicOrdering::Relaxed);
107 self.bytes_read.fetch_add(info.reads.bytes, AtomicOrdering::Relaxed);
108 self.writes_nodes.fetch_add(info.nodes_writes.ops, AtomicOrdering::Relaxed);
109 self.bytes_written_nodes
110 .fetch_add(info.nodes_writes.bytes, AtomicOrdering::Relaxed);
111 self.removed_nodes.fetch_add(info.removed_nodes.ops, AtomicOrdering::Relaxed);
112 self.bytes_removed_nodes
113 .fetch_add(info.removed_nodes.bytes, AtomicOrdering::Relaxed);
114 self.reads_cache.fetch_add(info.cache_reads.ops, AtomicOrdering::Relaxed);
115 self.bytes_read_cache.fetch_add(info.cache_reads.bytes, AtomicOrdering::Relaxed);
116 }
117
118 pub fn take(&self) -> sp_state_machine::UsageInfo {
120 use sp_state_machine::UsageUnit;
121
122 fn unit(ops: &AtomicU64, bytes: &AtomicU64) -> UsageUnit {
123 UsageUnit {
124 ops: ops.swap(0, AtomicOrdering::Relaxed),
125 bytes: bytes.swap(0, AtomicOrdering::Relaxed),
126 }
127 }
128
129 sp_state_machine::UsageInfo {
130 reads: unit(&self.reads, &self.bytes_read),
131 writes: unit(&self.writes, &self.bytes_written),
132 nodes_writes: unit(&self.writes_nodes, &self.bytes_written_nodes),
133 removed_nodes: unit(&self.removed_nodes, &self.bytes_removed_nodes),
134 cache_reads: unit(&self.reads_cache, &self.bytes_read_cache),
135 modified_reads: Default::default(),
136 overlay_writes: Default::default(),
137 memory: 0,
141 started: self.started,
142 span: self.started.elapsed(),
143 }
144 }
145}