rcu: Expedite first two FQS scans under callback-overload conditions
authorPaul E. McKenney <paulmck@kernel.org>
Sun, 23 Feb 2020 04:07:09 +0000 (20:07 -0800)
committerPaul E. McKenney <paulmck@kernel.org>
Mon, 27 Apr 2020 18:01:16 +0000 (11:01 -0700)
Even if some CPUs have excessive numbers of callbacks, RCU's grace-period
kthread will still wait normally between successive force-quiescent-state
scans.  The first two are the most important, as they are the ones that
enlist aid from the scheduler when overloaded.  This commit therefore
omits the wait before the first and the second force-quiescent-state
scan under callback-overload conditions.

This approach was inspired by a discussion with Jeff Roberson.

Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
kernel/rcu/tree.c
kernel/rcu/tree.h

index c88240a685ec81ca6f0078641a7961563069ce60..0132bc6152dde4f3ba589fd29ea83308710d3a16 100644 (file)
@@ -1624,12 +1624,16 @@ static bool rcu_gp_fqs_check_wake(int *gfp)
 {
        struct rcu_node *rnp = rcu_get_root();
 
-       /* Someone like call_rcu() requested a force-quiescent-state scan. */
+       // If under overload conditions, force an immediate FQS scan.
+       if (*gfp & RCU_GP_FLAG_OVLD)
+               return true;
+
+       // Someone like call_rcu() requested a force-quiescent-state scan.
        *gfp = READ_ONCE(rcu_state.gp_flags);
        if (*gfp & RCU_GP_FLAG_FQS)
                return true;
 
-       /* The current grace period has completed. */
+       // The current grace period has completed.
        if (!READ_ONCE(rnp->qsmask) && !rcu_preempt_blocked_readers_cgp(rnp))
                return true;
 
@@ -1667,13 +1671,15 @@ static void rcu_gp_fqs(bool first_time)
 static void rcu_gp_fqs_loop(void)
 {
        bool first_gp_fqs;
-       int gf;
+       int gf = 0;
        unsigned long j;
        int ret;
        struct rcu_node *rnp = rcu_get_root();
 
        first_gp_fqs = true;
        j = READ_ONCE(jiffies_till_first_fqs);
+       if (rcu_state.cbovld)
+               gf = RCU_GP_FLAG_OVLD;
        ret = 0;
        for (;;) {
                if (!ret) {
@@ -1698,7 +1704,11 @@ static void rcu_gp_fqs_loop(void)
                        trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsstart"));
                        rcu_gp_fqs(first_gp_fqs);
-                       first_gp_fqs = false;
+                       gf = 0;
+                       if (first_gp_fqs) {
+                               first_gp_fqs = false;
+                               gf = rcu_state.cbovld ? RCU_GP_FLAG_OVLD : 0;
+                       }
                        trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsend"));
                        cond_resched_tasks_rcu_qs();
@@ -1718,6 +1728,7 @@ static void rcu_gp_fqs_loop(void)
                                j = 1;
                        else
                                j = rcu_state.jiffies_force_qs - j;
+                       gf = 0;
                }
        }
 }
index 9dc2ec021da523a4d418034e044f3ce3df1b9a6a..44edd0a98ffe042420c0a3ce13f30704294596ef 100644 (file)
@@ -359,6 +359,7 @@ struct rcu_state {
 /* Values for rcu_state structure's gp_flags field. */
 #define RCU_GP_FLAG_INIT 0x1   /* Need grace-period initialization. */
 #define RCU_GP_FLAG_FQS  0x2   /* Need grace-period quiescent-state forcing. */
+#define RCU_GP_FLAG_OVLD 0x4   /* Experiencing callback overload. */
 
 /* Values for rcu_state structure's gp_state field. */
 #define RCU_GP_IDLE     0      /* Initial state and no GP in progress. */