* [PATCH] kernel/async: streamline cookie synchronization
@ 2025-07-08 14:15 David Jeffery
0 siblings, 0 replies; only message in thread
From: David Jeffery @ 2025-07-08 14:15 UTC (permalink / raw)
To: Tejun Heo, Rafael J. Wysocki, linux-kernel
Cc: Greg Kroah-Hartman, David Jeffery, Stuart Hayes
To prevent a thundering herd effect, implement a custom wake function for
the async subsystem which will only wake waiters which have all their
dependencies completed.
The async subsystem currently wakes all waiters on async_done when an async
task completes. When there are many tasks trying to synchronize on differnt
async values, this can create a thundering herd problem when an async task
wakes up all waiters, most of whom go back to waiting after causing
lock contention and wasting CPU.
Signed-off-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
---
This was originally submitted with a patch series for async shutdown as
the async shutdown patches could cause enough waiters to make the thundering
herd effect noticeable. The patch is being resubmitted separately as it
is its own issue and not part of the device shutdown code.
kernel/async.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/kernel/async.c b/kernel/async.c
index 4c3e6a44595f..ae327f29bac9 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -76,6 +76,12 @@ struct async_entry {
struct async_domain *domain;
};
+struct async_wait_entry {
+ wait_queue_entry_t wait;
+ async_cookie_t cookie;
+ struct async_domain *domain;
+};
+
static DECLARE_WAIT_QUEUE_HEAD(async_done);
static atomic_t entry_count;
@@ -298,6 +304,24 @@ void async_synchronize_full_domain(struct async_domain *domain)
}
EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
+/**
+ * async_domain_wake_function - wait function for cooking synchronization
+ *
+ * Custom wait function for async_synchronize_cookie_domain to check cookie
+ * value. This prevents waking up waiting threads unnecessarily.
+ */
+static int async_domain_wake_function(struct wait_queue_entry *wait,
+ unsigned int mode, int sync, void *key)
+{
+ struct async_wait_entry *await =
+ container_of(wait, struct async_wait_entry, wait);
+
+ if (lowest_in_progress(await->domain) < await->cookie)
+ return 0;
+
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+
/**
* async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing
* @cookie: async_cookie_t to use as checkpoint
@@ -310,11 +334,27 @@ EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain *domain)
{
ktime_t starttime;
+ struct async_wait_entry await = {
+ .cookie = cookie,
+ .domain = domain,
+ .wait = {
+ .func = async_domain_wake_function,
+ .private = current,
+ .flags = 0,
+ .entry = LIST_HEAD_INIT(await.wait.entry),
+ }};
pr_debug("async_waiting @ %i\n", task_pid_nr(current));
starttime = ktime_get();
- wait_event(async_done, lowest_in_progress(domain) >= cookie);
+ for (;;) {
+ prepare_to_wait(&async_done, &await.wait, TASK_UNINTERRUPTIBLE);
+
+ if (lowest_in_progress(domain) >= cookie)
+ break;
+ schedule();
+ }
+ finish_wait(&async_done, &await.wait);
pr_debug("async_continuing @ %i after %lli usec\n", task_pid_nr(current),
microseconds_since(starttime));
--
2.39.3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2025-07-08 14:20 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-08 14:15 [PATCH] kernel/async: streamline cookie synchronization David Jeffery
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).