Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ba5c840 authored by Paul E. McKenney's avatar Paul E. McKenney Committed by Ingo Molnar
Browse files

rcu: Add __rcu_pending tracing to hierarchical RCU



Add tracing to __rcu_pending() to provide information on why RCU
processing was kicked off.  This is helpful for debugging hierarchical
RCU, and might also be helpful in learning how hierarchical RCU operates.

Located-by: default avatarAnton Blanchard <anton@au1.ibm.com>
Tested-by: default avatarAnton Blanchard <anton@au1.ibm.com>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: anton@samba.org
Cc: akpm@linux-foundation.org
Cc: dipankar@in.ibm.com
Cc: manfred@colorfullife.com
Cc: cl@linux-foundation.org
Cc: josht@linux.vnet.ibm.com
Cc: schamp@sgi.com
Cc: niv@us.ibm.com
Cc: dvhltc@us.ibm.com
Cc: ego@in.ibm.com
Cc: laijs@cn.fujitsu.com
Cc: rostedt@goodmis.org
Cc: peterz@infradead.org
Cc: penberg@cs.helsinki.fi
Cc: andi@firstfloor.org
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
LKML-Reference: <1239683479943-git-send-email->
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 05cfbd66
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -161,8 +161,15 @@ struct rcu_data {
	unsigned long offline_fqs;	/* Kicked due to being offline. */
	unsigned long resched_ipi;	/* Sent a resched IPI. */

	/* 5) For future __rcu_pending statistics. */
	/* 5) __rcu_pending() statistics. */
	long n_rcu_pending;		/* rcu_pending() calls since boot. */
	long n_rp_qs_pending;
	long n_rp_cb_ready;
	long n_rp_cpu_needs_gp;
	long n_rp_gp_completed;
	long n_rp_gp_started;
	long n_rp_need_fqs;
	long n_rp_need_nothing;

	int cpu;
};
+19 −6
Original line number Diff line number Diff line
@@ -1259,31 +1259,44 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
	check_cpu_stall(rsp, rdp);

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

	/* Does this CPU have callbacks ready to invoke? */
	if (cpu_has_callbacks_ready_to_invoke(rdp))
	if (cpu_has_callbacks_ready_to_invoke(rdp)) {
		rdp->n_rp_cb_ready++;
		return 1;
	}

	/* Has RCU gone idle with this CPU needing another grace period? */
	if (cpu_needs_another_gp(rsp, rdp))
	if (cpu_needs_another_gp(rsp, rdp)) {
		rdp->n_rp_cpu_needs_gp++;
		return 1;
	}

	/* Has another RCU grace period completed?  */
	if (ACCESS_ONCE(rsp->completed) != rdp->completed) /* outside of lock */
	if (ACCESS_ONCE(rsp->completed) != rdp->completed) { /* outside lock */
		rdp->n_rp_gp_completed++;
		return 1;
	}

	/* Has a new RCU grace period started? */
	if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) /* outside of lock */
	if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) { /* outside lock */
		rdp->n_rp_gp_started++;
		return 1;
	}

	/* Has an RCU GP gone long enough to send resched IPIs &c? */
	if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) &&
	    ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0))
	    ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) {
		rdp->n_rp_need_fqs++;
		return 1;
	}

	/* nothing to do */
	rdp->n_rp_need_nothing++;
	return 0;
}

+63 −1
Original line number Diff line number Diff line
@@ -213,7 +213,63 @@ static struct file_operations rcugp_fops = {
	.release = single_release,
};

static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir;
static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
{
	seq_printf(m, "%3d%cnp=%ld "
		   "qsp=%ld cbr=%ld cng=%ld gpc=%ld gps=%ld nf=%ld nn=%ld\n",
		   rdp->cpu,
		   cpu_is_offline(rdp->cpu) ? '!' : ' ',
		   rdp->n_rcu_pending,
		   rdp->n_rp_qs_pending,
		   rdp->n_rp_cb_ready,
		   rdp->n_rp_cpu_needs_gp,
		   rdp->n_rp_gp_completed,
		   rdp->n_rp_gp_started,
		   rdp->n_rp_need_fqs,
		   rdp->n_rp_need_nothing);
}

static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
{
	int cpu;
	struct rcu_data *rdp;

	for_each_possible_cpu(cpu) {
		rdp = rsp->rda[cpu];
		if (rdp->beenonline)
			print_one_rcu_pending(m, rdp);
	}
}

static int show_rcu_pending(struct seq_file *m, void *unused)
{
	seq_puts(m, "rcu:\n");
	print_rcu_pendings(m, &rcu_state);
	seq_puts(m, "rcu_bh:\n");
	print_rcu_pendings(m, &rcu_bh_state);
	return 0;
}

static int rcu_pending_open(struct inode *inode, struct file *file)
{
	return single_open(file, show_rcu_pending, NULL);
}

static struct file_operations rcu_pending_fops = {
	.owner = THIS_MODULE,
	.open = rcu_pending_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

static struct dentry *rcudir;
static struct dentry *datadir;
static struct dentry *datadir_csv;
static struct dentry *gpdir;
static struct dentry *hierdir;
static struct dentry *rcu_pendingdir;

static int __init rcuclassic_trace_init(void)
{
	rcudir = debugfs_create_dir("rcu", NULL);
@@ -238,6 +294,11 @@ static int __init rcuclassic_trace_init(void)
						NULL, &rcuhier_fops);
	if (!hierdir)
		goto free_out;

	rcu_pendingdir = debugfs_create_file("rcu_pending", 0444, rcudir,
						NULL, &rcu_pending_fops);
	if (!rcu_pendingdir)
		goto free_out;
	return 0;
free_out:
	if (datadir)
@@ -257,6 +318,7 @@ static void __exit rcuclassic_trace_cleanup(void)
	debugfs_remove(datadir_csv);
	debugfs_remove(gpdir);
	debugfs_remove(hierdir);
	debugfs_remove(rcu_pendingdir);
	debugfs_remove(rcudir);
}