dotnet/BenchmarkDotNet · error · InvalidOperationException

One workload iteration stop event is missing, unable to calc

Error message

One workload iteration stop event is missing, unable to calculate stats

What it means

Symmetric to the overhead check: CalculateMetrics throws when workloadTimestamps.Count is odd, i.e. a WorkloadActualStart had no matching WorkloadActualStop. Without complete workload iteration boundaries the PMC counter samples cannot be attributed to iterations.

Source

Thrown at src/BenchmarkDotNet.Diagnostics.Windows/Tracing/TraceLogParser.cs:126

            {
                if (!totalOperationsPerIteration.HasValue)
                    totalOperationsPerIteration = totalOperations;
                else if (totalOperationsPerIteration.Value != totalOperations)
                    throw new InvalidOperationException($"TotalOperations count can't change during the benchmark run! Invalid trace!");

                workloadTimestamps.Add(timeStamp);
            }
        }

        public void HandleNewSample(double timeStamp, ulong instructionPointer, int profileSourceId)
            => samples.Add((timeStamp, instructionPointer, profileSourceId));

        public IEnumerable<Metric> CalculateMetrics(Dictionary<int, int> profileSourceIdToInterval, PreciseMachineCounter[] counters)
        {
            if (overheadTimestamps.Count % 2 != 0)
                throw new InvalidOperationException("One overhead iteration stop event is missing, unable to calculate stats");
            if (workloadTimestamps.Count % 2 != 0)
                throw new InvalidOperationException("One workload iteration stop event is missing, unable to calculate stats");
            if (!totalOperationsPerIteration.HasValue)
                throw new InvalidOperationException("TotalOperations is missing, unable to calculate stats");

            var overheadIterations = CreateIterationData(overheadTimestamps);
            var workloadIterations = CreateIterationData(workloadTimestamps);

            SumCountersPerIterations(profileSourceIdToInterval, workloadIterations, overheadIterations, counters);

            var workloadTotalPerCounter = Sum(workloadIterations);
            var overheadTotalPerCounter = Sum(overheadIterations);

            return workloadTotalPerCounter.Select(perCounter =>
            {
                var pmc = counters.Single(counter => counter.ProfileSourceId == perCounter.Key);

                overheadTotalPerCounter.TryGetValue(perCounter.Key, out var overhead);

                // result = (avg(workload) - avg(overhead))/op

View on GitHub (pinned to b515068b61)

Solutions

  1. Make sure the benchmark method does not throw so the engine can emit the stop event.
  2. Raise ETW buffer size and number of buffers when collecting the .etl.
  3. Re-run in isolation; intermittent event loss is environment-dependent.
Defensive patterns

Strategy: retry

Try / catch

try { /* run + parse trace */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("workload iteration stop event is missing"))
{
    log.Warning("ETW dropped a workload stop event; rerun with larger buffers / in isolation.");
}

Prevention

When it happens

Trigger: An ETW WorkloadActualStop event is missing from the trace. Same root causes as the overhead variant: dropped events, process exit mid-iteration, partial capture, or an exception that aborted the workload before the stop event fired.

Common situations: Benchmark threw an unhandled exception inside a workload iteration; ETW buffer overflow on a noisy machine; the trace was started/stopped asynchronously and missed the final stop event.

Related errors


AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13). Data as JSON: /api/errors/51db5d98bea861e8. Report an issue: GitHub.