diff --git a/tests/benchmarks/core/bench_scheduler.cpp b/tests/benchmarks/core/bench_scheduler.cpp index 9357734cc8..b2616af2ea 100644 --- a/tests/benchmarks/core/bench_scheduler.cpp +++ b/tests/benchmarks/core/bench_scheduler.cpp @@ -82,12 +82,24 @@ BENCHMARK(Scheduler_Call_5IntervalsFiring); static void Scheduler_SetTimeout(benchmark::State &state) { Scheduler scheduler; Component dummy_component; + // Number of distinct timeout keys; controls how many unique timers exist + // simultaneously and the drain cadence for process_to_add(). + static constexpr int kKeyCount = 5; for (auto _ : state) { + uint32_t now = millis(); for (int i = 0; i < kInnerIterations; i++) { - scheduler.set_timeout(&dummy_component, static_cast(i % 5), 1000, []() {}); + scheduler.set_timeout(&dummy_component, static_cast(i % kKeyCount), 1000, []() {}); + // Drain periodically to reflect production behavior where call() runs + // each main loop iteration. call() moves to_add_ into items_ and cleans + // up cancelled items. Without this, cancelled items accumulate causing + // O(n²) scan cost in cancel_item_locked_. + if ((i + 1) % kKeyCount == 0) { + scheduler.call(++now); + } } - scheduler.process_to_add(); + // Final drain in case kInnerIterations is not a multiple of kKeyCount + scheduler.call(++now); benchmark::DoNotOptimize(scheduler); } state.SetItemsProcessed(state.iterations() * kInnerIterations); @@ -104,17 +116,19 @@ static void Scheduler_SetInterval(benchmark::State &state) { static constexpr int kKeyCount = 5; for (auto _ : state) { + uint32_t now = millis(); for (int i = 0; i < kInnerIterations; i++) { scheduler.set_interval(&dummy_component, static_cast(i % kKeyCount), 1000, []() {}); - // Drain to_add_ periodically to reflect production behavior where - // process_to_add() runs each main loop iteration. Without this, - // cancelled items accumulate in to_add_ causing O(n²) scan cost. + // Drain periodically to reflect production behavior where call() runs + // each main loop iteration. call() moves to_add_ into items_ and cleans + // up cancelled items. Without this, cancelled items accumulate causing + // O(n²) scan cost in cancel_item_locked_. if ((i + 1) % kKeyCount == 0) { - scheduler.process_to_add(); + scheduler.call(++now); } } - // Final drain in case kInnerIterations is not a multiple of 5 - scheduler.process_to_add(); + // Final drain in case kInnerIterations is not a multiple of kKeyCount + scheduler.call(++now); benchmark::DoNotOptimize(scheduler); } state.SetItemsProcessed(state.iterations() * kInnerIterations); @@ -126,14 +140,24 @@ BENCHMARK(Scheduler_SetInterval); static void Scheduler_Defer(benchmark::State &state) { Scheduler scheduler; Component dummy_component; + // Number of distinct defer keys; controls how many unique defers exist + // simultaneously and the drain cadence for call(). + static constexpr int kKeyCount = 5; // defer() is Component::defer which calls set_timeout(delay=0). // Call set_timeout directly since defer() is protected. + // Drain with call() periodically to reflect production behavior where + // call() runs each main loop iteration, keeping the defer queue small. for (auto _ : state) { + uint32_t now = millis(); for (int i = 0; i < kInnerIterations; i++) { - scheduler.set_timeout(&dummy_component, static_cast(i % 5), 0, []() {}); + scheduler.set_timeout(&dummy_component, static_cast(i % kKeyCount), 0, []() {}); + if ((i + 1) % kKeyCount == 0) { + scheduler.call(++now); + } } - scheduler.process_to_add(); + // Final drain in case kInnerIterations is not a multiple of kKeyCount + scheduler.call(++now); benchmark::DoNotOptimize(scheduler); } state.SetItemsProcessed(state.iterations() * kInnerIterations);