Re: [PATCH tip/core/rcu 04/13] rcu: Make RCU_FANOUT_LEAF help text more explicit about skew_tick
From: Paul E. McKenney
Date: Wed Apr 19 2017 - 11:08:26 EST
On Wed, Apr 19, 2017 at 03:48:35PM +0200, Peter Zijlstra wrote:
> On Wed, Apr 19, 2017 at 03:22:26PM +0200, Peter Zijlstra wrote:
> > On Thu, Apr 13, 2017 at 11:42:32AM -0700, Paul E. McKenney wrote:
> >
> > > I believe that you are missing the fact that RCU grace-period
> > > initialization and cleanup walks through the rcu_node tree breadth
> > > first, using rcu_for_each_node_breadth_first().
> >
> > Indeed. That is the part I completely missed.
> >
> > > This macro (shown below)
> > > implements this breadth-first walk using a simple sequential traversal of
> > > the ->node[] array that provides the structures making up the rcu_node
> > > tree. As you can see, this scan is completely independent of how CPU
> > > numbers might be mapped to rcu_data slots in the leaf rcu_node structures.
> >
> > So this code is clearly not a hotpath, but still its performance
> > matters?
> >
> > Seems like you cannot win here :/
>
> So I sort of see what that code does, but I cannot quite grasp from the
> comments near there _why_ it is doing this.
>
> My thinking is that normal (active CPUs) will update their state at tick
> time through the tree, and once the state reaches the root node, IOW all
> CPUs agree they've observed that particular state, we advance the global
> state, rinse repeat. That's how tree-rcu works.
>
> NOHZ-idle stuff would be excluded entirely; that is, if we're allowed to
> go idle we're up-to-date, and completely drop out of the state tracking.
> When we become active again, we can simply sync the CPU's state to the
> active state and go from there -- ignoring whatever happened in the
> mean-time.
>
> So why do we have to do machine wide updates? How can we get at the end
> up a grace period without all CPUs already agreeing that its complete?
>
> /me puzzled.
This a decent overall summary of how RCU grace periods work, but there
are quite a few corner cases that complicate things. In this email,
I will focus on just one of them, starting with CPUs returning from
NOHZ-idle state.
In theory, you are correct when you say that we could have CPUs sync up
with current RCU state immediately upon return from idle. In practice,
people are already screaming at me about the single CPU-local atomic
operation and memory barriers, so adding code on the idle-exit fastpath
to acquire the leaf rcu_node structure's lock and grab the current
state would do nothing but cause Marc Zyngier and many others to report
performance bugs to me.
And even that would not be completely sufficient. After all, the state
in the leaf rcu_node structure will be out of date during grace-period
initialization and cleanup. So to -completely- synchronize state for
the incoming CPU, I would have to acquire the root rcu_node structure's
lock and look at the live state. Needless to say, the performance and
scalability implications of acquiring a global lock on each and every
idle exit event is not going to be at all pretty.
This means that even non-idle CPUs must necessarily be allowed to have
different about which grace period is currently in effect. We simply
cannot have total agreement on when a given grace period starts or
ends, because such agreement is just too expensive. Therefore, when a
grace period begins, the grace-period kthread scans the rcu_node tree
propagating this transition through the rcu_node tree. And similarly
when a grace period ends.
Because the rcu_node tree is mapped into a dense array, and because
the scan proceeds in index order, the scan operation is pretty much
best-case for the cache hardware. But on large machines with large
cache-miss latencies, it can still inflict a bit of pain -- almost all
of which has been addressed by the switch to grace-period kthreads.
Hey, you asked!!! ;-)
Thanx, Paul