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

Commit 269dcc1c authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

rcu: Add tracing data to support queueing models



The current tracing data is not sufficient to deduce the average time
that a callback spends waiting for a grace period to end.  Add three
per-CPU counters recording the number of callbacks invoked (ci), the
number of callbacks orphaned (co), and the number of callbacks adopted
(ca).  Given the existing callback queue length (ql), the average wait
time in absence of CPU hotplug operations is ql/ci.  The units of wait
time will be in terms of the duration over which ci was measured.

In the presence of CPU hotplug operations, there is room for argument,
but ql/(ci-co+ca) won't steer you too far wrong.

Also fixes a typo called out by Lucas De Marchi <lucas.de.marchi@gmail.com>.

Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 0ddea0ea
Loading
Loading
Loading
Loading
+12 −1
Original line number Original line Diff line number Diff line
@@ -125,6 +125,17 @@ o "b" is the batch limit for this CPU. If more than this number
	of RCU callbacks is ready to invoke, then the remainder will
	of RCU callbacks is ready to invoke, then the remainder will
	be deferred.
	be deferred.


o	"ci" is the number of RCU callbacks that have been invoked for
	this CPU.  Note that ci+ql is the number of callbacks that have
	been registered in absence of CPU-hotplug activity.

o	"co" is the number of RCU callbacks that have been orphaned due to
	this CPU going offline.

o	"ca" is the number of RCU callbacks that have been adopted due to
	other CPUs going offline.  Note that ci+co-ca+ql is the number of
	RCU callbacks registered on this CPU.

There is also an rcu/rcudata.csv file with the same information in
There is also an rcu/rcudata.csv file with the same information in
comma-separated-variable spreadsheet format.
comma-separated-variable spreadsheet format.


@@ -180,7 +191,7 @@ o "s" is the "signaled" state that drives force_quiescent_state()'s


o	"jfq" is the number of jiffies remaining for this grace period
o	"jfq" is the number of jiffies remaining for this grace period
	before force_quiescent_state() is invoked to help push things
	before force_quiescent_state() is invoked to help push things
	along.  Note that CPUs in dyntick-idle mode thoughout the grace
	along.  Note that CPUs in dyntick-idle mode throughout the grace
	period will not report on their own, but rather must be check by
	period will not report on their own, but rather must be check by
	some other CPU via force_quiescent_state().
	some other CPU via force_quiescent_state().


+3 −0
Original line number Original line Diff line number Diff line
@@ -1004,6 +1004,7 @@ static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp)
	for (i = 0; i < RCU_NEXT_SIZE; i++)
	for (i = 0; i < RCU_NEXT_SIZE; i++)
		rdp->nxttail[i] = &rdp->nxtlist;
		rdp->nxttail[i] = &rdp->nxtlist;
	rsp->orphan_qlen += rdp->qlen;
	rsp->orphan_qlen += rdp->qlen;
	rdp->n_cbs_orphaned += rdp->qlen;
	rdp->qlen = 0;
	rdp->qlen = 0;
	raw_spin_unlock(&rsp->onofflock);  /* irqs remain disabled. */
	raw_spin_unlock(&rsp->onofflock);  /* irqs remain disabled. */
}
}
@@ -1025,6 +1026,7 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
	*rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_list;
	*rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_list;
	rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_tail;
	rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_tail;
	rdp->qlen += rsp->orphan_qlen;
	rdp->qlen += rsp->orphan_qlen;
	rdp->n_cbs_adopted += rsp->orphan_qlen;
	rsp->orphan_cbs_list = NULL;
	rsp->orphan_cbs_list = NULL;
	rsp->orphan_cbs_tail = &rsp->orphan_cbs_list;
	rsp->orphan_cbs_tail = &rsp->orphan_cbs_list;
	rsp->orphan_qlen = 0;
	rsp->orphan_qlen = 0;
@@ -1156,6 +1158,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)


	/* Update count, and requeue any remaining callbacks. */
	/* Update count, and requeue any remaining callbacks. */
	rdp->qlen -= count;
	rdp->qlen -= count;
	rdp->n_cbs_invoked += count;
	if (list != NULL) {
	if (list != NULL) {
		*tail = rdp->nxtlist;
		*tail = rdp->nxtlist;
		rdp->nxtlist = list;
		rdp->nxtlist = list;
+3 −0
Original line number Original line Diff line number Diff line
@@ -202,6 +202,9 @@ struct rcu_data {
	long		qlen;		/* # of queued callbacks */
	long		qlen;		/* # of queued callbacks */
	long		qlen_last_fqs_check;
	long		qlen_last_fqs_check;
					/* qlen at last check for QS forcing */
					/* qlen at last check for QS forcing */
	unsigned long	n_cbs_invoked;	/* count of RCU cbs invoked. */
	unsigned long	n_cbs_orphaned;	/* RCU cbs sent to orphanage. */
	unsigned long	n_cbs_adopted;	/* RCU cbs adopted from orphanage. */
	unsigned long	n_force_qs_snap;
	unsigned long	n_force_qs_snap;
					/* did other CPU force QS recently? */
					/* did other CPU force QS recently? */
	long		blimit;		/* Upper limit on a processed batch */
	long		blimit;		/* Upper limit on a processed batch */
+7 −3
Original line number Original line Diff line number Diff line
@@ -64,7 +64,9 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
		   rdp->dynticks_fqs);
		   rdp->dynticks_fqs);
#endif /* #ifdef CONFIG_NO_HZ */
#endif /* #ifdef CONFIG_NO_HZ */
	seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
	seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
	seq_printf(m, " ql=%ld b=%ld\n", rdp->qlen, rdp->blimit);
	seq_printf(m, " ql=%ld b=%ld", rdp->qlen, rdp->blimit);
	seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
		   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
}
}


#define PRINT_RCU_DATA(name, func, m) \
#define PRINT_RCU_DATA(name, func, m) \
@@ -119,7 +121,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
		   rdp->dynticks_fqs);
		   rdp->dynticks_fqs);
#endif /* #ifdef CONFIG_NO_HZ */
#endif /* #ifdef CONFIG_NO_HZ */
	seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
	seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
	seq_printf(m, ",%ld,%ld\n", rdp->qlen, rdp->blimit);
	seq_printf(m, ",%ld,%ld", rdp->qlen, rdp->blimit);
	seq_printf(m, ",%lu,%lu,%lu\n",
		   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
}
}


static int show_rcudata_csv(struct seq_file *m, void *unused)
static int show_rcudata_csv(struct seq_file *m, void *unused)
@@ -128,7 +132,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused)
#ifdef CONFIG_NO_HZ
#ifdef CONFIG_NO_HZ
	seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
	seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
#endif /* #ifdef CONFIG_NO_HZ */
#endif /* #ifdef CONFIG_NO_HZ */
	seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\"\n");
	seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n");
#ifdef CONFIG_TREE_PREEMPT_RCU
#ifdef CONFIG_TREE_PREEMPT_RCU
	seq_puts(m, "\"rcu_preempt:\"\n");
	seq_puts(m, "\"rcu_preempt:\"\n");
	PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
	PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);