|
1 |
| -use std::fs::{self, File}; |
2 |
| -use std::time::Instant; |
3 |
| - |
4 |
| -use csv::Writer; |
5 | 1 | use rand::rngs::SmallRng;
|
6 | 2 | use rand::SeedableRng;
|
7 | 3 | use starknet_committer::block_committer::commit::commit_block;
|
8 | 4 | use starknet_committer::block_committer::input::{ConfigImpl, Input};
|
9 | 5 | use starknet_committer::block_committer::state_diff_generator::generate_random_state_diff;
|
| 6 | +use starknet_committer::block_committer::timing_util::TimeMeasurement; |
10 | 7 | use starknet_patricia::hash::hash_trait::HashOutput;
|
11 | 8 | use starknet_patricia_storage::map_storage::MapStorage;
|
12 | 9 | use tracing::info;
|
13 | 10 |
|
14 | 11 | pub type InputImpl = Input<ConfigImpl>;
|
15 | 12 |
|
16 |
| -struct TimeMeasurement { |
17 |
| - timer: Option<Instant>, |
18 |
| - total_time: u128, // Total duration of all blocks (milliseconds). |
19 |
| - per_fact_durations: Vec<u64>, // Average duration (microseconds) per new fact in a block. |
20 |
| - n_facts: Vec<usize>, |
21 |
| - block_durations: Vec<u64>, // Duration of a block (milliseconds). |
22 |
| - facts_in_db: Vec<usize>, // Number of facts in the DB prior to the current block. |
23 |
| - total_facts: usize, |
24 |
| -} |
25 |
| - |
26 |
| -impl TimeMeasurement { |
27 |
| - fn new(n_iterations: usize) -> Self { |
28 |
| - Self { |
29 |
| - timer: None, |
30 |
| - total_time: 0, |
31 |
| - per_fact_durations: Vec::with_capacity(n_iterations), |
32 |
| - n_facts: Vec::with_capacity(n_iterations), |
33 |
| - block_durations: Vec::with_capacity(n_iterations), |
34 |
| - facts_in_db: Vec::with_capacity(n_iterations), |
35 |
| - total_facts: 0, |
36 |
| - } |
37 |
| - } |
38 |
| - |
39 |
| - fn start_measurement(&mut self) { |
40 |
| - self.timer = Some(Instant::now()); |
41 |
| - } |
42 |
| - |
43 |
| - fn stop_measurement(&mut self, facts_count: usize) { |
44 |
| - let duration = |
45 |
| - self.timer.expect("stop_measurement called before start_measurement").elapsed(); |
46 |
| - info!( |
47 |
| - "Time elapsed for iteration {}: {} milliseconds", |
48 |
| - self.n_results(), |
49 |
| - duration.as_millis() |
50 |
| - ); |
51 |
| - let millis = duration.as_millis(); |
52 |
| - self.total_time += millis; |
53 |
| - #[allow(clippy::as_conversions)] |
54 |
| - self.per_fact_durations |
55 |
| - .push(duration.div_f32(facts_count as f32).as_micros().try_into().unwrap()); |
56 |
| - self.block_durations.push(millis.try_into().unwrap()); |
57 |
| - self.n_facts.push(facts_count); |
58 |
| - self.facts_in_db.push(self.total_facts); |
59 |
| - self.total_facts += facts_count; |
60 |
| - } |
61 |
| - |
62 |
| - fn n_results(&self) -> usize { |
63 |
| - self.block_durations.len() |
64 |
| - } |
65 |
| - |
66 |
| - /// Returns the average time per block (milliseconds). |
67 |
| - fn block_average_time(&self) -> f64 { |
68 |
| - #[allow(clippy::as_conversions)] |
69 |
| - { |
70 |
| - self.total_time as f64 / self.n_results() as f64 |
71 |
| - } |
72 |
| - } |
73 |
| - |
74 |
| - /// Returns the average time per fact over a window of `window_size` blocks (microseconds). |
75 |
| - fn average_window_time(&self, window_size: usize) -> Vec<f64> { |
76 |
| - let mut averages = Vec::new(); // In milliseconds. |
77 |
| - // Takes only the full windows, so if the last window is smaller than `window_size`, it is |
78 |
| - // ignored. |
79 |
| - let n_windows = self.n_results() / window_size; |
80 |
| - for i in 0..n_windows { |
81 |
| - let window_start = i * window_size; |
82 |
| - let sum: u64 = |
83 |
| - self.block_durations[window_start..window_start + window_size].iter().sum(); |
84 |
| - let sum_of_facts: usize = |
85 |
| - self.n_facts[window_start..window_start + window_size].iter().sum(); |
86 |
| - #[allow(clippy::as_conversions)] |
87 |
| - averages.push(1000.0 * sum as f64 / sum_of_facts as f64); |
88 |
| - } |
89 |
| - averages |
90 |
| - } |
91 |
| - |
92 |
| - fn pretty_print(&self, window_size: usize) { |
93 |
| - if self.n_results() == 0 { |
94 |
| - println!("No measurements were taken."); |
95 |
| - return; |
96 |
| - } |
97 |
| - |
98 |
| - println!( |
99 |
| - "Total time: {} milliseconds for {} iterations.", |
100 |
| - self.total_time, |
101 |
| - self.n_results() |
102 |
| - ); |
103 |
| - println!( |
104 |
| - "Average block time: {:.2} milliseconds. |
105 |
| - ", |
106 |
| - self.block_average_time() |
107 |
| - ); |
108 |
| - |
109 |
| - println!("Average time per window of {window_size} iterations:"); |
110 |
| - let means = self.average_window_time(window_size); |
111 |
| - let max = means.iter().cloned().fold(f64::MIN, f64::max); |
112 |
| - // Print a graph visualization of block times. |
113 |
| - for (i, fact_duration) in means.iter().enumerate() { |
114 |
| - let norm = fact_duration / max; |
115 |
| - #[allow(clippy::as_conversions)] |
116 |
| - let width = (norm * 40.0).round() as usize; // up tp 40 characters wide |
117 |
| - let bar = "█".repeat(width.max(1)); |
118 |
| - println!("win {i:>4}: {fact_duration:>8.4} microsecond / fact | {bar}"); |
119 |
| - } |
120 |
| - } |
121 |
| - |
122 |
| - fn to_csv(&self, path: &str, output_dir: &str) { |
123 |
| - fs::create_dir_all(output_dir).expect("Failed to create output directory."); |
124 |
| - let file = |
125 |
| - File::create(format!("{output_dir}/{path}")).expect("Failed to create CSV file."); |
126 |
| - let mut wtr = Writer::from_writer(file); |
127 |
| - wtr.write_record([ |
128 |
| - "block_number", |
129 |
| - "n_facts", |
130 |
| - "facts_in_db", |
131 |
| - "time_per_fact_micros", |
132 |
| - "block_duration_millis", |
133 |
| - ]) |
134 |
| - .expect("Failed to write CSV header."); |
135 |
| - for (i, (((&per_fact, &n_facts), &duration), &facts_in_db)) in self |
136 |
| - .per_fact_durations |
137 |
| - .iter() |
138 |
| - .zip(self.n_facts.iter()) |
139 |
| - .zip(self.block_durations.iter()) |
140 |
| - .zip(self.facts_in_db.iter()) |
141 |
| - .enumerate() |
142 |
| - { |
143 |
| - wtr.write_record(&[ |
144 |
| - i.to_string(), |
145 |
| - n_facts.to_string(), |
146 |
| - facts_in_db.to_string(), |
147 |
| - per_fact.to_string(), |
148 |
| - duration.to_string(), |
149 |
| - ]) |
150 |
| - .expect("Failed to write CSV record."); |
151 |
| - } |
152 |
| - wtr.flush().expect("Failed to flush CSV writer."); |
153 |
| - } |
154 |
| -} |
155 |
| - |
156 | 13 | /// Runs the committer on n_iterations random generated blocks.
|
157 | 14 | /// Prints the time measurement to the console and saves statistics to a CSV file in the given
|
158 | 15 | /// output directory.
|
|
0 commit comments