2015-02-11 14:43:01

by Alexander Gordeev

[permalink] [raw]
Subject: [PATCH 0/3] rcu: Tweak tiny RCU

Hi Paul,

These are few code improvements to the tiny RCU.

Cc: "Paul E. McKenney" <[email protected]>

Alexander Gordeev (3):
rcu: Remove unnecessary condition check in rcu_qsctr_help()
rcu: Remove fast path from __rcu_process_callbacks()
rcu: Call trace_rcu_batch_start() with enabled interrupts

kernel/rcu/tiny.c | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)

--
1.8.3.1


2015-02-11 14:44:17

by Alexander Gordeev

[permalink] [raw]
Subject: [PATCH 1/3] rcu: Remove unnecessary condition check in rcu_qsctr_help()

In cases ->curtail and ->donetail pointers differ ->rcucblist
always points to the beginning of the current list and thus
can not be NULL. Therefore, the check ->rcucblist != NULL is
redundant and could be removed.

Cc: "Paul E. McKenney" <[email protected]>
Signed-off-by: Alexander Gordeev <[email protected]>
---
kernel/rcu/tiny.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index cc9ceca..d4e7fe5 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -103,8 +103,7 @@ EXPORT_SYMBOL(__rcu_is_watching);
static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
{
RCU_TRACE(reset_cpu_stall_ticks(rcp));
- if (rcp->rcucblist != NULL &&
- rcp->donetail != rcp->curtail) {
+ if (rcp->donetail != rcp->curtail) {
rcp->donetail = rcp->curtail;
return 1;
}
--
1.8.3.1

2015-02-11 14:43:42

by Alexander Gordeev

[permalink] [raw]
Subject: [PATCH 2/3] rcu: Remove fast path from __rcu_process_callbacks()

The standard code path accommodates a condition when no
RCU callbacks are ready to invoke. Since size of the code
is a priority for tiny RCU, remove the fast path.

Cc: "Paul E. McKenney" <[email protected]>
Signed-off-by: Alexander Gordeev <[email protected]>
---
kernel/rcu/tiny.c | 11 -----------
1 file changed, 11 deletions(-)

diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index d4e7fe5..069742d 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -168,17 +168,6 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
unsigned long flags;
RCU_TRACE(int cb_count = 0);

- /* If no RCU callbacks ready to invoke, just return. */
- if (&rcp->rcucblist == rcp->donetail) {
- RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, 0, -1));
- RCU_TRACE(trace_rcu_batch_end(rcp->name, 0,
- !!ACCESS_ONCE(rcp->rcucblist),
- need_resched(),
- is_idle_task(current),
- false));
- return;
- }
-
/* Move the ready-to-invoke callbacks to a local list. */
local_irq_save(flags);
RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
--
1.8.3.1

2015-02-11 14:43:05

by Alexander Gordeev

[permalink] [raw]
Subject: [PATCH 3/3] rcu: Call trace_rcu_batch_start() with enabled interrupts

Currently trace_rcu_batch_start() is called with local
interrupts disabled. Yet, there is no reason to do so.

Cc: "Paul E. McKenney" <[email protected]>
Signed-off-by: Alexander Gordeev <[email protected]>
---
kernel/rcu/tiny.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index 069742d..01e80ac 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -166,11 +166,12 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
const char *rn = NULL;
struct rcu_head *next, *list;
unsigned long flags;
+ RCU_TRACE(long qlen);
RCU_TRACE(int cb_count = 0);

/* Move the ready-to-invoke callbacks to a local list. */
local_irq_save(flags);
- RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
+ RCU_TRACE(qlen = rcp->qlen);
list = rcp->rcucblist;
rcp->rcucblist = *rcp->donetail;
*rcp->donetail = NULL;
@@ -180,6 +181,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
local_irq_restore(flags);

