From 55e3ed2a3976020d8513d5276d2afbaf2ea53c4d Mon Sep 17 00:00:00 2001 From: Qi Date: Sat, 24 May 2025 01:24:00 +0800 Subject: [PATCH] runtime: eliminate unnecessary lfence while operating on `queue::Local` (#7340) --- .../runtime/scheduler/multi_thread/queue.rs | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/tokio/src/runtime/scheduler/multi_thread/queue.rs b/tokio/src/runtime/scheduler/multi_thread/queue.rs index bf546fde5..68670e63c 100644 --- a/tokio/src/runtime/scheduler/multi_thread/queue.rs +++ b/tokio/src/runtime/scheduler/multi_thread/queue.rs @@ -107,12 +107,19 @@ pub(crate) fn local() -> (Steal, Local) { impl Local { /// Returns the number of entries in the queue pub(crate) fn len(&self) -> usize { - self.inner.len() as usize + let (_, head) = unpack(self.inner.head.load(Acquire)); + // safety: this is the **only** thread that updates this cell. + let tail = unsafe { self.inner.tail.unsync_load() }; + len(head, tail) } /// How many tasks can be pushed into the queue pub(crate) fn remaining_slots(&self) -> usize { - self.inner.remaining_slots() + let (steal, _) = unpack(self.inner.head.load(Acquire)); + // safety: this is the **only** thread that updates this cell. + let tail = unsafe { self.inner.tail.unsync_load() }; + + LOCAL_QUEUE_CAPACITY - len(steal, tail) } pub(crate) fn max_capacity(&self) -> usize { @@ -124,7 +131,7 @@ impl Local { /// Separate to `is_stealable` so that refactors of `is_stealable` to "protect" /// some tasks from stealing won't affect this pub(crate) fn has_tasks(&self) -> bool { - !self.inner.is_empty() + self.len() != 0 } /// Pushes a batch of tasks to the back of the queue. All tasks must fit in @@ -384,8 +391,17 @@ impl Local { } impl Steal { + /// Returns the number of entries in the queue + pub(crate) fn len(&self) -> usize { + let (_, head) = unpack(self.0.head.load(Acquire)); + let tail = self.0.tail.load(Acquire); + len(head, tail) + } + + /// Return true if the queue is empty, + /// false if there are any entries in the queue pub(crate) fn is_empty(&self) -> bool { - self.0.is_empty() + self.len() == 0 } /// Steals half the tasks from self and place them into `dst`. @@ -543,14 +559,6 @@ impl Steal { } } -cfg_unstable_metrics! { - impl Steal { - pub(crate) fn len(&self) -> usize { - self.0.len() as _ - } - } -} - impl Clone for Steal { fn clone(&self) -> Steal { Steal(self.0.clone()) @@ -565,24 +573,10 @@ impl Drop for Local { } } -impl Inner { - fn remaining_slots(&self) -> usize { - let (steal, _) = unpack(self.head.load(Acquire)); - let tail = self.tail.load(Acquire); - - LOCAL_QUEUE_CAPACITY - (tail.wrapping_sub(steal) as usize) - } - - fn len(&self) -> UnsignedShort { - let (_, head) = unpack(self.head.load(Acquire)); - let tail = self.tail.load(Acquire); - - tail.wrapping_sub(head) - } - - fn is_empty(&self) -> bool { - self.len() == 0 - } +/// Calculate the length of the queue using the head and tail. +/// The `head` can be the `steal` or `real` head. +fn len(head: UnsignedShort, tail: UnsignedShort) -> usize { + tail.wrapping_sub(head) as usize } /// Split the head value into the real head and the index a stealer is working