Few cores have one counter per event, so events time-share the programmable counters. Each event counts only while it is scheduled, denoted time_enabled, within the whole run time_total.
The scaled estimate is scaled = raw x (time_total / time_enabled). Assume a raw count of 1.2M gathered over 2 ms inside a 10 ms run.
scaled = 1.2e6 x (10 ms / 2 ms)
= 1.2e6 x 5
= 6.0e6 eventsScaling assumes the event rate was steady across the run. Bursty events break that assumption, so bursty counts need a dedicated counter and a replay.
Every ratio needs a stated denominator with matching window and scope. A count without a denominator is a rumor, not evidence.
Trap | Example | Fix |
|---|---|---|
Mixed denominators | Events per micro-op beside events per cycle | Convert to one denominator before comparing |
Scope mismatch | Per-core misses over system-wide cycles | Use core cycles for core events |
Window mismatch | Counts from a warmup window beside steady-state cycles | Lock one window for numerator and denominator |
Event aliasing | Two names for one underlying event summed twice | Read the event list once and de-duplicate |
Lock the workload revision, the run window, and the frequency state before comparing two runs. Traces from different thermal or frequency envelopes never compare.
Calibrate against small golden microbenchmarks with known answers, such as a loop with a known trip count. A counter that fails a golden check leaves the run, not the conclusion.
Repeat the run and require the key ratios to agree within a stated band.
Cross-check one counter claim against a second independent source.
Drop counters that fail consistency checks under controlled replay.
6.0M events. The calc block shows 1.2M x (10 / 2) = 6.0M, valid only if the rate was steady.
Scope mismatch. Core events need core cycles, so either scope both to the core or both to the system.