summaryrefslogtreecommitdiff
path: root/kernel/workqueue.c
diff options
context:
space:
mode:
authorAaron Tomlin <atomlin@atomlin.com>2026-09-04 15:34:47 -0400
committerTejun Heo <tj@kernel.org>2026-09-04 10:21:02 -1000
commit8bbd858c4710ff90491365c09209d9d6f70ced77 (patch)
tree72a9493957f53e273d94969aa647c2d8395b1a9d /kernel/workqueue.c
parenta53b50e21af2eb8d4e74c8f84e409692a3332588 (diff)
downloadlinux-next-8bbd858c4710ff90491365c09209d9d6f70ced77.tar.gz
linux-next-8bbd858c4710ff90491365c09209d9d6f70ced77.zip
workqueue: Add workqueue_bh_budget_yield tracepoint
Bottom-Half (BH) workqueues execute work items in softirq context. To prevent softirqs from starving user and kernel threads, bh_worker() enforces execution limits (i.e., BH_WORKER_JIFFIES and BH_WORKER_RESTARTS). When keep_working() is still true but either the time slice or restart count is exhausted, bh_worker() yields execution and re-raises the softirq via kick_bh_pool(). Currently, there is no observability into when a BH worker hits these limits and is forced to yield. Add the workqueue_bh_budget_yield tracepoint, emitted when bh_worker() exits the processing loop with pending work items remaining. It records, the worker pool ID, pool CPU, number of loop restarts consumed, a boolean flag indicating whether the yield was due to a time slice timeout, and a boolean flag indicating whether this is a high-priority BH pool. Signed-off-by: Aaron Tomlin <atomlin@atomlin.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r--kernel/workqueue.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 53bb9ad56f49..5b70489a1e65 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3770,6 +3770,9 @@ static void bh_worker(struct worker *worker)
struct worker_pool *pool = worker->pool;
int nr_restarts = BH_WORKER_RESTARTS;
unsigned long end = jiffies + BH_WORKER_JIFFIES;
+ bool budget_exhausted = false;
+ bool timeout = false;
+ int restarts = 0;
worker_lock_callback(pool);
raw_spin_lock_irq(&pool->lock);
@@ -3792,8 +3795,23 @@ static void bh_worker(struct worker *worker)
if (assign_work(work, worker, NULL))
process_scheduled_works(worker);
- } while (keep_working(pool) &&
- --nr_restarts && time_before(jiffies, end));
+
+ if (!keep_working(pool))
+ break;
+
+ if (!--nr_restarts) {
+ budget_exhausted = true;
+ break;
+ }
+
+ if (!time_before(jiffies, end)) {
+ budget_exhausted = true;
+ timeout = true;
+ break;
+ }
+
+ restarts++;
+ } while (1);
worker_set_flags(worker, WORKER_PREP);
done:
@@ -3801,6 +3819,10 @@ done:
kick_pool(pool);
raw_spin_unlock_irq(&pool->lock);
worker_unlock_callback(pool);
+
+ if (budget_exhausted)
+ trace_workqueue_bh_budget_yield(pool, restarts, timeout,
+ pool->attrs->nice == HIGHPRI_NICE_LEVEL);
}
/*