/* Invoke the callbacks on the local list. */
+ RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, qlen, -1));
RCU_TRACE(rn = rcp->name);
while (list) {
next = list->next;
--
1.8.3.1

2015-02-11 16:09:33

by Paul E. McKenney

[permalink] [raw]
Subject: Re: [PATCH 1/3] rcu: Remove unnecessary condition check in rcu_qsctr_help()

On Wed, Feb 11, 2015 at 03:42:37PM +0100, Alexander Gordeev wrote:
> In cases ->curtail and ->donetail pointers differ ->rcucblist
> always points to the beginning of the current list and thus
> can not be NULL. Therefore, the check ->rcucblist != NULL is
> redundant and could be removed.
>
> Cc: "Paul E. McKenney" <[email protected]>
> Signed-off-by: Alexander Gordeev <[email protected]>

Good point, queued for 3.21.

Thanx, Paul

> ---
> kernel/rcu/tiny.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
> index cc9ceca..d4e7fe5 100644
> --- a/kernel/rcu/tiny.c
> +++ b/kernel/rcu/tiny.c
> @@ -103,8 +103,7 @@ EXPORT_SYMBOL(__rcu_is_watching);
> static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
> {
> RCU_TRACE(reset_cpu_stall_ticks(rcp));
> - if (rcp->rcucblist != NULL &&
> - rcp->donetail != rcp->curtail) {
> + if (rcp->donetail != rcp->curtail) {
> rcp->donetail = rcp->curtail;
> return 1;
> }
> --
> 1.8.3.1
>

2015-02-11 16:11:13

by Paul E. McKenney

[permalink] [raw]
Subject: Re: [PATCH 2/3] rcu: Remove fast path from __rcu_process_callbacks()

On Wed, Feb 11, 2015 at 03:42:38PM +0100, Alexander Gordeev wrote:
> The standard code path accommodates a condition when no
> RCU callbacks are ready to invoke. Since size of the code
> is a priority for tiny RCU, remove the fast path.
>
> Cc: "Paul E. McKenney" <[email protected]>
> Signed-off-by: Alexander Gordeev <[email protected]>

Also a good point. The savings is small in production builds because
the RCU_TRACE() statements are not compiled, but every little bit helps,
and the simplification is good as well.

Queued for 3.21.

Thanx, Paul

> ---
> kernel/rcu/tiny.c | 11 -----------
> 1 file changed, 11 deletions(-)
>
> diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
> index d4e7fe5..069742d 100644
> --- a/kernel/rcu/tiny.c
> +++ b/kernel/rcu/tiny.c
> @@ -168,17 +168,6 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> unsigned long flags;
> RCU_TRACE(int cb_count = 0);
>
> - /* If no RCU callbacks ready to invoke, just return. */
> - if (&rcp->rcucblist == rcp->donetail) {
> - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, 0, -1));
> - RCU_TRACE(trace_rcu_batch_end(rcp->name, 0,
> - !!ACCESS_ONCE(rcp->rcucblist),
> - need_resched(),
> - is_idle_task(current),
> - false));
> - return;
> - }
> -
> /* Move the ready-to-invoke callbacks to a local list. */
> local_irq_save(flags);
> RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
> --
> 1.8.3.1
>

2015-02-11 16:13:38

by Paul E. McKenney

[permalink] [raw]
Subject: Re: [PATCH 3/3] rcu: Call trace_rcu_batch_start() with enabled interrupts

On Wed, Feb 11, 2015 at 03:42:39PM +0100, Alexander Gordeev wrote:
> Currently trace_rcu_batch_start() is called with local
> interrupts disabled. Yet, there is no reason to do so.
>
> Cc: "Paul E. McKenney" <[email protected]>
> Signed-off-by: Alexander Gordeev <[email protected]>

Hmmm... I am not seeing this one. As you noted in the commit log for
your earlier patch, the purpose of Tiny RCU is to be tiny, not to be
all that fast. This commit increases the size a bit (admittedly only
when CONFIG_RCU_TRACE=y), and also increases complexity a bit.

So it does not look to me to be something we want for Tiny RCU.

So what am I missing here?

Thanx, Paul

> ---
> kernel/rcu/tiny.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
> index 069742d..01e80ac 100644
> --- a/kernel/rcu/tiny.c
> +++ b/kernel/rcu/tiny.c
> @@ -166,11 +166,12 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> const char *rn = NULL;
> struct rcu_head *next, *list;
> unsigned long flags;
> + RCU_TRACE(long qlen);
> RCU_TRACE(int cb_count = 0);
>
> /* Move the ready-to-invoke callbacks to a local list. */
> local_irq_save(flags);
> - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
> + RCU_TRACE(qlen = rcp->qlen);
> list = rcp->rcucblist;
> rcp->rcucblist = *rcp->donetail;
> *rcp->donetail = NULL;
> @@ -180,6 +181,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> local_irq_restore(flags);
>
> /* Invoke the callbacks on the local list. */
> + RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, qlen, -1));
> RCU_TRACE(rn = rcp->name);
> while (list) {
> next = list->next;
> --
> 1.8.3.1
>

2015-02-11 16:36:50

by Alexander Gordeev

[permalink] [raw]
Subject: Re: [PATCH 3/3] rcu: Call trace_rcu_batch_start() with enabled interrupts

On Wed, Feb 11, 2015 at 08:13:30AM -0800, Paul E. McKenney wrote:
> On Wed, Feb 11, 2015 at 03:42:39PM +0100, Alexander Gordeev wrote:
> > Currently trace_rcu_batch_start() is called with local
> > interrupts disabled. Yet, there is no reason to do so.
> >
> > Cc: "Paul E. McKenney" <[email protected]>
> > Signed-off-by: Alexander Gordeev <[email protected]>
>
> Hmmm... I am not seeing this one. As you noted in the commit log for
> your earlier patch, the purpose of Tiny RCU is to be tiny, not to be
> all that fast. This commit increases the size a bit (admittedly only
> when CONFIG_RCU_TRACE=y), and also increases complexity a bit.
>
> So it does not look to me to be something we want for Tiny RCU.
>
> So what am I missing here?

The benefit - "heavy" trace_rcu_batch_start() is called while interrupts
are enabled. Which is normally a priority, but in this case - still a
good tradeoff IMHO.

And I do not agree :) The code reads better with the loop tightly "enclosed"
with trace_rcu_batch_start()/trace_rcu_batch_end().

