This series makes the NAPI/queue/IRQ relationship visible to the network
stack and then builds net/dynthread on top of it, a loadable module that
adapts the NAPI processing and the RX queue IRQ placement of a set of
net devices to the scheduling behaviour of a target application at
runtime.
Motivation
----------
Interrupt and softirq processing of network RX competes with latency
sensitive applications (e.g. mysqld) for CPU time. When such an
application runs for a long time on a CPU without blocking, the softirq
work of the NIC completion queues can preempt it on the same CPU and
inflate its tail latency. The usual remedies are to steer the RX queue
IRQs to other CPUs and/or to move NAPI processing into kernel threads
bound to spare CPUs, but a static configuration cannot follow the
application: once the target goes idle, is scheduled in short bursts, or
is displaced, the reserved CPUs are simply wasted.
To do this from a module, the queue a NAPI instance serves, the NAPI
instance of a queue and the interrupt vector of that NAPI must be
discoverable. Mainline added that association in v6.8/v6.9 (queue/NAPI
pointer, netif_napi_set_irq(), mlx5e conversion and the RTNL fixes that
come with it). Patches 1-6 of this series backport that infrastructure
and the necessary mlx5e corrections; patches 7-12 add the scheduler.
Approach
--------
The module periodically samples the scheduling statistics of all
threads matching the appname module parameter and classifies them into
one of five statuses (DATA_LOSS, NO_TASK, NOT_RUNNING, FRAGMENTATION,
LONG_RUNNING_WITH_INTERRUPTS). Acting on that status it:
- restores the RX queue IRQs to their original affinity when the
target is gone or barely running;
- spreads the IRQs over the NUMA node of their queues when processing
in softirq context is acceptable again;
- switches the NAPI processing of the configured net devices to
kernel threads and binds the NAPI threads (and, optionally, the
queue IRQs) to the CPUs of their NUMA node that the target tasks
are not allowed to use;
- scales the number of CPUs used by those threads with their measured
load while the target stays in the long-running status.
An unusable sample (counters moved backwards: DATA_LOSS) keeps the
previous status, so a single bad sample cannot toggle the mode.
Everything is controlled through module parameters, and the original
IRQ affinity and NAPI mode are restored when the target disappears,
the scheduler is disabled or the module is unloaded. The module is
buildable only as a loadable module; the Kconfig entry currently
allows ARM64.
Patch breakdown
---------------
1/12 net: Add queue and napi association
Backport the queue <-> NAPI mapping: add enum netdev_queue_type, a
napi pointer to struct netdev_queue and struct netdev_rx_queue, and
netif_queue_set_napi() to set or clear it for RX and TX queues. The
netdev_queue field is added through the KABI helpers so the layout
of the structure is preserved.
2/12 net: Add NAPI IRQ support
Add napi->irq and netif_napi_set_irq(), so a driver can publish the
interrupt vector that serves a NAPI instance. It is initialized to
-1 by netif_napi_add_weight() and stays unknown for drivers that do
not call the setter.
3/12 net/mlx5e: link NAPI instances to queues and IRQs
Make mlx5e call netif_napi_set_irq() when a channel is opened and
register/clear the queue/NAPI association for its RX and TX queues
(including the PTP queues) when they are activated/deactivated. This
is also what users of the queue GET netlink API expect.
4/12 net/mlx5e: Acquire RTNL lock before RQs/SQs activation/deactivation
netif_queue_set_napi() asserts RTNL for a registered netdev, so take
the lock in the mlx5e TX reporter recovery paths that activate or
deactivate queues without it.
5/12 net/mlx5e: Fix lock order in
mlx5e_tx_reporter_ptpsq_unhealthy_recover
The RTNL has to be acquired before priv->state_lock in the PTP SQ
recovery. Move the lock acquisition up so the order matches the
probe and channel switch paths.
6/12 net/mlx5e: Do not block on RTNL while recovering an SQ
The recovery callbacks run synchronously from
devlink_health_report()
under the devlink lock, from SQ work items, while channel teardown
holds the RTNL and waits for those work items with
cancel_work_sync().
Replace the blocking rtnl_lock() with rtnl_trylock() and abandon the
recovery when the SQ has been disabled by the teardown, following
the
existing mlx5e_tx_timeout_work() pattern. This avoids a deadlock
that
also stalled all devlink operations on the device.
7/12 net: dynthread: Add dynamic threaded NAPI scheduler framework
Wire the new directory into net/Kconfig and net/Makefile, add the
NET_DYNTHREAD Kconfig entry and the module skeleton. On load the
module takes a reference on each device given with the '#' separated
ifname parameter, walks the IRQ descriptor table through the
exported irq_get_irq_data(), snapshots desc->action and the
effective
affinity under desc->lock, and records the IRQ number and the
original affinity CPU of every RX queue. IRQs are matched against
the device name, its parent device name and the irqname pattern.
Also count the NUMA nodes the recorded queues span, drop the device
references on unload, and unwind a partially failed init.
8/12 net: dynthread: Monitor the load of the target tasks
Add the sampling loop and the status judgement. Every monitored
thread whose name matches appname contributes its runtime,
voluntary/involuntary context switches and its allowed CPU mask;
the masks are unioned to know where the target may run. The sample
is compared with the previous one to derive the average runtime per
switch, the nvcsw percentage and the CPU load, and to classify it as
DATA_LOSS, NO_TASK, NOT_RUNNING, FRAGMENTATION or
LONG_RUNNING_WITH_INTERRUPTS. Add the periodic hrtimer/work worker,
the dynthreaded enable/disable parameter, a mutex serializing the
worker control, a zeroed baseline on every enable, and the
last_status tracking used to carry the transition sample.
9/12 net: dynthread: Steer the RX queue IRQs away from the target tasks
Manage the affinity of the recorded RX queue IRQs. When the target
tasks sit in a single NUMA node and enough CPUs of that node are
free, move all queue IRQs there round-robin; when the target is
gone or barely running, restore the affinity recorded at load time;
when the target is fragmented, spread the IRQs over a subset of
their own NUMA node sized from dyn_threaded_irq_cpucore_per. Track
the "bound to one node" state so spreading is suppressed while it
is active, and clear it on every recovery. All of this is skipped
when dyn_threaded_bindirq is off, and the IRQ affinity is restored
when the worker is stopped.
10/12 net: dynthread: Switch NAPI to threads on spare CPUs
Enable threaded NAPI (dev_set_threaded) on the monitored devices in
LONG_RUNNING_WITH_INTERRUPTS and bind each NAPI thread from the NUMA
node of its queue IRQ: use the whole node if the target is not
there,
the target-free CPUs of the node if any, otherwise the first
dyn_threaded_corenum CPUs of the node. Use napi->irq when the driver
published it and fall back to the RX queue IRQ recorded by the
module
(e.g. hns3) otherwise. Optionally bind the queue IRQ to the same
mask. Record the CPUs used by the NAPI threads in napi_cpumask for
the load evaluation of the next patch. Switch the devices back to
softirq mode in NO_TASK, NOT_RUNNING and FRAGMENTATION, when the
scheduler is disabled and on module unload; the NAPI and IRQ
operations run under the rtnetlink lock.
11/12 net: dynthread: Scale the number of NAPI thread CPUs
Sample the kernel_cpustat of the CPUs used by the NAPI threads and
compare consecutive periods. Grow dyn_threaded_corenum when the
irq/softirq share or the total load of those CPUs is too high, and
shrink it when the user share is high or the total load is low,
within the lower/upper limit parameters. Damping and anti-fight
rules avoid oscillating right after a change or undoing a change
made for the opposite reason; the two total-load driven directions
check each other, and the cpustat baseline is taken over the mask
that was actually just bound. The default core count is computed at
init from the busiest device's RX queue count divided by the online
NUMA nodes and clamped to the limits. Reset the damping state and
the baseline when leaving the long-running status or when the
scheduler is stopped, and serialize the core-count updates with the
module parameter setter.
12/12 net: dynthread: Add debug switch and instrumentation
Add the dyn_threaded_debug module parameter and instrument the
periodic sampling, the status transitions, the IRQ affinity
decisions, the NAPI thread masks and the CPU-count resizes. The
messages are recorded with trace_printk() so they can be read from
tracefs without flooding the console; without tracing support they
fall back to dynamic debug. The switch is off by default.
Amritha Nambiar (2):
net: Add queue and napi association
net: Add NAPI IRQ support
Cai Xinchen (7):
net/mlx5e: Do not block on RTNL while recovering an SQ
net: dynthread: Add dynamic threaded NAPI scheduler framework
net: dynthread: Monitor the load of the target tasks
net: dynthread: Steer the RX queue IRQs away from the target tasks
net: dynthread: Switch NAPI to threads on spare CPUs
net: dynthread: Scale the number of NAPI thread CPUs
net: dynthread: Add debug switch and instrumentation
Carolina Jubran (1):
net/mlx5e: Acquire RTNL lock before RQs/SQs activation/deactivation
Cosmin Ratiu (1):
net/mlx5e: Fix lock order in mlx5e_tx_reporter_ptpsq_unhealthy_recover
Joe Damato (1):
net/mlx5e: link NAPI instances to queues and IRQs
arch/arm64/configs/openeuler_defconfig | 1 +
.../net/ethernet/mellanox/mlx5/core/en/ptp.c | 5 +-
.../mellanox/mlx5/core/en/reporter_tx.c | 25 +
.../net/ethernet/mellanox/mlx5/core/en_main.c | 7 +
include/linux/netdevice.h | 21 +-
include/net/netdev_rx_queue.h | 2 +-
net/Kconfig | 1 +
net/Makefile | 1 +
net/core/dev.c | 38 +
net/dynthread/Kconfig | 13 +
net/dynthread/Makefile | 2 +
net/dynthread/net_dynthread.c | 1375 +++++++++++++++++
12 files changed, 1487 insertions(+), 4 deletions(-)
create mode 100644 net/dynthread/Kconfig
create mode 100644 net/dynthread/Makefile
create mode 100644 net/dynthread/net_dynthread.c
--
2.18.0.huawei.25