On Tue, Aug 25, 2020 at 02:55:53PM -0700, Paul E. McKenney wrote: > On Mon, Aug 24, 2020 at 10:48:42PM -0400, Joel Fernandes (Google) wrote: > > Track how the segcb list changes before/after acceleration, during > > queuing and during dequeuing. > > > > This has proved useful to discover an optimization to avoid unwanted GP > > requests when there are no callbacks accelerated. The overhead is minimal as > > each segment's length is now stored in the respective segment. > > > > Signed-off-by: Joel Fernandes (Google) <joel@xxxxxxxxxxxxxxxxx> > > Speaking of tracing, diagnostics, and debugging, a few instances of > ASSERT_EXCLUSIVE_WRITER() in the previous patch might save a lot > of debugging. Help KCSAN help us. Ok, I will look into it, thanks. > > include/trace/events/rcu.h | 25 +++++++++++++++++++++++++ > > kernel/rcu/rcu_segcblist.c | 27 +++++++++++++++++++++++++++ > > kernel/rcu/rcu_segcblist.h | 7 +++++++ > > kernel/rcu/tree.c | 23 +++++++++++++++++++++++ > > 4 files changed, 82 insertions(+) > > > > diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h > > index 155b5cb43cfd..7b84df3c95df 100644 > > --- a/include/trace/events/rcu.h > > +++ b/include/trace/events/rcu.h > > @@ -505,6 +505,31 @@ TRACE_EVENT_RCU(rcu_callback, > > __entry->qlen) > > ); > > > > +TRACE_EVENT_RCU(rcu_segcb, > > + > > + TP_PROTO(const char *ctx, int *cb_count, unsigned long *gp_seq), > > + > > + TP_ARGS(ctx, cb_count, gp_seq), > > + > > + TP_STRUCT__entry( > > + __field(const char *, ctx) > > + __array(int, cb_count, 4) > > + __array(unsigned long, gp_seq, 4) > > + ), > > + > > + TP_fast_assign( > > + __entry->ctx = ctx; > > + memcpy(__entry->cb_count, cb_count, 4 * sizeof(int)); > > + memcpy(__entry->gp_seq, gp_seq, 4 * sizeof(unsigned long)); > > + ), > > + > > + TP_printk("%s cb_count: (DONE=%d, WAIT=%d, NEXT_READY=%d, NEXT=%d) " > > + "gp_seq: (DONE=%lu, WAIT=%lu, NEXT_READY=%lu, NEXT=%lu)", __entry->ctx, > > + __entry->cb_count[0], __entry->cb_count[1], __entry->cb_count[2], __entry->cb_count[3], > > + __entry->gp_seq[0], __entry->gp_seq[1], __entry->gp_seq[2], __entry->gp_seq[3]) > > + > > +); > > + > > /* > > * Tracepoint for the registration of a single RCU callback of the special > > * kvfree() form. The first argument is the RCU type, the second argument > > diff --git a/kernel/rcu/rcu_segcblist.c b/kernel/rcu/rcu_segcblist.c > > index 73a103464ea4..6419dbbaecde 100644 > > --- a/kernel/rcu/rcu_segcblist.c > > +++ b/kernel/rcu/rcu_segcblist.c > > @@ -378,6 +378,33 @@ void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, > > rcu_segcblist_set_seglen(rsclp, RCU_DONE_TAIL, 0); > > } > > > > +/* > > + * Return how many CBs each segment along with their gp_seq values. > > + * > > + * This function is O(N) where N is the number of callbacks. Only used from > > + * tracing code which is usually disabled in production. > > + */ > > +#ifdef CONFIG_RCU_TRACE > > +void rcu_segcblist_countseq(struct rcu_segcblist *rsclp, > > + int cbcount[RCU_CBLIST_NSEGS], > > + unsigned long gpseq[RCU_CBLIST_NSEGS]) > > +{ > > Why not declare the arrays here and invoke the new trace event from > here also? That would simplify the usage and save a few lines of code. True! I will do it that way. thanks, - Joel