> Thanx, Paul
>
> > ---
> > kernel/rcu/tiny.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
> > index 069742d..01e80ac 100644
> > --- a/kernel/rcu/tiny.c
> > +++ b/kernel/rcu/tiny.c
> > @@ -166,11 +166,12 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> > const char *rn = NULL;
> > struct rcu_head *next, *list;
> > unsigned long flags;
> > + RCU_TRACE(long qlen);
> > RCU_TRACE(int cb_count = 0);
> >
> > /* Move the ready-to-invoke callbacks to a local list. */
> > local_irq_save(flags);
> > - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
> > + RCU_TRACE(qlen = rcp->qlen);
> > list = rcp->rcucblist;
> > rcp->rcucblist = *rcp->donetail;
> > *rcp->donetail = NULL;
> > @@ -180,6 +181,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> > local_irq_restore(flags);
> >
> > /* Invoke the callbacks on the local list. */
> > + RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, qlen, -1));
> > RCU_TRACE(rn = rcp->name);
> > while (list) {
> > next = list->next;
> > --
> > 1.8.3.1
> >
>

--
Regards,
Alexander Gordeev
[email protected]

2015-02-11 17:20:56

by Paul E. McKenney

[permalink] [raw]
Subject: Re: [PATCH 3/3] rcu: Call trace_rcu_batch_start() with enabled interrupts

On Wed, Feb 11, 2015 at 04:48:24PM +0000, Alexander Gordeev wrote:
> On Wed, Feb 11, 2015 at 08:13:30AM -0800, Paul E. McKenney wrote:
> > On Wed, Feb 11, 2015 at 03:42:39PM +0100, Alexander Gordeev wrote:
> > > Currently trace_rcu_batch_start() is called with local
> > > interrupts disabled. Yet, there is no reason to do so.
> > >
> > > Cc: "Paul E. McKenney" <[email protected]>
> > > Signed-off-by: Alexander Gordeev <[email protected]>
> >
> > Hmmm... I am not seeing this one. As you noted in the commit log for
> > your earlier patch, the purpose of Tiny RCU is to be tiny, not to be
> > all that fast. This commit increases the size a bit (admittedly only
> > when CONFIG_RCU_TRACE=y), and also increases complexity a bit.
> >
> > So it does not look to me to be something we want for Tiny RCU.
> >
> > So what am I missing here?
>
> The benefit - "heavy" trace_rcu_batch_start() is called while interrupts
> are enabled. Which is normally a priority, but in this case - still a
> good tradeoff IMHO.
>
> And I do not agree :) The code reads better with the loop tightly "enclosed"
> with trace_rcu_batch_start()/trace_rcu_batch_end().

Sorry, but I am still not seeing this one as being worth the change.
I did take the other two, and they are passing light rcutorture testing,
so we are good on that front, at least.

Thanx, Paul

> > > ---
> > > kernel/rcu/tiny.c | 4 +++-
> > > 1 file changed, 3 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
> > > index 069742d..01e80ac 100644
> > > --- a/kernel/rcu/tiny.c
> > > +++ b/kernel/rcu/tiny.c
> > > @@ -166,11 +166,12 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> > > const char *rn = NULL;
> > > struct rcu_head *next, *list;
> > > unsigned long flags;
> > > + RCU_TRACE(long qlen);
> > > RCU_TRACE(int cb_count = 0);
> > >
> > > /* Move the ready-to-invoke callbacks to a local list. */
> > > local_irq_save(flags);
> > > - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
> > > + RCU_TRACE(qlen = rcp->qlen);
> > > list = rcp->rcucblist;
> > > rcp->rcucblist = *rcp->donetail;
> > > *rcp->donetail = NULL;
> > > @@ -180,6 +181,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
> > > local_irq_restore(flags);
> > >
> > > /* Invoke the callbacks on the local list. */
> > > + RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, qlen, -1));
> > > RCU_TRACE(rn = rcp->name);
> > > while (list) {
> > > next = list->next;
> > > --
> > > 1.8.3.1
> > >
> >
>
> --
> Regards,
> Alexander Gordeev
> [email protected]
>