Skip to content

Commit 4c994c5

Browse files
committed
starknet_committer: add storage benchmark timing in commit_block
1 parent 6929281 commit 4c994c5

File tree

3 files changed

+117
-48
lines changed

3 files changed

+117
-48
lines changed

crates/starknet_committer/src/block_committer/commit.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::block_committer::input::{
1313
Input,
1414
StateDiff,
1515
};
16+
use crate::block_committer::timing_util::{Action, TimeMeasurement};
1617
use crate::forest::filled_forest::FilledForest;
1718
use crate::forest::original_skeleton_forest::{ForestSortedIndices, OriginalSkeletonForest};
1819
use crate::forest::updated_skeleton_forest::UpdatedSkeletonForest;
@@ -25,6 +26,7 @@ type BlockCommitmentResult<T> = Result<T, BlockCommitmentError>;
2526
pub async fn commit_block<S: Storage>(
2627
input: Input<ConfigImpl>,
2728
storage: &mut S,
29+
#[cfg(feature = "benchmark")] time_measurement: &mut TimeMeasurement,
2830
) -> BlockCommitmentResult<FilledForest> {
2931
let (mut storage_tries_indices, mut contracts_trie_indices, mut classes_trie_indices) =
3032
get_all_modified_indices(&input.state_diff);
@@ -38,6 +40,9 @@ pub async fn commit_block<S: Storage>(
3840
};
3941
let actual_storage_updates = input.state_diff.actual_storage_updates();
4042
let actual_classes_updates = input.state_diff.actual_classes_updates();
43+
// Reads - fetch_nodes.
44+
#[cfg(feature = "benchmark")]
45+
time_measurement.start_measurement(Action::Read);
4146
let (mut original_forest, original_contracts_trie_leaves) = OriginalSkeletonForest::create(
4247
storage,
4348
input.contracts_trie_root_hash,
@@ -47,6 +52,9 @@ pub async fn commit_block<S: Storage>(
4752
&forest_sorted_indices,
4853
&input.config,
4954
)?;
55+
let n_read_facts = original_forest.storage_tries.values().map(|trie| trie.nodes.len()).sum();
56+
#[cfg(feature = "benchmark")]
57+
time_measurement.stop_measurement(Some(n_read_facts), Action::Read);
5058
info!("Original skeleton forest created successfully.");
5159

5260
if input.config.warn_on_trivial_modifications() {
@@ -57,6 +65,9 @@ pub async fn commit_block<S: Storage>(
5765
);
5866
}
5967

68+
// Compute the new topology.
69+
#[cfg(feature = "benchmark")]
70+
time_measurement.start_measurement(Action::Compute);
6071
let updated_forest = UpdatedSkeletonForest::create(
6172
&mut original_forest,
6273
&input.state_diff.skeleton_classes_updates(),
@@ -67,6 +78,7 @@ pub async fn commit_block<S: Storage>(
6778
)?;
6879
info!("Updated skeleton forest created successfully.");
6980

81+
// Compute the new hashes.
7082
let filled_forest = FilledForest::create::<TreeHashFunctionImpl>(
7183
updated_forest,
7284
actual_storage_updates,
@@ -76,6 +88,8 @@ pub async fn commit_block<S: Storage>(
7688
&input.state_diff.address_to_nonce,
7789
)
7890
.await?;
91+
#[cfg(feature = "benchmark")]
92+
time_measurement.stop_measurement(None, Action::Compute);
7993
info!("Filled forest created successfully.");
8094

8195
Ok(filled_forest)

crates/starknet_committer/src/block_committer/timing_util.rs

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,103 @@ use std::time::Instant;
33

44
use csv::Writer;
55
use tracing::info;
6+
7+
use crate::block_committer::input::{ConfigImpl, Input};
8+
9+
pub type InputImpl = Input<ConfigImpl>;
10+
11+
#[derive(Debug, PartialEq, Eq)]
12+
pub enum Action {
13+
Total,
14+
Read,
15+
Compute,
16+
Write,
17+
}
18+
619
pub struct TimeMeasurement {
7-
timer: Option<Instant>,
8-
total_time: u128, // Total duration of all blocks (milliseconds).
9-
per_fact_durations: Vec<u64>, // Average duration (microseconds) per new fact in a block.
10-
n_facts: Vec<usize>,
11-
block_durations: Vec<u64>, // Duration of a block (milliseconds).
12-
facts_in_db: Vec<usize>, // Number of facts in the DB prior to the current block.
13-
total_facts: usize,
20+
pub block_timer: Option<Instant>,
21+
pub read_timer: Option<Instant>,
22+
pub compute_timer: Option<Instant>,
23+
pub writer_timer: Option<Instant>,
24+
pub total_time: u64, // Total duration of all blocks (milliseconds).
25+
pub n_new_facts: Vec<usize>,
26+
pub n_read_facts: Vec<usize>,
27+
pub block_durations: Vec<u64>, // Duration of a block (milliseconds).
28+
pub read_durations: Vec<u64>, // Duration of a read (milliseconds).
29+
pub compute_durations: Vec<u64>, // Duration of a compute (milliseconds).
30+
pub write_durations: Vec<u64>, // Duration of a write (milliseconds).
31+
pub facts_in_db: Vec<usize>, // Number of facts in the DB prior to the current block.
32+
pub block_number: usize,
33+
pub total_facts: usize,
1434
}
1535

1636
impl TimeMeasurement {
17-
pub fn new(n_iterations: usize) -> Self {
37+
pub fn new(size: usize) -> Self {
1838
Self {
19-
timer: None,
39+
block_timer: None,
40+
read_timer: None,
41+
compute_timer: None,
42+
writer_timer: None,
2043
total_time: 0,
21-
per_fact_durations: Vec::with_capacity(n_iterations),
22-
n_facts: Vec::with_capacity(n_iterations),
23-
block_durations: Vec::with_capacity(n_iterations),
24-
facts_in_db: Vec::with_capacity(n_iterations),
44+
n_new_facts: Vec::with_capacity(size),
45+
n_read_facts: Vec::with_capacity(size),
46+
read_durations: Vec::with_capacity(size),
47+
compute_durations: Vec::with_capacity(size),
48+
write_durations: Vec::with_capacity(size),
49+
block_durations: Vec::with_capacity(size),
50+
facts_in_db: Vec::with_capacity(size),
51+
block_number: 0,
2552
total_facts: 0,
2653
}
2754
}
2855

29-
pub fn start_measurement(&mut self) {
30-
self.timer = Some(Instant::now());
56+
fn get_mut_timer(&mut self, action: &Action) -> &mut Option<Instant> {
57+
match action {
58+
Action::Total => &mut self.block_timer,
59+
Action::Read => &mut self.read_timer,
60+
Action::Compute => &mut self.compute_timer,
61+
Action::Write => &mut self.writer_timer,
62+
}
3163
}
3264

33-
pub fn stop_measurement(&mut self, facts_count: usize) {
34-
let duration =
35-
self.timer.expect("stop_measurement called before start_measurement").elapsed();
65+
pub fn start_measurement(&mut self, action: Action) {
66+
*self.get_mut_timer(&action) = Some(Instant::now());
67+
}
68+
69+
/// Stop the measurement for the given action and add the duration to the corresponding vector.
70+
/// facts_count is either the number of facts read from the DB for Read action, or the number of
71+
/// new facts written to the DB for the Total action.
72+
pub fn stop_measurement(&mut self, facts_count: Option<usize>, action: Action) {
73+
let duration = self
74+
.get_mut_timer(&action)
75+
.expect("stop_measurement called before start_measurement")
76+
.elapsed();
3677
info!(
3778
"Time elapsed for iteration {}: {} milliseconds",
3879
self.n_results(),
3980
duration.as_millis()
4081
);
41-
let millis = duration.as_millis();
82+
let millis: u64 = duration.as_millis().try_into().unwrap();
83+
match action {
84+
Action::Total => {
85+
self.block_durations.push(millis);
4286
self.total_time += millis;
43-
#[allow(clippy::as_conversions)]
44-
self.per_fact_durations
45-
.push(duration.div_f32(facts_count as f32).as_micros().try_into().unwrap());
46-
self.block_durations.push(millis.try_into().unwrap());
47-
self.n_facts.push(facts_count);
87+
self.n_new_facts.push(facts_count.unwrap());
4888
self.facts_in_db.push(self.total_facts);
49-
self.total_facts += facts_count;
89+
self.total_facts += facts_count.unwrap();
90+
self.block_number += 1;
91+
}
92+
Action::Read => {
93+
self.read_durations.push(millis);
94+
self.n_read_facts.push(facts_count.unwrap());
95+
}
96+
Action::Compute => {
97+
self.compute_durations.push(millis);
98+
}
99+
Action::Write => {
100+
self.write_durations.push(millis);
101+
}
102+
}
50103
}
51104

52105
pub fn n_results(&self) -> usize {
@@ -72,7 +125,7 @@ impl TimeMeasurement {
72125
let sum: u64 =
73126
self.block_durations[window_start..window_start + window_size].iter().sum();
74127
let sum_of_facts: usize =
75-
self.n_facts[window_start..window_start + window_size].iter().sum();
128+
self.n_new_facts[window_start..window_start + window_size].iter().sum();
76129
#[allow(clippy::as_conversions)]
77130
averages.push(1000.0 * sum as f64 / sum_of_facts as f64);
78131
}
@@ -116,26 +169,26 @@ impl TimeMeasurement {
116169
let mut wtr = Writer::from_writer(file);
117170
wtr.write_record([
118171
"block_number",
119-
"n_facts",
120-
"facts_in_db",
121-
"time_per_fact_micros",
172+
"n_new_facts",
173+
"n_read_facts",
174+
"initial_facts_in_db",
122175
"block_duration_millis",
176+
"read_duration_millis",
177+
"compute_duration_millis",
178+
"write_duration_millis",
123179
])
124180
.expect("Failed to write CSV header.");
125-
for (i, (((&per_fact, &n_facts), &duration), &facts_in_db)) in self
126-
.per_fact_durations
127-
.iter()
128-
.zip(self.n_facts.iter())
129-
.zip(self.block_durations.iter())
130-
.zip(self.facts_in_db.iter())
131-
.enumerate()
132-
{
181+
let n_results = self.n_results();
182+
for i in 0..n_results {
133183
wtr.write_record(&[
134-
i.to_string(),
135-
n_facts.to_string(),
136-
facts_in_db.to_string(),
137-
per_fact.to_string(),
138-
duration.to_string(),
184+
(self.block_number - n_results + i).to_string(),
185+
self.n_new_facts[i].to_string(),
186+
self.n_read_facts[i].to_string(),
187+
self.facts_in_db[i].to_string(),
188+
self.block_durations[i].to_string(),
189+
self.read_durations[i].to_string(),
190+
self.compute_durations[i].to_string(),
191+
self.write_durations[i].to_string(),
139192
])
140193
.expect("Failed to write CSV record.");
141194
}

crates/starknet_committer_cli/src/commands.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rand::SeedableRng;
33
use starknet_committer::block_committer::commit::commit_block;
44
use starknet_committer::block_committer::input::{ConfigImpl, Input};
55
use starknet_committer::block_committer::state_diff_generator::generate_random_state_diff;
6-
use starknet_committer::block_committer::timing_util::TimeMeasurement;
6+
use starknet_committer::block_committer::timing_util::{Action, TimeMeasurement};
77
use starknet_patricia::hash::hash_trait::HashOutput;
88
use starknet_patricia_storage::map_storage::MapStorage;
99
use tracing::info;
@@ -30,13 +30,15 @@ pub async fn run_storage_benchmark(seed: u64, n_iterations: usize, output_dir: &
3030
config: ConfigImpl::default(),
3131
};
3232

33-
time_measurement.start_measurement();
34-
let filled_forest =
35-
commit_block(input, &mut storage).await.expect("Failed to commit the given block.");
36-
// TODO(Tzahi): measure the computation above and the fact writing below separately.
33+
time_measurement.start_measurement(Action::Total);
34+
let filled_forest = commit_block(input, &mut storage, &mut time_measurement)
35+
.await
36+
.expect("Failed to commit the given block.");
37+
time_measurement.start_measurement(Action::Write);
3738
let n_new_facts = filled_forest.write_to_storage(&mut storage);
39+
time_measurement.stop_measurement(None, Action::Write);
3840

39-
time_measurement.stop_measurement(n_new_facts);
41+
time_measurement.stop_measurement(Some(n_new_facts), Action::Total);
4042

4143
contracts_trie_root_hash = filled_forest.get_contract_root_hash();
4244
classes_trie_root_hash = filled_forest.get_compiled_class_root_hash();

0 commit comments

Comments
 (0)