From 2b16141fc6d73e570d338da5d3448c67373405cb Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:44:57 +0200 Subject: [PATCH] Add stateClonedCount metric (#4128) * Add stateClonedCount metric * Fix clonedCount --- .../src/chain/stateCache/stateContextCache.ts | 4 ++++ .../stateContextCheckpointsCache.ts | 19 +++++++++++++------ .../src/metrics/metrics/lodestar.ts | 10 ++++++++++ .../state-transition/src/cache/stateCache.ts | 9 +++++++++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index a506afbe23a9..65aec4270482 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -38,7 +38,11 @@ export class StateContextCache { if (!item) { return null; } + this.metrics?.hits.inc(); + // clonedCount + 1 as there's a .clone() below + this.metrics?.stateClonedCount.observe(item.clonedCount + 1); + return item.clone(); } diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 11c885cd2f14..e42a856b7412 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -36,13 +36,20 @@ export class CheckpointStateCache { this.metrics?.lookups.inc(); const cpKey = toCheckpointKey(cp); const item = this.cache.get(cpKey); - if (item) { - this.metrics?.hits.inc(); - if (cpKey === this.preComputedCheckpoint) { - this.preComputedCheckpointHits = (this.preComputedCheckpointHits ?? 0) + 1; - } + + if (!item) { + return null; + } + + this.metrics?.hits.inc(); + // clonedCount + 1 as there's a .clone() below + this.metrics?.stateClonedCount.observe(item.clonedCount + 1); + + if (cpKey === this.preComputedCheckpoint) { + this.preComputedCheckpointHits = (this.preComputedCheckpointHits ?? 0) + 1; } - return item ? item.clone() : null; + + return item.clone(); } add(cp: phase0.Checkpoint, item: CachedBeaconStateAllForks): void { diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 29d2866781e4..c11ee375c20d 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -835,6 +835,11 @@ export function createLodestarMetrics( name: "lodestar_state_cache_seconds_since_last_read", help: "Avg min max of all state cache items seconds since last reads", }), + stateClonedCount: register.histogram({ + name: "lodestar_state_cache_state_cloned_clount", + help: "Histogram of cloned count per state every time state.clone() is called", + buckets: [1, 2, 5, 10, 50, 250], + }), }, cpStateCache: { @@ -866,6 +871,11 @@ export function createLodestarMetrics( name: "lodestar_cp_state_epoch_seconds_since_last_read", help: "Avg min max of all state cache items seconds since last reads", }), + stateClonedCount: register.histogram({ + name: "lodestar_cp_state_cache_state_cloned_clount", + help: "Histogram of cloned count per state every time state.clone() is called", + buckets: [1, 2, 5, 10, 50, 250], + }), }, seenCache: { diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index ee00872318e4..e88ea5710713 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -5,6 +5,8 @@ import {BeaconStatePhase0, BeaconStateAltair, BeaconStateBellatrix, BeaconStateA export type BeaconStateCache = { config: IBeaconConfig; epochCtx: EpochContext; + /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */ + readonly clonedCount: number; }; /** @@ -119,6 +121,7 @@ export function createCachedBeaconState( return getCachedBeaconState(state, { config: immutableData.config, epochCtx: EpochContext.createFromState(state, immutableData, opts), + clonedCount: 0, }); } @@ -132,6 +135,7 @@ export function getCachedBeaconState( const cachedState = state as T & BeaconStateCache; cachedState.config = cache.config; cachedState.epochCtx = cache.epochCtx; + (cachedState as {clonedCount: number}).clonedCount = cache.clonedCount; // Overwrite .clone function to preserve cache // TreeViewDU.clone() creates a new object that does not have the attached cache @@ -139,9 +143,14 @@ export function getCachedBeaconState( function clone(this: T & BeaconStateCache): T & BeaconStateCache { const viewDUCloned = viewDUClone(); + + // Override `readonly` attribute in single place where `.clonedCount` is incremented + (this as {clonedCount: number}).clonedCount++; + return getCachedBeaconState(viewDUCloned, { config: this.config, epochCtx: this.epochCtx.clone(), + clonedCount: 0, }) as T & BeaconStateCache; }