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>
This commit is contained in:
parent
045fb9315a
commit
433cdddcd9
|
@ -274,6 +274,42 @@ TRACE_EVENT(rcu_dyntick,
|
||||||
__entry->oldnesting, __entry->newnesting)
|
__entry->oldnesting, __entry->newnesting)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tracepoint for RCU preparation for idle, the goal being to get RCU
|
||||||
|
* processing done so that the current CPU can shut off its scheduling
|
||||||
|
* clock and enter dyntick-idle mode. One way to accomplish this is
|
||||||
|
* to drain all RCU callbacks from this CPU, and the other is to have
|
||||||
|
* done everything RCU requires for the current grace period. In this
|
||||||
|
* latter case, the CPU will be awakened at the end of the current grace
|
||||||
|
* period in order to process the remainder of its callbacks.
|
||||||
|
*
|
||||||
|
* These tracepoints take a string as argument:
|
||||||
|
*
|
||||||
|
* "No callbacks": Nothing to do, no callbacks on this CPU.
|
||||||
|
* "In holdoff": Nothing to do, holding off after unsuccessful attempt.
|
||||||
|
* "Dyntick with callbacks": Callbacks remain, but RCU doesn't need CPU.
|
||||||
|
* "Begin holdoff": Attempt failed, don't retry until next jiffy.
|
||||||
|
* "More callbacks": Still more callbacks, try again to clear them out.
|
||||||
|
* "Callbacks drained": All callbacks processed, off to dyntick idle!
|
||||||
|
* "CPU awakened at GP end":
|
||||||
|
*/
|
||||||
|
TRACE_EVENT(rcu_prep_idle,
|
||||||
|
|
||||||
|
TP_PROTO(char *reason),
|
||||||
|
|
||||||
|
TP_ARGS(reason),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(char *, reason)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->reason = reason;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("%s", __entry->reason)
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tracepoint for the registration of a single RCU callback function.
|
* Tracepoint for the registration of a single RCU callback function.
|
||||||
* The first argument is the type of RCU, the second argument is
|
* The first argument is the type of RCU, the second argument is
|
||||||
|
@ -482,6 +518,7 @@ TRACE_EVENT(rcu_torture_read,
|
||||||
#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0)
|
#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0)
|
||||||
#define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0)
|
#define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0)
|
||||||
#define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0)
|
#define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0)
|
||||||
|
#define trace_rcu_prep_idle(reason) do { } while (0)
|
||||||
#define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0)
|
#define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0)
|
||||||
#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0)
|
#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0)
|
||||||
#define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0)
|
#define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0)
|
||||||
|
|
|
@ -2031,10 +2031,13 @@ static void rcu_prepare_for_idle(int cpu)
|
||||||
/* If no callbacks or in the holdoff period, enter dyntick-idle. */
|
/* If no callbacks or in the holdoff period, enter dyntick-idle. */
|
||||||
if (!rcu_cpu_has_callbacks(cpu)) {
|
if (!rcu_cpu_has_callbacks(cpu)) {
|
||||||
per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1;
|
per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1;
|
||||||
|
trace_rcu_prep_idle("No callbacks");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (per_cpu(rcu_dyntick_holdoff, cpu) == jiffies)
|
if (per_cpu(rcu_dyntick_holdoff, cpu) == jiffies) {
|
||||||
|
trace_rcu_prep_idle("In holdoff");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check and update the rcu_dyntick_drain sequencing. */
|
/* Check and update the rcu_dyntick_drain sequencing. */
|
||||||
if (per_cpu(rcu_dyntick_drain, cpu) <= 0) {
|
if (per_cpu(rcu_dyntick_drain, cpu) <= 0) {
|
||||||
|
@ -2044,9 +2047,11 @@ static void rcu_prepare_for_idle(int cpu)
|
||||||
/* We have hit the limit, so time to give up. */
|
/* We have hit the limit, so time to give up. */
|
||||||
per_cpu(rcu_dyntick_holdoff, cpu) = jiffies;
|
per_cpu(rcu_dyntick_holdoff, cpu) = jiffies;
|
||||||
if (!rcu_pending(cpu)) {
|
if (!rcu_pending(cpu)) {
|
||||||
|
trace_rcu_prep_idle("Dyntick with callbacks");
|
||||||
per_cpu(rcu_awake_at_gp_end, cpu) = 1;
|
per_cpu(rcu_awake_at_gp_end, cpu) = 1;
|
||||||
return; /* Nothing to do immediately. */
|
return; /* Nothing to do immediately. */
|
||||||
}
|
}
|
||||||
|
trace_rcu_prep_idle("Begin holdoff");
|
||||||
invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */
|
invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2073,9 +2078,15 @@ static void rcu_prepare_for_idle(int cpu)
|
||||||
c = c || per_cpu(rcu_bh_data, cpu).nxtlist;
|
c = c || per_cpu(rcu_bh_data, cpu).nxtlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If RCU callbacks are still pending, RCU still needs this CPU. */
|
/*
|
||||||
if (c)
|
* If RCU callbacks are still pending, RCU still needs this CPU.
|
||||||
|
* So try forcing the callbacks through the grace period.
|
||||||
|
*/
|
||||||
|
if (c) {
|
||||||
|
trace_rcu_prep_idle("More callbacks");
|
||||||
invoke_rcu_core();
|
invoke_rcu_core();
|
||||||
|
} else
|
||||||
|
trace_rcu_prep_idle("Callbacks drained");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2085,6 +2096,7 @@ static void rcu_prepare_for_idle(int cpu)
|
||||||
*/
|
*/
|
||||||
static void rcu_wake_cpu(void *unused)
|
static void rcu_wake_cpu(void *unused)
|
||||||
{
|
{
|
||||||
|
trace_rcu_prep_idle("CPU awakened at GP end");
|
||||||
invoke_rcu_core();
|
invoke_rcu_core();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue