diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2011-11-22 17:58:03 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-12-11 13:32:00 -0500 |
commit | 433cdddcd9ac5558068edd7f8d4707a70f7710f5 (patch) | |
tree | 7f3686eb64c9ee3a239e5920df588c70837c5637 | |
parent | 045fb9315a2129023d70a0eecf0942e18fca4fcd (diff) |
rcu: Add tracing for RCU_FAST_NO_HZ
This commit adds trace_rcu_prep_idle(), which is invoked from
rcu_prepare_for_idle() and rcu_wake_cpu() to trace attempts on
the part of RCU to force CPUs into dyntick-idle mode.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r-- | include/trace/events/rcu.h | 37 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 18 |
2 files changed, 52 insertions, 3 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index 7f6877a35051..debe453c9623 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -275,6 +275,42 @@ TRACE_EVENT(rcu_dyntick, | |||
275 | ); | 275 | ); |
276 | 276 | ||
277 | /* | 277 | /* |
278 | * Tracepoint for RCU preparation for idle, the goal being to get RCU | ||
279 | * processing done so that the current CPU can shut off its scheduling | ||
280 | * clock and enter dyntick-idle mode. One way to accomplish this is | ||
281 | * to drain all RCU callbacks from this CPU, and the other is to have | ||
282 | * done everything RCU requires for the current grace period. In this | ||
283 | * latter case, the CPU will be awakened at the end of the current grace | ||
284 | * period in order to process the remainder of its callbacks. | ||
285 | * | ||
286 | * These tracepoints take a string as argument: | ||
287 | * | ||
288 | * "No callbacks": Nothing to do, no callbacks on this CPU. | ||
289 | * "In holdoff": Nothing to do, holding off after unsuccessful attempt. | ||
290 | * "Dyntick with callbacks": Callbacks remain, but RCU doesn't need CPU. | ||
291 | * "Begin holdoff": Attempt failed, don't retry until next jiffy. | ||
292 | * "More callbacks": Still more callbacks, try again to clear them out. | ||
293 | * "Callbacks drained": All callbacks processed, off to dyntick idle! | ||
294 | * "CPU awakened at GP end": | ||
295 | */ | ||
296 | TRACE_EVENT(rcu_prep_idle, | ||
297 | |||
298 | TP_PROTO(char *reason), | ||
299 | |||
300 | TP_ARGS(reason), | ||
301 | |||
302 | TP_STRUCT__entry( | ||
303 | __field(char *, reason) | ||
304 | ), | ||
305 | |||
306 | TP_fast_assign( | ||
307 | __entry->reason = reason; | ||
308 | ), | ||
309 | |||
310 | TP_printk("%s", __entry->reason) | ||
311 | ); | ||
312 | |||
313 | /* | ||
278 | * Tracepoint for the registration of a single RCU callback function. | 314 | * Tracepoint for the registration of a single RCU callback function. |
279 | * The first argument is the type of RCU, the second argument is | 315 | * The first argument is the type of RCU, the second argument is |
280 | * a pointer to the RCU callback itself, and the third element is the | 316 | * a pointer to the RCU callback itself, and the third element is the |
@@ -482,6 +518,7 @@ TRACE_EVENT(rcu_torture_read, | |||
482 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0) | 518 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0) |
483 | #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) | 519 | #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) |
484 | #define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0) | 520 | #define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0) |
521 | #define trace_rcu_prep_idle(reason) do { } while (0) | ||
485 | #define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0) | 522 | #define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0) |
486 | #define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0) | 523 | #define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0) |
487 | #define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0) | 524 | #define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0) |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index b70ca8cc52e1..6467f5669ab7 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -2031,10 +2031,13 @@ static void rcu_prepare_for_idle(int cpu) | |||
2031 | /* If no callbacks or in the holdoff period, enter dyntick-idle. */ | 2031 | /* If no callbacks or in the holdoff period, enter dyntick-idle. */ |
2032 | if (!rcu_cpu_has_callbacks(cpu)) { | 2032 | if (!rcu_cpu_has_callbacks(cpu)) { |
2033 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; | 2033 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; |
2034 | trace_rcu_prep_idle("No callbacks"); | ||
2034 | return; | 2035 | return; |
2035 | } | 2036 | } |
2036 | if (per_cpu(rcu_dyntick_holdoff, cpu) == jiffies) | 2037 | if (per_cpu(rcu_dyntick_holdoff, cpu) == jiffies) { |
2038 | trace_rcu_prep_idle("In holdoff"); | ||
2037 | return; | 2039 | return; |
2040 | } | ||
2038 | 2041 | ||
2039 | /* Check and update the rcu_dyntick_drain sequencing. */ | 2042 | /* Check and update the rcu_dyntick_drain sequencing. */ |
2040 | if (per_cpu(rcu_dyntick_drain, cpu) <= 0) { | 2043 | if (per_cpu(rcu_dyntick_drain, cpu) <= 0) { |
@@ -2044,9 +2047,11 @@ static void rcu_prepare_for_idle(int cpu) | |||
2044 | /* We have hit the limit, so time to give up. */ | 2047 | /* We have hit the limit, so time to give up. */ |
2045 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies; | 2048 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies; |
2046 | if (!rcu_pending(cpu)) { | 2049 | if (!rcu_pending(cpu)) { |
2050 | trace_rcu_prep_idle("Dyntick with callbacks"); | ||
2047 | per_cpu(rcu_awake_at_gp_end, cpu) = 1; | 2051 | per_cpu(rcu_awake_at_gp_end, cpu) = 1; |
2048 | return; /* Nothing to do immediately. */ | 2052 | return; /* Nothing to do immediately. */ |
2049 | } | 2053 | } |
2054 | trace_rcu_prep_idle("Begin holdoff"); | ||
2050 | invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */ | 2055 | invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */ |
2051 | return; | 2056 | return; |
2052 | } | 2057 | } |
@@ -2073,9 +2078,15 @@ static void rcu_prepare_for_idle(int cpu) | |||
2073 | c = c || per_cpu(rcu_bh_data, cpu).nxtlist; | 2078 | c = c || per_cpu(rcu_bh_data, cpu).nxtlist; |
2074 | } | 2079 | } |
2075 | 2080 | ||
2076 | /* If RCU callbacks are still pending, RCU still needs this CPU. */ | 2081 | /* |
2077 | if (c) | 2082 | * If RCU callbacks are still pending, RCU still needs this CPU. |
2083 | * So try forcing the callbacks through the grace period. | ||
2084 | */ | ||
2085 | if (c) { | ||
2086 | trace_rcu_prep_idle("More callbacks"); | ||
2078 | invoke_rcu_core(); | 2087 | invoke_rcu_core(); |
2088 | } else | ||
2089 | trace_rcu_prep_idle("Callbacks drained"); | ||
2079 | } | 2090 | } |
2080 | 2091 | ||
2081 | /* | 2092 | /* |
@@ -2085,6 +2096,7 @@ static void rcu_prepare_for_idle(int cpu) | |||
2085 | */ | 2096 | */ |
2086 | static void rcu_wake_cpu(void *unused) | 2097 | static void rcu_wake_cpu(void *unused) |
2087 | { | 2098 | { |
2099 | trace_rcu_prep_idle("CPU awakened at GP end"); | ||
2088 | invoke_rcu_core(); | 2100 | invoke_rcu_core(); |
2089 | } | 2101 | } |
2090 | 2102 | ||