Imply and set strict CPU affinity for WQ_RT workqueues for even lower
worst case execution latency.

With this, a benchmark which measures the GPU submit latency against a
real-time Vulkan queue when faced with CPU saturation, highlights a
dramatic reduction in maximum observed latencies and further reduction in
the median, and 95- and 98-the percentiles:

    us      7.3.0   WQ_RT   +strict_affinity

   median     30     21           11
    min        2      3            2
    max     1038    941          108
   95pct    2384     49           28
   98pct    2922     63           51

Signed-off-by: Tvrtko Ursulin <[email protected]>
Cc: Boris Brezillon <[email protected]>
Cc: Chia-I Wu <[email protected]>
Cc: Liviu Dudau <[email protected]>
Cc: Matthew Brost <[email protected]>
Cc: Steven Price <[email protected]>
Cc: Tejun Heo <[email protected]>
---
 Documentation/core-api/workqueue.rst |  5 +++--
 kernel/workqueue.c                   | 13 ++++++++++---
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/Documentation/core-api/workqueue.rst 
b/Documentation/core-api/workqueue.rst
index 54697907f2b0..d699c3832b19 100644
--- a/Documentation/core-api/workqueue.rst
+++ b/Documentation/core-api/workqueue.rst
@@ -226,8 +226,9 @@ resources, scheduled and executed.
   implements concurrency management among its workers.
 
 ``WQ_RT``
-  Real-time priority workqueues must be created as unbound. Their worker 
threads
-  use the FIFO scheduling policy with the lowest applicable priority.
+  Real-time priority workqueues must be created as unbound and will be
+  configured with the strict CPU affinity set. Their worker threads use the 
FIFO
+  scheduling policy with the lowest applicable priority.
 
   To be used sparingly for use cases such as the real-time GPU rendering
   contexts accessible to privileged clients.
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 637240667cf7..26a26831bee7 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5723,8 +5723,12 @@ static void
 sanitize_immutable_workqueue_attrs(struct workqueue_struct *wq,
                                   struct workqueue_attrs *attrs)
 {
-       if (wq->flags & WQ_RT)
+       if (wq->flags & WQ_RT) {
                attrs->prio = RT_PRIORITY;
+               /* Strict CPU affinity for low latency execution. */
+               attrs->affn_scope = WQ_AFFN_CPU;
+               attrs->affn_strict = true;
+       }
 
        if (wq->flags & __WQ_ORDERED)
                attrs->ordered = true;
@@ -7847,8 +7851,11 @@ static umode_t wq_sysfs_unbound_group_visible(struct 
kobject *kobj,
        if (!(wq->flags & WQ_UNBOUND))
                return 0;
 
-       /* Do not allow priority changes for RT workers. */
-       if ((wq->flags & WQ_RT) && (attr == &dev_attr_nice.attr))
+       /* Do not allow priority and affinity changes for RT workers. */
+       if ((wq->flags & WQ_RT) &&
+            (attr == &dev_attr_nice.attr ||
+             attr == &dev_attr_affinity_scope.attr ||
+             attr == &dev_attr_affinity_strict.attr))
                return 0444;
 
        return attr->mode;
-- 
2.56.0

Reply via email to