Skip to content

Commit ab97152

Browse files
committed
rcu-tasks: Use more callback queues if contention encountered
The rcupdate.rcu_task_enqueue_lim module parameter allows system administrators to tune the number of callback queues used by the RCU Tasks flavors. However if callback storms are infrequent, it would be better to operate with a single queue on a given system unless and until that system actually needed more queues. Systems not needing more queues can then avoid the overhead of checking the extra queues and especially avoid the overhead of fanning workqueue handlers out to all CPUs to invoke callbacks. This commit therefore switches to using all the CPUs' callback queues if call_rcu_tasks_generic() encounters too much lock contention. The amount of lock contention to tolerate defaults to 100 contended lock acquisitions per jiffy, and can be adjusted using the new rcupdate.rcu_task_contend_lim module parameter. Such switching is undertaken only if the rcupdate.rcu_task_enqueue_lim module parameter is negative, which is its default value (-1). This allows savvy systems administrators to set the number of queues to some known good value and to not have to worry about the kernel doing any second guessing. [ paulmck: Apply feedback from Guillaume Tucker and kernelci. ] Reported-by: Martin Lau <kafai@fb.com> Cc: Neeraj Upadhyay <neeraj.iitr10@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 3063b33 commit ab97152

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4805,6 +4805,14 @@
48054805
period to instead use normal non-expedited
48064806
grace-period processing.
48074807

4808+
rcupdate.rcu_task_contend_lim= [KNL]
4809+
Set the minimum number of callback-queuing-time
4810+
lock-contention events per jiffy required to
4811+
cause the RCU Tasks flavors to switch to per-CPU
4812+
callback queuing. This switching only occurs
4813+
when rcupdate.rcu_task_enqueue_lim is set to
4814+
the default value of -1.
4815+
48084816
rcupdate.rcu_task_enqueue_lim= [KNL]
48094817
Set the number of callback queues to use for the
48104818
RCU Tasks family of RCU flavors. The default

kernel/rcu/tasks.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ module_param(rcu_task_stall_timeout, int, 0644);
142142
static int rcu_task_enqueue_lim __read_mostly = -1;
143143
module_param(rcu_task_enqueue_lim, int, 0444);
144144

145+
static bool rcu_task_cb_adjust;
146+
static int rcu_task_contend_lim __read_mostly = 100;
147+
module_param(rcu_task_contend_lim, int, 0444);
148+
145149
/* RCU tasks grace-period state for debugging. */
146150
#define RTGS_INIT 0
147151
#define RTGS_WAIT_WAIT_CBS 1
@@ -207,10 +211,13 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
207211
int lim;
208212

209213
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
210-
if (rcu_task_enqueue_lim < 0)
211-
rcu_task_enqueue_lim = nr_cpu_ids;
212-
else if (rcu_task_enqueue_lim == 0)
214+
if (rcu_task_enqueue_lim < 0) {
215+
rcu_task_enqueue_lim = 1;
216+
rcu_task_cb_adjust = true;
217+
pr_info("%s: Setting adjustable number of callback queues.\n", __func__);
218+
} else if (rcu_task_enqueue_lim == 0) {
213219
rcu_task_enqueue_lim = 1;
220+
}
214221
lim = rcu_task_enqueue_lim;
215222

216223
if (lim > nr_cpu_ids)
@@ -251,6 +258,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
251258
{
252259
unsigned long flags;
253260
unsigned long j;
261+
bool needadjust = false;
254262
bool needwake;
255263
struct rcu_tasks_percpu *rtpcp;
256264

@@ -266,7 +274,9 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
266274
rtpcp->rtp_jiffies = j;
267275
rtpcp->rtp_n_lock_retries = 0;
268276
}
269-
rtpcp->rtp_n_lock_retries++;
277+
if (rcu_task_cb_adjust && ++rtpcp->rtp_n_lock_retries > rcu_task_contend_lim &&
278+
READ_ONCE(rtp->percpu_enqueue_lim) != nr_cpu_ids)
279+
needadjust = true; // Defer adjustment to avoid deadlock.
270280
}
271281
if (!rcu_segcblist_is_enabled(&rtpcp->cblist)) {
272282
raw_spin_unlock_rcu_node(rtpcp); // irqs remain disabled.
@@ -276,6 +286,15 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
276286
needwake = rcu_segcblist_empty(&rtpcp->cblist);
277287
rcu_segcblist_enqueue(&rtpcp->cblist, rhp);
278288
raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
289+
if (unlikely(needadjust)) {
290+
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
291+
if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
292+
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids));
293+
smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
294+
pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
295+
}
296+
raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
297+
}
279298
/* We can't create the thread unless interrupts are enabled. */
280299
if (needwake && READ_ONCE(rtp->kthread_ptr))
281300
irq_work_queue(&rtpcp->rtp_irq_work);

0 commit comments

Comments
 (0)