aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-08-26 00:20:47 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-09-25 09:44:25 -0400
commitc229828ca6bc62d6c654f64b1d1b8a9ebd8a56f3 (patch)
treeaa97acce16acc6ead3013fecc17bdc51d0d0edda
parent7a497c963eceac42677ce1f5d7bb470abedd15f4 (diff)
rcu: Throttle rcu_try_advance_all_cbs() execution
The rcu_try_advance_all_cbs() function is invoked on each attempted entry to and every exit from idle. If this function determines that there are callbacks ready to invoke, the caller will invoke the RCU core, which in turn will result in a pair of context switches. If a CPU enters and exits idle extremely frequently, this can result in an excessive number of context switches and high CPU overhead. This commit therefore causes rcu_try_advance_all_cbs() to throttle itself, refusing to do work more than once per jiffy. Reported-by: Tibor Billes <tbilles@gmx.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Tested-by: Tibor Billes <tbilles@gmx.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
-rw-r--r--kernel/rcutree.h2
-rw-r--r--kernel/rcutree_plugin.h12
2 files changed, 11 insertions, 3 deletions
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 5f97eab602cd..52be957c9fe2 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -104,6 +104,8 @@ struct rcu_dynticks {
104 /* idle-period nonlazy_posted snapshot. */ 104 /* idle-period nonlazy_posted snapshot. */
105 unsigned long last_accelerate; 105 unsigned long last_accelerate;
106 /* Last jiffy CBs were accelerated. */ 106 /* Last jiffy CBs were accelerated. */
107 unsigned long last_advance_all;
108 /* Last jiffy CBs were all advanced. */
107 int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */ 109 int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
108#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */ 110#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
109}; 111};
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 18d9c91f25d1..d81e3856fa91 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -1630,17 +1630,23 @@ module_param(rcu_idle_lazy_gp_delay, int, 0644);
1630extern int tick_nohz_enabled; 1630extern int tick_nohz_enabled;
1631 1631
1632/* 1632/*
1633 * Try to advance callbacks for all flavors of RCU on the current CPU. 1633 * Try to advance callbacks for all flavors of RCU on the current CPU, but
1634 * Afterwards, if there are any callbacks ready for immediate invocation, 1634 * only if it has been awhile since the last time we did so. Afterwards,
1635 * return true. 1635 * if there are any callbacks ready for immediate invocation, return true.
1636 */ 1636 */
1637static bool rcu_try_advance_all_cbs(void) 1637static bool rcu_try_advance_all_cbs(void)
1638{ 1638{
1639 bool cbs_ready = false; 1639 bool cbs_ready = false;
1640 struct rcu_data *rdp; 1640 struct rcu_data *rdp;
1641 struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
1641 struct rcu_node *rnp; 1642 struct rcu_node *rnp;
1642 struct rcu_state *rsp; 1643 struct rcu_state *rsp;
1643 1644
1645 /* Exit early if we advanced recently. */
1646 if (jiffies == rdtp->last_advance_all)
1647 return 0;
1648 rdtp->last_advance_all = jiffies;
1649
1644 for_each_rcu_flavor(rsp) { 1650 for_each_rcu_flavor(rsp) {
1645 rdp = this_cpu_ptr(rsp->rda); 1651 rdp = this_cpu_ptr(rsp->rda);
1646 rnp = rdp->mynode; 1652 rnp = rdp->mynode;