This series makes the NAPI/queue/IRQ relationship visible to the network
stack, backports the drivers and locking fixes it needs, 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) together
with the RTNL fixes it requires. Patches 1-8 of this series backport
that infrastructure, adapt it to the OLK KABI layout and fix the mlx5e
lock ordering; patches 9-14 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 and it is enabled in the arm64 openeuler defconfig.
Patch breakdown
---------------
1/14 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
new netdev_queue field is put into reserve space so the layout of
the structure is preserved.
2/14 net: fix KABI breakage for queue napi association
Keep the struct layout stable across the backport: use the reserved
domain segment of KABI 1 for netdev_queue and KABI 2 for
netdev_rx_queue.
3/14 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. The ice and netdev-genl/netlink parts of the
upstream patch are not needed here and are dropped.
4/14 net: Fix napi irq KABI breakage
Store napi->irq in the reserved domain segment of KABI 1 so that the
napi_struct layout does not change.
5/14 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.
6/14 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.
7/14 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.
8/14 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.
9/14 net: dynthread: Add dynamic threaded NAPI scheduler framework
Wire the new directory into net/Kconfig and net/Makefile, add the
NET_DYNTHREAD Kconfig entry (ARM64, module only) 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.
10/14 net: dynthread: Monitor the load of the target tasks
Add the sampling loop and the status judgement. Every
dyn_threaded_interval ms, 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.
11/14 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.
12/14 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. The NAPI list is built by head insertion, so
it is walked in reverse to visit the NAPIs in registration (vector)
order, matching the ascending order in which the RX queue IRQs are
recorded. 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.
13/14 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. The lower/upper limit parameters reject zero and an
inverted range, refuse a change that would move the computed default
out of range, and clamp the current core count into the new range.
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.
14/14 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
JiangJieHua (2):
net: fix KABI breakage for queue napi association
net: Fix napi irq KABI breakage
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 | 23 +
.../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 | 1493 +++++++++++++++++
12 files changed, 1603 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