From 0924b63e10513f0bc8fb9d8cc77114d141c60877 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 17 Feb 2021 19:49:00 +0100
Subject: [PATCH] event/TimerWheel: add `empty` flag to optimize a common case

---
 src/event/TimerWheel.cxx |  9 ++++++++-
 src/event/TimerWheel.hxx | 10 ++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/event/TimerWheel.cxx b/src/event/TimerWheel.cxx
index f0d3dea4d..2f406a302 100644
--- a/src/event/TimerWheel.cxx
+++ b/src/event/TimerWheel.cxx
@@ -54,6 +54,8 @@ TimerWheel::Insert(CoarseTimerEvent &t) noexcept
 	const auto due = std::max(t.GetDue(), last_time);
 
 	buckets[BucketIndexAt(due)].push_back(t);
+
+	empty = false;
 }
 
 void
@@ -99,10 +101,15 @@ TimerWheel::GetNextDue(const std::size_t bucket_index,
 inline Event::Duration
 TimerWheel::GetSleep(Event::TimePoint now) const noexcept
 {
+	if (empty)
+		return Event::Duration(-1);
+
 	auto t = GetNextDue(BucketIndexAt(now), GetBucketStartTime(now));
 	assert(t > now);
-	if (t == Event::TimePoint::max())
+	if (t == Event::TimePoint::max()) {
+		empty = true;
 		return Event::Duration(-1);
+	}
 
 	return t - now;
 }
diff --git a/src/event/TimerWheel.hxx b/src/event/TimerWheel.hxx
index 685829bd4..fd10ee9e4 100644
--- a/src/event/TimerWheel.hxx
+++ b/src/event/TimerWheel.hxx
@@ -72,6 +72,16 @@ class TimerWheel final {
 	 */
 	Event::TimePoint last_time{};
 
+	/**
+	 * If this flag is true, then all buckets are guaranteed to be
+	 * empty.  If it is false, the buckets may or may not be
+	 * empty; if so, the next full scan will set it back to true.
+	 *
+	 * This field is "mutable" so the "const" method GetSleep()
+	 * can update it.
+	 */
+	mutable bool empty = true;
+
 public:
 	TimerWheel() noexcept;
 	~TimerWheel() noexcept;