2.1. Keep names stable and put variation in metadata
An event name answers “what work was this?” Metadata answers “under which conditions?” A stable name makes runs comparable even when the module, shape, or backend changes.
span "model.forward" runAttention (metadata := {
phase := some "forward"
activity := some "operator"
backend := some backendName
dtype := some dtypeName
device := some deviceName
moduleName := some "encoder.block.0"
graphNode := some nodeName
stepIndex := some step
inputShapes := #[inputShape]
outputShapes := #[outputShape]
})
LeanProfiler uses the following fields as the summary key:
name, phase, activity, backend, dtype, device, module
Those fields split rows because they commonly identify meaningfully different implementations. A CPU and CUDA forward pass should not be averaged together, and neither should two modules whose costs need to be compared.
Step, graph node, and shape arrays remain attached to individual trace events. Putting a step number in the grouping key would create one summary row per iteration. Putting arbitrary shapes in the key could do the same for variable-length inputs. The trace is where those details belong; the summary is where repeated observations become a distribution.
When another dimension really does define a separate benchmark population, use a stable name or one of the grouping fields deliberately. Do not encode an entire JSON payload into an event name.