2025 05 16.RuntimeMetricsSummary - SergeiGolos/wod-wiki GitHub Wiki
This document outlines how RuntimeMetric
objects are created, assembled, and managed within the wod.wiki runtime system. It details the roles of different block types in generating and aggregating metrics.
- Definition (effort, repetitions, resistance, distance) - as per memory
74eb0117-4e09-4991-bdfd-20d4a63f10cc
. - Purpose: To capture quantifiable results of workout components.
-
EffortBlock
: Primary generator ofRuntimeMetric
instances for individual exercises.- Metrics are derived from
PrecompiledNode
sources passed during its construction, which contain parsed workout data (e.g., exercise name, repetitions, weight, distance). - Manages its metrics within its own
MetricsContext
, initialized withMetricsRelationshipType.INHERIT
(viaAbstractBlockLifecycle
). - During its lifecycle, particularly in its overridden
enhanceResultSpan
anddoLeave
methods, it adds further details like 'Last Updated' timestamps, completion timestamps, and a 'Status: completed' metric to itsResultSpan
(stored inBlockContext
).
- Metrics are derived from
-
RuntimeJit
: As per memory74eb0117-4e09-4991-bdfd-20d4a63f10cc
,RuntimeJit
plays a role in the initial compilation of the workout.AbstractBlockLifecycle
'sinitializeMetrics
method, usingMetricsFactory
, then creates theRuntimeMetric
structures fromPrecompiledNode
s for each block.
This section describes how different runtime blocks handle metrics, particularly in terms of merging metrics from child blocks or inheriting them. The core aggregation logic (ADD, MULTIPLY, INHERIT) resides in MetricsContext.getMetrics()
, orchestrated by AbstractBlockLifecycle
.
- Its
MetricsContext
(initialized byAbstractBlockLifecycle
) contains base metrics from itsPrecompiledNode
sources. - Uses
MetricsRelationshipType.INHERIT
. It doesn't aggregate child metrics. - Its overridden
enhanceResultSpan
method dynamically adds detailed descriptions (e.g., "10 Pullups 50kg") and timestamps to itsResultSpan
.
- Its
MetricsContext
is initialized withMetricsRelationshipType.MULTIPLY
byAbstractBlockLifecycle
.- When its
getMetrics()
is called (likely by a parent or for final summary),MetricsContext
will handle multiplying the metrics of its children (representing one round) by the number of rounds completed (this.ctx.index
).
- When its
-
ResultSpan
Enhancements (via overriddenenhanceResultSpan
):- Updates the
ResultSpan
label with round progress. - Adds a 'Rounds'
RuntimeMetric
. - When a round completes (in
doNext()
), generates a 'Round Complete' metric and adds it to the currentResultSpan
(viathis.ctx.addMetricsToResultSpan()
).
- Updates the
- Its
MetricsContext
is initialized withMetricsRelationshipType.ADD
byAbstractBlockLifecycle
. -
ResultSpan
Enhancements (via overriddenenhanceResultSpan
):- This is where it aggregates metrics from its children. It calls
getMetrics()
on each child block (which in turn uses theirMetricsContext
). - The summed child metrics are then added to its own
ResultSpan
viathis.ctx.addMetricsToResultSpan()
. - Manages child
ResultSpan
s via itschildSpanRegistry
to facilitate this aggregation.
- This is where it aggregates metrics from its children. It calls
- Its
MetricsContext
is initialized byAbstractBlockLifecycle
, likely defaulting toMetricsRelationshipType.ADD
. - When its
doLeave()
method is called:- Its
ResultSpan
(created onenter
and stored inthis.ctx
) is finalized. - The call to
ResultSpan.fromBlock(this)
(or an equivalentthis.getMetrics(true,true)
) triggers itsMetricsContext
to aggregate metrics from all its direct children (top-level workout segments).
- Its
- The final
ResultSpan
contains the grand total for the workout and is emitted byWriteResultAction
.
-
IdleRuntimeBlock
,DoneRuntimeBlock
: Typically do not generate significant performance metrics. TheirMetricsContext
would be minimal, and they wouldn't overrideenhanceResultSpan
extensively.
BlockContext
serves as the stateful companion to RuntimeBlock
instances, crucial for metric management by providing storage and basic manipulation tools for ITimeSpan
s and ResultSpan
s. It does not perform aggregation logic itself.
-
State Holding: Stores
index
,childIndex
,spans
(array ofITimeSpan
),resultSpans
(array ofResultSpan
),blockKey
, etc. -
ResultSpan
Management:-
createResultSpan()
: Called byAbstractBlockLifecycle.createResultSpan()
to instantiate a newResultSpan
when a block begins execution. This span is stored inctx.resultSpans
. -
getCurrentResultSpan()
: Allows blocks to retrieve their activeResultSpan
for updates during their lifecycle (e.g., inenhanceResultSpan
). -
addMetricsToResultSpan()
: Key method used by block-specificenhanceResultSpan
overrides to add generated or aggregatedRuntimeMetric
arrays to theirResultSpan
. -
completeResultSpan()
: Marks aResultSpan
as complete, typically called byAbstractBlockLifecycle.leave()
.
-
-
Facilitator:
BlockContext
provides the mutable storage forResultSpan
objects that are populated byAbstractBlockLifecycle
and its concrete subclasses.
AbstractBlockLifecycle
implements the Template Method pattern and is central to orchestrating metric initialization, ResultSpan
management, and providing access to aggregated metrics.
-
Initialization &
MetricsContext
Setup:- In its constructor, it creates a
MetricsContext
for the block, establishing itsMetricsRelationshipType
(ADD, MULTIPLY, INHERIT) and linking it to a parentMetricsContext
if applicable. - Calls
initializeMetrics()
, which uses aMetricsFactory
to create baseRuntimeMetric
objects from thePrecompiledNode
sources and adds them to the block'sMetricsContext
.
- In its constructor, it creates a
-
Metric Calculation (
getMetrics
):- Implements
IMetricsProvider
. - Its
getMetrics(includeChildren, inheritFromParent)
method delegates directly tothis.metricsContext.getMetrics()
. This is where the actual hierarchical aggregation (ADD, MULTIPLY) or INHERITance logic defined byMetricsRelationshipType
is executed by theMetricsContext
.
- Implements
-
ResultSpan
Lifecycle Orchestration:-
enter()
: Calls itscreateResultSpan()
helper, which in turn callsthis.ctx.createResultSpan()
to make a newResultSpan
for the current execution. It then callsthis.enhanceResultSpan()
for initial population. -
enhanceResultSpan(span)
(Protected Hook): This is a key extension point. The base version adds default metrics. Subclasses override it to:- Add their own specific metrics (e.g., 'Round Complete' for
RepeatingBlock
). - For aggregator blocks (like
TimedGroupBlock
), fetch aggregated metrics from children (by callingchild.getMetrics()
) and add them to their ownspan
(usingthis.ctx.addMetricsToResultSpan()
).
- Add their own specific metrics (e.g., 'Round Complete' for
-
leave()
: Performs a final call toenhanceResultSpan()
on the currentResultSpan
, then callsthis.ctx.completeResultSpan()
. It also callsupdateMetricsContextFromSpans()
to potentially sync theMetricsContext
with data from theResultSpan
s (though primary aggregation forgetMetrics()
relies on theMetricsContext
hierarchy).
-
-
Overall Flow:
AbstractBlockLifecycle
sets up theMetricsContext
(which knows how to calculate its total metrics). It also manages theResultSpan
for an execution instance, allowing subclasses to fill thisResultSpan
with the relevant metrics that will eventually be reported.
RuntimeMetrics
are initialized from script definitions by AbstractBlockLifecycle
(using MetricsFactory
) and stored in a block's MetricsContext
. The MetricsContext
itself, governed by MetricsRelationshipType
, is responsible for calculating a block's total metrics, including aggregation from children when its getMetrics()
method is called. During runtime, each block execution gets a ResultSpan
(managed via BlockContext
and AbstractBlockLifecycle
). Blocks populate their ResultSpan
(via overridden enhanceResultSpan
methods) with their specific metrics and/or metrics aggregated from children (obtained by calling child.getMetrics()
). This ResultSpan
is then emitted upon block completion, providing a snapshot of that block's performance for that specific run.