diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-08-14 19:24:26 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-09-23 12:18:13 -0400 |
commit | 9261dd0da6c6432f08670719069449c6efe4f7a9 (patch) | |
tree | b8c95dd0e4751e3069e9263d6f46b86251d5dc35 | |
parent | bb311eccbdab974639263060b8452bf304af0b0c (diff) |
rcu: Add tracing for rcuo no-CBs CPU wakeup handshake
Lost wakeups from call_rcu() to the rcuo kthreads can result in hangs
that are difficult to diagnose. This commit therefore adds tracing to
help pin down the cause of these hangs.
Reported-by: Clark Williams <williams@redhat.com>
Reported-by: Carsten Emde <C.Emde@osadl.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
[ paulmck: Add const per kbuild test robot's advice. ]
-rw-r--r-- | include/trace/events/rcu.h | 37 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 14 |
2 files changed, 50 insertions, 1 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index 98466c618ebc..4301cd9e3ee5 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -172,6 +172,42 @@ TRACE_EVENT(rcu_grace_period_init, | |||
172 | ); | 172 | ); |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Tracepoint for RCU no-CBs CPU callback handoffs. This event is intended | ||
176 | * to assist debugging of these handoffs. | ||
177 | * | ||
178 | * The first argument is the name of the RCU flavor, and the second is | ||
179 | * the number of the offloaded CPU are extracted. The third and final | ||
180 | * argument is a string as follows: | ||
181 | * | ||
182 | * "WakeEmpty": Wake rcuo kthread, first CB to empty list. | ||
183 | * "WakeOvf": Wake rcuo kthread, CB list is huge. | ||
184 | * "WakeNot": Don't wake rcuo kthread. | ||
185 | * "WakeNotPoll": Don't wake rcuo kthread because it is polling. | ||
186 | * "WokeEmpty": rcuo kthread woke to find empty list. | ||
187 | * "WokeNonEmpty": rcuo kthread woke to find non-empty list. | ||
188 | */ | ||
189 | TRACE_EVENT(rcu_nocb_wake, | ||
190 | |||
191 | TP_PROTO(const char *rcuname, int cpu, const char *reason), | ||
192 | |||
193 | TP_ARGS(rcuname, cpu, reason), | ||
194 | |||
195 | TP_STRUCT__entry( | ||
196 | __field(const char *, rcuname) | ||
197 | __field(int, cpu) | ||
198 | __field(const char *, reason) | ||
199 | ), | ||
200 | |||
201 | TP_fast_assign( | ||
202 | __entry->rcuname = rcuname; | ||
203 | __entry->cpu = cpu; | ||
204 | __entry->reason = reason; | ||
205 | ), | ||
206 | |||
207 | TP_printk("%s %d %s", __entry->rcuname, __entry->cpu, __entry->reason) | ||
208 | ); | ||
209 | |||
210 | /* | ||
175 | * Tracepoint for tasks blocking within preemptible-RCU read-side | 211 | * Tracepoint for tasks blocking within preemptible-RCU read-side |
176 | * critical sections. Track the type of RCU (which one day might | 212 | * critical sections. Track the type of RCU (which one day might |
177 | * include SRCU), the grace-period number that the task is blocking | 213 | * include SRCU), the grace-period number that the task is blocking |
@@ -667,6 +703,7 @@ TRACE_EVENT(rcu_barrier, | |||
667 | #define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \ | 703 | #define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \ |
668 | level, grplo, grphi, event) \ | 704 | level, grplo, grphi, event) \ |
669 | do { } while (0) | 705 | do { } while (0) |
706 | #define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0) | ||
670 | #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) | 707 | #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) |
671 | #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) | 708 | #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) |
672 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \ | 709 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \ |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 130c97b027f2..f4ed24b18e77 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -2108,15 +2108,22 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp, | |||
2108 | 2108 | ||
2109 | /* If we are not being polled and there is a kthread, awaken it ... */ | 2109 | /* If we are not being polled and there is a kthread, awaken it ... */ |
2110 | t = ACCESS_ONCE(rdp->nocb_kthread); | 2110 | t = ACCESS_ONCE(rdp->nocb_kthread); |
2111 | if (rcu_nocb_poll | !t) | 2111 | if (rcu_nocb_poll | !t) { |
2112 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | ||
2113 | TPS("WakeNotPoll")); | ||
2112 | return; | 2114 | return; |
2115 | } | ||
2113 | len = atomic_long_read(&rdp->nocb_q_count); | 2116 | len = atomic_long_read(&rdp->nocb_q_count); |
2114 | if (old_rhpp == &rdp->nocb_head) { | 2117 | if (old_rhpp == &rdp->nocb_head) { |
2115 | wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */ | 2118 | wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */ |
2116 | rdp->qlen_last_fqs_check = 0; | 2119 | rdp->qlen_last_fqs_check = 0; |
2120 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmpty")); | ||
2117 | } else if (len > rdp->qlen_last_fqs_check + qhimark) { | 2121 | } else if (len > rdp->qlen_last_fqs_check + qhimark) { |
2118 | wake_up_process(t); /* ... or if many callbacks queued. */ | 2122 | wake_up_process(t); /* ... or if many callbacks queued. */ |
2119 | rdp->qlen_last_fqs_check = LONG_MAX / 2; | 2123 | rdp->qlen_last_fqs_check = LONG_MAX / 2; |
2124 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvf")); | ||
2125 | } else { | ||
2126 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeNot")); | ||
2120 | } | 2127 | } |
2121 | return; | 2128 | return; |
2122 | } | 2129 | } |
@@ -2233,10 +2240,15 @@ static int rcu_nocb_kthread(void *arg) | |||
2233 | wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); | 2240 | wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); |
2234 | list = ACCESS_ONCE(rdp->nocb_head); | 2241 | list = ACCESS_ONCE(rdp->nocb_head); |
2235 | if (!list) { | 2242 | if (!list) { |
2243 | if (!rcu_nocb_poll) | ||
2244 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | ||
2245 | TPS("WokeEmpty")); | ||
2236 | schedule_timeout_interruptible(1); | 2246 | schedule_timeout_interruptible(1); |
2237 | flush_signals(current); | 2247 | flush_signals(current); |
2238 | continue; | 2248 | continue; |
2239 | } | 2249 | } |
2250 | trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, | ||
2251 | TPS("WokeNonEmpty")); | ||
2240 | 2252 | ||
2241 | /* | 2253 | /* |
2242 | * Extract queued callbacks, update counts, and wait | 2254 | * Extract queued callbacks, update counts, and wait |