Skip to content

Commit

Permalink
Revert "rcu: Make RCU_FAST_NO_HZ take advantage of numbered callbacks"
Browse files Browse the repository at this point in the history
This reverts commit c0f4dfd.

The above change allows the CPU to enter idle with RCU callbacks pending
for the durations specified in rcu_idle_gp_delay or rcu_idle_lazy_gp_delay.
This was causing a throughput decrease in synchronize_rcu(), as mentioned
by the original author.
These decreases were determined to be too large, as sub- 1 jiffy
synchronize_rcu() latency in cpu idle scenarios was desired.

Reverting this change change in order to start the force_quiescent_state()
state machine upon entering idle, rather than on the scheduler tick()

CRs-Fixed: 887035
Change-Id: I61865131dad751ec0fa14653b2b08b8bada4d061
Signed-off-by: Patrick Daly <[email protected]>
  • Loading branch information
Patrick Daly authored and Ed Tam committed Sep 9, 2015
1 parent 96e6824 commit fd469cd
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 129 deletions.
17 changes: 7 additions & 10 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -580,16 +580,13 @@ config RCU_FAST_NO_HZ
depends on NO_HZ_COMMON && SMP
default n
help
This option permits CPUs to enter dynticks-idle state even if
they have RCU callbacks queued, and prevents RCU from waking
these CPUs up more than roughly once every four jiffies (by
default, you can adjust this using the rcutree.rcu_idle_gp_delay
parameter), thus improving energy efficiency. On the other
hand, this option increases the duration of RCU grace periods,
for example, slowing down synchronize_rcu().

Say Y if energy efficiency is critically important, and you
don't care about increased grace-period durations.
This option causes RCU to attempt to accelerate grace periods in
order to allow CPUs to enter dynticks-idle state more quickly.
On the other hand, this option increases the overhead of the
dynticks-idle checking, thus degrading scheduling latency.

Say Y if energy efficiency is critically important, and you don't
care about real-time response.

Say N if you are unsure.

Expand Down
28 changes: 11 additions & 17 deletions kernel/rcutree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2787,27 +2787,19 @@ static int rcu_pending(int cpu)
}

/*
* Return true if the specified CPU has any callback. If all_lazy is
* non-NULL, store an indication of whether all callbacks are lazy.
* (If there are no callbacks, all of them are deemed to be lazy.)
* Check to see if any future RCU-related work will need to be done
* by the current CPU, even if none need be done immediately, returning
* 1 if so.
*/
static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
static int rcu_cpu_has_callbacks(int cpu)
{
bool al = true;
bool hc = false;
struct rcu_data *rdp;
struct rcu_state *rsp;

for_each_rcu_flavor(rsp) {
rdp = per_cpu_ptr(rsp->rda, cpu);
if (rdp->qlen != rdp->qlen_lazy)
al = false;
if (rdp->nxtlist)
hc = true;
}
if (all_lazy)
*all_lazy = al;
return hc;
/* RCU callbacks either ready or pending? */
for_each_rcu_flavor(rsp)
if (per_cpu_ptr(rsp->rda, cpu)->nxtlist)
return 1;
return 0;
}

/*
Expand Down Expand Up @@ -3026,6 +3018,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
atomic_set(&rdp->dynticks->dynticks,
(atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
rcu_prepare_for_idle_init(cpu);
raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */

/* Add CPU to rcu_node bitmasks. */
Expand Down Expand Up @@ -3094,6 +3087,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
case CPU_DYING_FROZEN:
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
rcu_cleanup_after_idle(cpu);
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
Expand Down
14 changes: 11 additions & 3 deletions kernel/rcutree.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,20 @@ struct rcu_dynticks {
int dynticks_nmi_nesting; /* Track NMI nesting level. */
atomic_t dynticks; /* Even value for idle, else odd. */
#ifdef CONFIG_RCU_FAST_NO_HZ
bool all_lazy; /* Are all CPU's CBs lazy? */
int dyntick_drain; /* Prepare-for-idle state variable. */
unsigned long dyntick_holdoff;
/* No retries for the jiffy of failure. */
struct timer_list idle_gp_timer;
/* Wake up CPU sleeping with callbacks. */
unsigned long idle_gp_timer_expires;
/* When to wake up CPU (for repost). */
bool idle_first_pass; /* First pass of attempt to go idle? */
unsigned long nonlazy_posted;
/* # times non-lazy CBs posted to CPU. */
unsigned long nonlazy_posted_snap;
/* idle-period nonlazy_posted snapshot. */
unsigned long last_accelerate;
/* Last jiffy CBs were accelerated. */
unsigned long last_advance_all;
/* Last jiffy CBs were all advanced. */
int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
};
Expand Down Expand Up @@ -520,6 +527,7 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
struct rcu_node *rnp);
#endif /* #ifdef CONFIG_RCU_BOOST */
static void __cpuinit rcu_prepare_kthreads(int cpu);
static void rcu_prepare_for_idle_init(int cpu);
static void rcu_cleanup_after_idle(int cpu);
static void rcu_prepare_for_idle(int cpu);
static void rcu_idle_count_callbacks_posted(void);
Expand Down
Loading

0 comments on commit fd469cd

Please sign in to comment.