dotnet/BenchmarkDotNet · error · InvalidOperationException

TotalOperations count can't change during the benchmark run!

Error message

TotalOperations count can't change during the benchmark run! Invalid trace!

What it means

ProcessMetrics.HandleIterationEvent throws when two Workload iteration events in the same benchmark run report a different TotalOperations count. The PMC metric calculation requires the operations-per-iteration to be constant so per-counter values can be divided by a single denominator. A mismatch means the trace is internally inconsistent.

Source

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

        private readonly List<double> workloadTimestamps = new List<double>(20);
        private long? totalOperationsPerIteration;

        private readonly List<(double timeStamp, ulong instructionPointer, int profileSource)> samples = [];

        public bool HasBenchmarkEvents => overheadTimestamps.Any() || workloadTimestamps.Any();

        public void HandleIterationEvent(double timeStamp, IterationMode iterationMode, long totalOperations)
        {
            if (iterationMode == IterationMode.Overhead)
            {
                overheadTimestamps.Add(timeStamp);
            }
            else if (iterationMode == IterationMode.Workload)
            {
                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);

View on GitHub (pinned to b515068b61)

Solutions

  1. Ensure the benchmarked method and its [OperationsPerInvoke] are deterministic and do not mutate global state between invocations.
  2. Re-run in isolation (no other heavy processes) to avoid ETW event interleaving across processes.
  3. If the workload legitimately varies, report it as an inconsistency upstream instead of relying on the PMC diagnoser metrics.
Defensive patterns

Strategy: validation

Try / catch

try { /* run with PMC diagnoser */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("TotalOperations count can't change"))
{
    log.Error($"Non-deterministic operations-per-iteration detected. Make the [Benchmark] deterministic. {ex.Message}");
}

Prevention

When it happens

Trigger: The benchmark engine emitted WorkloadActualStart/Stop events whose TotalOperations field differs between iterations (non-deterministic OperationCount, the [Benchmark] method mutating a shared counter, or a corrupted/partial ETW trace).

Common situations: Marking a method with [OperationsPerInvoke] while the method itself changes the count it reports; sharing mutable state across invocations; capturing a trace over a noisy machine where events from two processes interleave and get attributed incorrectly.

Related errors


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