From: Lai Jiangshan on

I found something RCU_SOFTIRQ are called without do any thing.
(use function_graph to find it:
1) | rcu_process_callbacks() {
1) | __rcu_process_callbacks() {
1) 0.634 us | rcu_process_gp_end();
1) 0.487 us | check_for_new_grace_period();
1) 2.672 us | }
1) | __rcu_process_callbacks() {
1) 0.633 us | rcu_process_gp_end();
1) 0.491 us | check_for_new_grace_period();
1) 2.672 us | }
)

This patch make RCU_SOFTIRQ raised when need.

Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 1947c4e..06a1780 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -133,6 +133,7 @@ module_param(qlowmark, int, 0);

static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
static int rcu_pending(int cpu);
+static int rcu_qs_pending(int cpu);

/*
* Return the number of RCU-sched batches processed thus far for debug & stats.
@@ -1125,8 +1126,9 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
*/
void rcu_check_callbacks(int cpu, int user)
{
- if (!rcu_pending(cpu))
- return; /* if nothing for RCU to do. */
+ if (!rcu_qs_pending(cpu))
+ goto check_rcu_softirq_work;
+
if (user ||
(idle_cpu(cpu) && rcu_scheduler_active &&
!in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
@@ -1158,7 +1160,10 @@ void rcu_check_callbacks(int cpu, int user)
rcu_bh_qs(cpu);
}
rcu_preempt_check_callbacks(cpu);
- raise_softirq(RCU_SOFTIRQ);
+
+check_rcu_softirq_work:
+ if (rcu_pending(cpu))
+ raise_softirq(RCU_SOFTIRQ);
}

#ifdef CONFIG_SMP
@@ -1497,9 +1502,9 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
/* Check for CPU stalls, if enabled. */
check_cpu_stall(rsp, rdp);

- /* Is the RCU core waiting for a quiescent state from this CPU? */
- if (rdp->qs_pending) {
- rdp->n_rp_qs_pending++;
+ /* Does this RCU need to report quiescent state? */
+ if (rdp->qs_pending && rdp->passed_quiesc) {
+ rdp->n_rp_report_qs++;
return 1;
}

@@ -1551,6 +1556,24 @@ static int rcu_pending(int cpu)
rcu_preempt_pending(cpu);
}

+/* Is the RCU core waiting for a quiescent state from this CPU? */
+static int __rcu_qs_pending(struct rcu_data *rdp)
+{
+ if (rdp->qs_pending) {
+ rdp->n_rp_qs_pending++;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rcu_qs_pending(int cpu)
+{
+ return __rcu_qs_pending(&per_cpu(rcu_sched_data, cpu)) ||
+ __rcu_qs_pending(&per_cpu(rcu_bh_data, cpu)) ||
+ rcu_preempt_qs_pending(cpu);
+}
+
/*
* 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
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 4a525a3..c0f312e 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -223,6 +223,7 @@ struct rcu_data {
/* 5) __rcu_pending() statistics. */
unsigned long n_rcu_pending; /* rcu_pending() calls since boot. */
unsigned long n_rp_qs_pending;
+ unsigned long n_rp_report_qs;
unsigned long n_rp_cb_ready;
unsigned long n_rp_cpu_needs_gp;
unsigned long n_rp_gp_completed;
@@ -378,6 +379,7 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp);
#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */
static int rcu_preempt_pending(int cpu);
+static int rcu_preempt_qs_pending(int cpu);
static int rcu_preempt_needs_cpu(int cpu);
static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
static void rcu_preempt_send_cbs_to_orphanage(void);
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 79b53bd..4befb64 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -689,6 +689,11 @@ static int rcu_preempt_pending(int cpu)
&per_cpu(rcu_preempt_data, cpu));
}

+static int rcu_preempt_qs_pending(int cpu)
+{
+ return __rcu_qs_pending(&per_cpu(rcu_preempt_data, cpu));
+}
+
/*
* Does preemptable RCU need the CPU to stay out of dynticks mode?
*/
@@ -914,6 +919,11 @@ static int rcu_preempt_pending(int cpu)
return 0;
}

+static int rcu_preempt_qs_pending(int cpu)
+{
+ return 0;
+}
+
/*
* Because preemptable RCU does not exist, it never needs any CPU.
*/



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/