rcu: Track rcu_nocb_kthread()'s sleeping and awakening
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Thu, 15 Aug 2013 20:23:23 +0000 (13:23 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 23 Sep 2013 16:18:16 +0000 (09:18 -0700)
This commit adds event traces to track all of rcu_nocb_kthread()'s
blocking and awakening.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
include/trace/events/rcu.h
kernel/rcutree_plugin.h

index 4301cd9..a087d82 100644 (file)
@@ -183,8 +183,12 @@ TRACE_EVENT(rcu_grace_period_init,
  *     "WakeOvf": Wake rcuo kthread, CB list is huge.
  *     "WakeNot": Don't wake rcuo kthread.
  *     "WakeNotPoll": Don't wake rcuo kthread because it is polling.
+ *     "Poll": Start of new polling cycle for rcu_nocb_poll.
+ *     "Sleep": Sleep waiting for CBs for !rcu_nocb_poll.
  *     "WokeEmpty": rcuo kthread woke to find empty list.
  *     "WokeNonEmpty": rcuo kthread woke to find non-empty list.
+ *     "WaitQueue": Enqueue partially done, timed wait for it to complete.
+ *     "WokeQueue": Partial enqueue now complete.
  */
 TRACE_EVENT(rcu_nocb_wake,
 
index 24b01b6..21205b1 100644 (file)
@@ -2230,6 +2230,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
 static int rcu_nocb_kthread(void *arg)
 {
        int c, cl;
+       bool firsttime = 1;
        struct rcu_head *list;
        struct rcu_head *next;
        struct rcu_head **tail;
@@ -2238,8 +2239,15 @@ static int rcu_nocb_kthread(void *arg)
        /* Each pass through this loop invokes one batch of callbacks */
        for (;;) {
                /* If not polling, wait for next batch of callbacks. */
-               if (!rcu_nocb_poll)
+               if (!rcu_nocb_poll) {
+                       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                           TPS("Sleep"));
                        wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head);
+               } else if (firsttime) {
+                       firsttime = 0;
+                       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                           TPS("Poll"));
+               }
                list = ACCESS_ONCE(rdp->nocb_head);
                if (!list) {
                        if (!rcu_nocb_poll)
@@ -2249,6 +2257,7 @@ static int rcu_nocb_kthread(void *arg)
                        flush_signals(current);
                        continue;
                }
+               firsttime = 1;
                trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                    TPS("WokeNonEmpty"));
 
@@ -2271,7 +2280,11 @@ static int rcu_nocb_kthread(void *arg)
                        next = list->next;
                        /* Wait for enqueuing to complete, if needed. */
                        while (next == NULL && &list->next != tail) {
+                               trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                                   TPS("WaitQueue"));
                                schedule_timeout_interruptible(1);
+                               trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                                   TPS("WokeQueue"));
                                next = list->next;
                        }
                        debug_rcu_head_unqueue(list);