Skip to content
This repository has been archived by the owner on Dec 2, 2020. It is now read-only.

Commit

Permalink
rcu: Speed up calling of RCU tasks callbacks
Browse files Browse the repository at this point in the history
Joel Fernandes found that the synchronize_rcu_tasks() was taking a
significant amount of time. He demonstrated it with the following test:

 # cd /sys/kernel/tracing
 # while [ 1 ]; do x=1; done &
 # echo '__schedule_bug:traceon' > set_ftrace_filter
 # time echo '!__schedule_bug:traceon' > set_ftrace_filter;

real	0m1.064s
user	0m0.000s
sys	0m0.004s

Where it takes a little over a second to perform the synchronize,
because there's a loop that waits 1 second at a time for tasks to get
through their quiescent points when there's a task that must be waited
for.

After discussion we came up with a simple way to wait for holdouts but
increase the time for each iteration of the loop but no more than a
full second.

With the new patch we have:

 # time echo '!__schedule_bug:traceon' > set_ftrace_filter;

real	0m0.131s
user	0m0.000s
sys	0m0.004s

Which drops it down to 13% of what the original wait time was.

Link: http://lkml.kernel.org/r/20180523063815.198302-2-joel@joelfernandes.org
Reported-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Suggested-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: celtare21 <celtare21@gmail.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: laststandrighthere <laststandrighthere@gmail.com>
Signed-off-by: Lau <laststandrighthere@gmail.com>
  • Loading branch information
rostedt authored and dracarys18 committed Sep 17, 2020
1 parent 8dbbc91 commit 65e156e
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions kernel/rcu/update.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
struct rcu_head *list;
struct rcu_head *next;
LIST_HEAD(rcu_tasks_holdouts);
int fract;

/* Run on housekeeping CPUs by default. Sysadm can move if desired. */
housekeeping_affine(current);
Expand Down Expand Up @@ -735,13 +736,25 @@ static int __noreturn rcu_tasks_kthread(void *arg)
* holdouts. When the list is empty, we are done.
*/
lastreport = jiffies;
while (!list_empty(&rcu_tasks_holdouts)) {

/* Start off with HZ/10 wait and slowly back off to 1 HZ wait*/
fract = 10;

for (;;) {
bool firstreport;
bool needreport;
int rtst;
struct task_struct *t1;

schedule_timeout_interruptible(HZ);
if (list_empty(&rcu_tasks_holdouts))
break;

/* Slowly back off waiting for holdouts */
schedule_timeout_interruptible(HZ/fract);

if (fract > 1)
fract--;

rtst = READ_ONCE(rcu_task_stall_timeout);
needreport = rtst > 0 &&
time_after(jiffies, lastreport + rtst);
Expand Down

0 comments on commit 65e156e

Please sign in to comment.