Skip to content

Commit 1bda942

Browse files
michaelsproulThreeHrSleep
authored andcommitted
Measure consensus verification time (sigp#6089)
* Measure consensus verification time * Track execution time properly
1 parent d091e0d commit 1bda942

File tree

5 files changed

+124
-42
lines changed

5 files changed

+124
-42
lines changed

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3088,14 +3088,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
30883088
notify_execution_layer,
30893089
)?;
30903090
publish_fn()?;
3091+
3092+
// Record the time it took to complete consensus verification.
3093+
if let Some(timestamp) = self.slot_clock.now_duration() {
3094+
self.block_times_cache
3095+
.write()
3096+
.set_time_consensus_verified(block_root, block_slot, timestamp)
3097+
}
3098+
30913099
let executed_block = chain.into_executed_block(execution_pending).await?;
3092-
// Record the time it took to ask the execution layer.
3093-
if let Some(seen_timestamp) = self.slot_clock.now_duration() {
3094-
self.block_times_cache.write().set_execution_time(
3095-
block_root,
3096-
block_slot,
3097-
seen_timestamp,
3098-
)
3100+
3101+
// Record the *additional* time it took to wait for execution layer verification.
3102+
if let Some(timestamp) = self.slot_clock.now_duration() {
3103+
self.block_times_cache
3104+
.write()
3105+
.set_time_executed(block_root, block_slot, timestamp)
30993106
}
31003107

31013108
match executed_block {

beacon_node/beacon_chain/src/block_times_cache.rs

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ type BlockRoot = Hash256;
1919
pub struct Timestamps {
2020
pub observed: Option<Duration>,
2121
pub all_blobs_observed: Option<Duration>,
22-
pub execution_time: Option<Duration>,
22+
pub consensus_verified: Option<Duration>,
23+
pub started_execution: Option<Duration>,
24+
pub executed: Option<Duration>,
2325
pub attestable: Option<Duration>,
2426
pub imported: Option<Duration>,
2527
pub set_as_head: Option<Duration>,
@@ -32,7 +34,9 @@ pub struct BlockDelays {
3234
pub observed: Option<Duration>,
3335
/// The time after the start of the slot we saw all blobs.
3436
pub all_blobs_observed: Option<Duration>,
35-
/// The time it took to get verification from the EL for the block.
37+
/// The time it took to complete consensus verification of the block.
38+
pub consensus_verification_time: Option<Duration>,
39+
/// The time it took to complete execution verification of the block.
3640
pub execution_time: Option<Duration>,
3741
/// The delay from the start of the slot before the block became available
3842
///
@@ -58,13 +62,16 @@ impl BlockDelays {
5862
let all_blobs_observed = times
5963
.all_blobs_observed
6064
.and_then(|all_blobs_observed| all_blobs_observed.checked_sub(slot_start_time));
65+
let consensus_verification_time = times
66+
.consensus_verified
67+
.and_then(|consensus_verified| consensus_verified.checked_sub(times.observed?));
6168
let execution_time = times
62-
.execution_time
63-
.and_then(|execution_time| execution_time.checked_sub(times.observed?));
69+
.executed
70+
.and_then(|executed| executed.checked_sub(times.started_execution?));
6471
// Duration since UNIX epoch at which block became available.
65-
let available_time = times.execution_time.map(|execution_time| {
66-
std::cmp::max(execution_time, times.all_blobs_observed.unwrap_or_default())
67-
});
72+
let available_time = times
73+
.executed
74+
.map(|executed| std::cmp::max(executed, times.all_blobs_observed.unwrap_or_default()));
6875
// Duration from the start of the slot until the block became available.
6976
let available_delay =
7077
available_time.and_then(|available_time| available_time.checked_sub(slot_start_time));
@@ -80,6 +87,7 @@ impl BlockDelays {
8087
BlockDelays {
8188
observed,
8289
all_blobs_observed,
90+
consensus_verification_time,
8391
execution_time,
8492
available: available_delay,
8593
attestable,
@@ -155,6 +163,9 @@ impl BlockTimesCache {
155163
slot: Slot,
156164
timestamp: Duration,
157165
) {
166+
// Unlike other functions in this file, we update the blob observed time only if it is
167+
// *greater* than existing blob observation times. This allows us to know the observation
168+
// time of the last blob to arrive.
158169
let block_times = self
159170
.cache
160171
.entry(block_root)
@@ -168,48 +179,89 @@ impl BlockTimesCache {
168179
}
169180
}
170181

171-
pub fn set_execution_time(&mut self, block_root: BlockRoot, slot: Slot, timestamp: Duration) {
182+
/// Set the timestamp for `field` if that timestamp is less than any previously known value.
183+
///
184+
/// If no previous value is known for the field, then the supplied timestamp will always be
185+
/// stored.
186+
pub fn set_time_if_less(
187+
&mut self,
188+
block_root: BlockRoot,
189+
slot: Slot,
190+
field: impl Fn(&mut Timestamps) -> &mut Option<Duration>,
191+
timestamp: Duration,
192+
) {
172193
let block_times = self
173194
.cache
174195
.entry(block_root)
175196
.or_insert_with(|| BlockTimesCacheValue::new(slot));
176-
if block_times
177-
.timestamps
178-
.execution_time
179-
.map_or(true, |prev| timestamp < prev)
180-
{
181-
block_times.timestamps.execution_time = Some(timestamp);
197+
let existing_timestamp = field(&mut block_times.timestamps);
198+
if existing_timestamp.map_or(true, |prev| timestamp < prev) {
199+
*existing_timestamp = Some(timestamp);
182200
}
183201
}
184202

203+
pub fn set_time_consensus_verified(
204+
&mut self,
205+
block_root: BlockRoot,
206+
slot: Slot,
207+
timestamp: Duration,
208+
) {
209+
self.set_time_if_less(
210+
block_root,
211+
slot,
212+
|timestamps| &mut timestamps.consensus_verified,
213+
timestamp,
214+
)
215+
}
216+
217+
pub fn set_time_executed(&mut self, block_root: BlockRoot, slot: Slot, timestamp: Duration) {
218+
self.set_time_if_less(
219+
block_root,
220+
slot,
221+
|timestamps| &mut timestamps.executed,
222+
timestamp,
223+
)
224+
}
225+
226+
pub fn set_time_started_execution(
227+
&mut self,
228+
block_root: BlockRoot,
229+
slot: Slot,
230+
timestamp: Duration,
231+
) {
232+
self.set_time_if_less(
233+
block_root,
234+
slot,
235+
|timestamps| &mut timestamps.started_execution,
236+
timestamp,
237+
)
238+
}
239+
185240
pub fn set_time_attestable(&mut self, block_root: BlockRoot, slot: Slot, timestamp: Duration) {
186-
let block_times = self
187-
.cache
188-
.entry(block_root)
189-
.or_insert_with(|| BlockTimesCacheValue::new(slot));
190-
if block_times
191-
.timestamps
192-
.attestable
193-
.map_or(true, |prev| timestamp < prev)
194-
{
195-
block_times.timestamps.attestable = Some(timestamp);
196-
}
241+
self.set_time_if_less(
242+
block_root,
243+
slot,
244+
|timestamps| &mut timestamps.attestable,
245+
timestamp,
246+
)
197247
}
198248

199249
pub fn set_time_imported(&mut self, block_root: BlockRoot, slot: Slot, timestamp: Duration) {
200-
let block_times = self
201-
.cache
202-
.entry(block_root)
203-
.or_insert_with(|| BlockTimesCacheValue::new(slot));
204-
block_times.timestamps.imported = Some(timestamp);
250+
self.set_time_if_less(
251+
block_root,
252+
slot,
253+
|timestamps| &mut timestamps.imported,
254+
timestamp,
255+
)
205256
}
206257

207258
pub fn set_time_set_as_head(&mut self, block_root: BlockRoot, slot: Slot, timestamp: Duration) {
208-
let block_times = self
209-
.cache
210-
.entry(block_root)
211-
.or_insert_with(|| BlockTimesCacheValue::new(slot));
212-
block_times.timestamps.set_as_head = Some(timestamp);
259+
self.set_time_if_less(
260+
block_root,
261+
slot,
262+
|timestamps| &mut timestamps.set_as_head,
263+
timestamp,
264+
)
213265
}
214266

215267
pub fn get_block_delays(

beacon_node/beacon_chain/src/block_verification.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,13 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
13441344
// The specification declares that this should be run *inside* `per_block_processing`,
13451345
// however we run it here to keep `per_block_processing` pure (i.e., no calls to external
13461346
// servers).
1347+
if let Some(started_execution) = chain.slot_clock.now_duration() {
1348+
chain.block_times_cache.write().set_time_started_execution(
1349+
block_root,
1350+
block.slot(),
1351+
started_execution,
1352+
);
1353+
}
13471354
let payload_verification_status = payload_notifier.notify_new_payload().await?;
13481355

13491356
// If the payload did not validate or invalidate the block, check to see if this block is

beacon_node/beacon_chain/src/canonical_head.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,15 @@ fn observe_head_block_delays<E: EthSpec, S: SlotClock>(
13851385
.as_millis() as i64,
13861386
);
13871387

1388+
// The time it took to check the validity within Lighthouse
1389+
metrics::set_gauge(
1390+
&metrics::BEACON_BLOCK_DELAY_CONSENSUS_VERIFICATION_TIME,
1391+
block_delays
1392+
.consensus_verification_time
1393+
.unwrap_or_else(|| Duration::from_secs(0))
1394+
.as_millis() as i64,
1395+
);
1396+
13881397
// The time it took to check the validity with the EL
13891398
metrics::set_gauge(
13901399
&metrics::BEACON_BLOCK_DELAY_EXECUTION_TIME,
@@ -1447,6 +1456,7 @@ fn observe_head_block_delays<E: EthSpec, S: SlotClock>(
14471456
"total_delay_ms" => block_delay_total.as_millis(),
14481457
"observed_delay_ms" => format_delay(&block_delays.observed),
14491458
"blob_delay_ms" => format_delay(&block_delays.all_blobs_observed),
1459+
"consensus_time_ms" => format_delay(&block_delays.consensus_verification_time),
14501460
"execution_time_ms" => format_delay(&block_delays.execution_time),
14511461
"available_delay_ms" => format_delay(&block_delays.available),
14521462
"attestable_delay_ms" => format_delay(&block_delays.attestable),
@@ -1463,6 +1473,7 @@ fn observe_head_block_delays<E: EthSpec, S: SlotClock>(
14631473
"total_delay_ms" => block_delay_total.as_millis(),
14641474
"observed_delay_ms" => format_delay(&block_delays.observed),
14651475
"blob_delay_ms" => format_delay(&block_delays.all_blobs_observed),
1476+
"consensus_time_ms" => format_delay(&block_delays.consensus_verification_time),
14661477
"execution_time_ms" => format_delay(&block_delays.execution_time),
14671478
"available_delay_ms" => format_delay(&block_delays.available),
14681479
"attestable_delay_ms" => format_delay(&block_delays.attestable),

beacon_node/beacon_chain/src/metrics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,11 @@ lazy_static! {
857857
"Duration between the start of the block's slot and the time the block was observed.",
858858
);
859859

860+
pub static ref BEACON_BLOCK_DELAY_CONSENSUS_VERIFICATION_TIME: Result<IntGauge> = try_create_int_gauge(
861+
"beacon_block_delay_consensus_verification_time",
862+
"The time taken to verify the block within Lighthouse",
863+
);
864+
860865
pub static ref BEACON_BLOCK_DELAY_EXECUTION_TIME: Result<IntGauge> = try_create_int_gauge(
861866
"beacon_block_delay_execution_time",
862867
"The duration in verifying the block with the execution layer.",

0 commit comments

Comments
 (0)