Skip to content

Commit d6b6d39

Browse files
committed
Merge tag 'wq-for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue updates from Tejun Heo: - The maximum concurrency limit of 512 which was set a long time ago is too low now. A legitimate use (BPF cgroup release) of system_wq could saturate it under stress test conditions leading to false dependencies and deadlocks. While the offending use was switched to a dedicated workqueue, use the opportunity to bump WQ_MAX_ACTIVE four fold and document that system workqueue shouldn't be saturated. Workqueue should add at least a warning mechanism for cases where system workqueues are saturated. - Recent workqueue updates to support more flexible execution topology made unbound workqueues use per-cpu worker pool frontends which pushed up workqueue flush overhead. As consecutive CPUs are likely to be pointing to the same worker pool, reduce overhead by switching locks only when necessary. * tag 'wq-for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: workqueue: Reduce expensive locks for unbound workqueue workqueue: Adjust WQ_MAX_ACTIVE from 512 to 2048 workqueue: doc: Add a note saturating the system_wq is not permitted
2 parents a0e752b + 85f0d8e commit d6b6d39

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

Documentation/core-api/workqueue.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ CPU which can be assigned to the work items of a wq. For example, with
245245
at the same time per CPU. This is always a per-CPU attribute, even for
246246
unbound workqueues.
247247

248-
The maximum limit for ``@max_active`` is 512 and the default value used
249-
when 0 is specified is 256. These values are chosen sufficiently high
248+
The maximum limit for ``@max_active`` is 2048 and the default value used
249+
when 0 is specified is 1024. These values are chosen sufficiently high
250250
such that they are not the limiting factor while providing protection in
251251
runaway cases.
252252

@@ -357,6 +357,11 @@ Guidelines
357357
difference in execution characteristics between using a dedicated wq
358358
and a system wq.
359359

360+
Note: If something may generate more than @max_active outstanding
361+
work items (do stress test your producers), it may saturate a system
362+
wq and potentially lead to deadlock. It should utilize its own
363+
dedicated workqueue rather than the system wq.
364+
360365
* Unless work items are expected to consume a huge amount of CPU
361366
cycles, using a bound wq is usually beneficial due to the increased
362367
level of locality in wq operations and work item execution.

include/linux/workqueue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ enum wq_flags {
412412
};
413413

414414
enum wq_consts {
415-
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
415+
WQ_MAX_ACTIVE = 2048, /* I like 2048, better ideas? */
416416
WQ_UNBOUND_MAX_ACTIVE = WQ_MAX_ACTIVE,
417417
WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2,
418418

kernel/workqueue.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3833,16 +3833,28 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
38333833
{
38343834
bool wait = false;
38353835
struct pool_workqueue *pwq;
3836+
struct worker_pool *current_pool = NULL;
38363837

38373838
if (flush_color >= 0) {
38383839
WARN_ON_ONCE(atomic_read(&wq->nr_pwqs_to_flush));
38393840
atomic_set(&wq->nr_pwqs_to_flush, 1);
38403841
}
38413842

3843+
/*
3844+
* For unbound workqueue, pwqs will map to only a few pools.
3845+
* Most of the time, pwqs within the same pool will be linked
3846+
* sequentially to wq->pwqs by cpu index. So in the majority
3847+
* of pwq iters, the pool is the same, only doing lock/unlock
3848+
* if the pool has changed. This can largely reduce expensive
3849+
* lock operations.
3850+
*/
38423851
for_each_pwq(pwq, wq) {
3843-
struct worker_pool *pool = pwq->pool;
3844-
3845-
raw_spin_lock_irq(&pool->lock);
3852+
if (current_pool != pwq->pool) {
3853+
if (likely(current_pool))
3854+
raw_spin_unlock_irq(&current_pool->lock);
3855+
current_pool = pwq->pool;
3856+
raw_spin_lock_irq(&current_pool->lock);
3857+
}
38463858

38473859
if (flush_color >= 0) {
38483860
WARN_ON_ONCE(pwq->flush_color != -1);
@@ -3859,9 +3871,11 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
38593871
pwq->work_color = work_color;
38603872
}
38613873

3862-
raw_spin_unlock_irq(&pool->lock);
38633874
}
38643875

3876+
if (current_pool)
3877+
raw_spin_unlock_irq(&current_pool->lock);
3878+
38653879
if (flush_color >= 0 && atomic_dec_and_test(&wq->nr_pwqs_to_flush))
38663880
complete(&wq->first_flusher->done);
38673881

0 commit comments

Comments
 (0)