linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pranith Kumar <bobby.prani@gmail.com>
To: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Josh Triplett <josh@joshtriplett.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Lai Jiangshan <laijs@cn.fujitsu.com>,
	"open list:READ-COPY UPDATE..." <linux-kernel@vger.kernel.org>,
	Peter Zijlstra <peterz@infradead.org>
Subject: Re: [PATCH 11/16] rcu: Check for spurious wakeup using return value
Date: Thu, 24 Jul 2014 15:59:33 -0400	[thread overview]
Message-ID: <53D165A5.6010206@gmail.com> (raw)
In-Reply-To: <20140724181223.GO11241@linux.vnet.ibm.com>

Adding peterz to CC as git blames him for wait_event code. :)

(original LKML link: https://lkml.org/lkml/2014/7/23/45)

On Thu, Jul 24, 2014 at 2:12 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:

>> >> > How does this added check help?  I don't see that it does.  If the flag
>> >> > is set, we want to wake up.  If we get a spurious wakeup, but then the
>> >> > flag gets set before we actually wake up, we still want to wake up.
>> >>
>> >> So I took a look at the docs again, and using the return value is the
>> >> recommended way to check for spurious wakeups.
>> >>
>> >> The condition in wait_event_interruptible() is checked when the task
>> >> is woken up (either due to stray signals or explicitly) and it returns
>> >> true if condition evaluates to true.
>>
>> this should be returns '0' if the condition evaluates to true.
>
> Ah, but if the condition changes while wait_event_interruptible() is in
> the process of returning, it is quite possible that the answer will be
> different afterwards.  For example, consider this scenario:
>
> o       wait_event_interruptible() decides to return spuriously for
>         whatever reason, and thus returns a non-zero value.
>
> o       An invocation of (say) rcu_start_gp_advanced() sets ->gp_flags
>         to RCU_GP_FLAG_INIT, thus requesting that a new grace period
>         start.
>
> o       At this point, the return value says that we should not start
>         a new grace period, but the ->gp_flags value says that we
>         should.
>
> Because it is the ->gp_flags value that really knows, the current code
> ignores wait_event_interruptible()'s return value and just checks
> the ->gp_flags value.

OK. Let me simplify what wait_event_interruptible is doing. That will
give you an idea why checking the return value is sufficient.

In highly simplified form wait_event() does the following:

ret = wait_event(wq, condition):

	ret = -ERESTARTSYS;
	if (condition) {
		ret = 0;
		goto out;
	}
	sleep();
	/* wakes up */
	if (condition)
		ret = 0;
out:
	return ret;

Considering this, the above situation will now be:

o       wait_event_interruptible() decides to return spuriously for
        whatever reason, and thus returns a non-zero value.

o       An invocation of (say) rcu_start_gp_advanced() sets ->gp_flags
        to RCU_GP_FLAG_INIT, thus requesting that a new grace period
        start.

o       At this point, the return value says that we should not start
        a new grace period, but the ->gp_flags value says that we
        should.

o	We see that return value is non-zero and go back to wait_event

o	In wait_event, we check that the condition is actually true and 
	return immediately without sleeping and with a return value of 0.

If ->gp_flags is set after returning from wait_event_interruptible and we 
get back to waiting again, we will immediately see that the condition is true
and return and continue with rcu_gpu_init().

The basic idea is that in cases of spurious wakeup we return to waiting as
soon as possible and if the condition becomes true while we are going back to
wait_event, we return immediately with a value of 0.

>
>> >> In the current scenario, if we get a spurious wakeup, we take the
>> >> costly path of checking this condition again (with a barrier and lock)
>> >> before going back to wait.
>> >>
>> >> The scenario of getting an actual wakeup after getting a spurious
>> >> wakeup exists even today, this is the window after detecting a
>> >> spurious wakeup and before going back to wait. I am not sure if using
>> >> the return value enlarges that window as we are going back to sleep
>> >> immediately.
>> >>
>> >> Thoughts?
>> >
>> > If the flag is set, why should we care whether or not the wakeup was
>> > spurious?  If the flag is not set, why should we care whether or not
>> > wait_event_interruptible() thought that the wakeup was not spurious?
>>
>> A correction about the return value above: return will be 0 if the
>> condition is true, in this case if the flag is set.
>>
>> If the flag is set, ret will be 0 and we will go ahead with
>> rcu_gp_init(). (no change wrt current behavior)
>
> Sorry, this is not always correct.  RCU is highly concurrent, so you do
> need to start thinking in terms of concurrency.  Your reasoning above
> is a symptom of single-threaded thinking.  Please see my scenario above
> showing how the return can be non-zero even though ->gp_flags is set.
>
>> If the flag is not set, currently we go ahead and call rcu_gp_init()
>> from where we check if the flag is set (after a lock+barrier) and
>> return.
>
> True enough.  Is that really a problem?  If so, exactly why is it a
> problem?

The problem is that we are detecting a spurious wakeup after unnecessary work
which we can avoid by checking the return value.

>
>> If we care about what wait_event_interruptible() returns, we can go
>> back and wait for an actual wakeup much earlier without the additional
>> overhead of calling rcu_gp_init().
>
> The key phrase here is "If we care".  Should we care?  If so, why?
>
> I suggest running some random benchmark and counting how many times
> rcu_gp_init() is called and how many times rcu_gp_init() returns
> because ->gp_flags is not set.  If rcu_gp_init() returns because
> ->gp_flags is not set a significant fraction of the time, then this
> -might- be worth worrying about.  (Extra credit: Under what conditions

In the grand scheme of things, I agree that minor optimizations may not seem
to be worth much. But when the optimizationss are straight forward and 
are _actually_ improving things, even by a small margin, I think they are
worth considering.

Think of the billions of cycles we will save ;-)

> -might- be worth worrying about.  (Extra credit: Under what conditions
> would it be worth worrying about, and how would you go about checking
> to see whether those conditions hold?)
>


-- 
Pranith

  reply	other threads:[~2014-07-24 19:57 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-23  5:09 [PATCH 00/16] rcu: Some minor fixes and cleanups Pranith Kumar
2014-07-23  5:09 ` [PATCH 01/16] rcu: Use rcu_num_nodes instead of NUM_RCU_NODES Pranith Kumar
2014-07-23  5:09 ` [PATCH 02/16] rcu: Check return value for cpumask allocation Pranith Kumar
2014-07-23 12:06   ` Paul E. McKenney
2014-07-23 12:49     ` Pranith Kumar
2014-07-23 17:14     ` Pranith Kumar
2014-07-23 18:01       ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 03/16] rcu: Fix comment for gp_state field values Pranith Kumar
2014-07-23  5:09 ` [PATCH 04/16] rcu: Remove redundant check for an online CPU Pranith Kumar
2014-07-23 12:09   ` Paul E. McKenney
2014-07-23 13:23     ` Pranith Kumar
2014-07-23 13:41       ` Paul E. McKenney
2014-07-23 14:01         ` Pranith Kumar
2014-07-23 14:14           ` Paul E. McKenney
2014-07-23 15:07             ` Pranith Kumar
2014-07-23 15:21               ` Pranith Kumar
2014-07-23  5:09 ` [PATCH 05/16] rcu: Add noreturn attribute to boost kthread Pranith Kumar
2014-07-23  5:09 ` [PATCH 06/16] rcu: Clear gp_flags only when actually starting new gp Pranith Kumar
2014-07-23 12:13   ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 07/16] rcu: Save and restore irq flags in rcu_gp_cleanup() Pranith Kumar
2014-07-23 12:16   ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 08/16] rcu: Clean up rcu_spawn_one_boost_kthread() Pranith Kumar
2014-07-23  5:09 ` [PATCH 09/16] rcu: Remove redundant check for online cpu Pranith Kumar
2014-07-23 12:21   ` Paul E. McKenney
2014-07-23 12:59     ` Pranith Kumar
2014-07-23 13:50       ` Paul E. McKenney
2014-07-23 14:12         ` Pranith Kumar
2014-07-23 14:23           ` Paul E. McKenney
2014-07-23 15:11             ` Pranith Kumar
2014-07-23 15:30               ` Paul E. McKenney
2014-07-23 15:44                 ` Pranith Kumar
2014-07-23 19:15                   ` Paul E. McKenney
2014-07-23 20:01                     ` Pranith Kumar
2014-07-23 20:16                     ` Pranith Kumar
2014-07-23 20:23                       ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 10/16] rcu: Check for RCU_FLAG_GP_INIT bit in gp_flags for spurious wakeup Pranith Kumar
2014-07-23 12:23   ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 11/16] rcu: Check for spurious wakeup using return value Pranith Kumar
2014-07-23 12:26   ` Paul E. McKenney
2014-07-24  2:36     ` Pranith Kumar
2014-07-24  3:43       ` Paul E. McKenney
2014-07-24  4:03         ` Pranith Kumar
2014-07-24 18:12           ` Paul E. McKenney
2014-07-24 19:59             ` Pranith Kumar [this message]
2014-07-24 20:27               ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 12/16] rcu: Rename rcu_spawn_gp_kthread() to rcu_spawn_kthreads() Pranith Kumar
2014-07-23  5:09 ` [PATCH 13/16] rcu: Spawn nocb kthreads from rcu_prepare_kthreads() Pranith Kumar
2014-07-23  5:09 ` [PATCH 14/16] rcu: Remove redundant checks for rcu_scheduler_fully_active Pranith Kumar
2014-07-23 12:27   ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 15/16] rcu: Check for a nocb cpu before trying to spawn nocb threads Pranith Kumar
2014-07-23 12:28   ` Paul E. McKenney
2014-07-23 13:14     ` Pranith Kumar
2014-07-23 13:42       ` Paul E. McKenney
2014-07-23  5:09 ` [PATCH 16/16] rcu: kvm.sh: Fix error when you pass --cpus argument Pranith Kumar
2014-07-23 12:31   ` Paul E. McKenney
2014-07-23 14:45 ` [PATCH 00/16] rcu: Some minor fixes and cleanups Paul E. McKenney
2014-08-27  1:10   ` Pranith Kumar
2014-08-27  3:20     ` Paul E. McKenney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53D165A5.6010206@gmail.com \
    --to=bobby.prani@gmail.com \
    --cc=josh@joshtriplett.org \
    --cc=laijs@cn.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).