Unsynchronized lazy conditions

classic Classic list List threaded Threaded
31 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Hi,

I'd like to issue a warning message a relatively low number of times in
a multi-threaded application. My code is this:

class Foo {
   private boolean warned;

   public void run() {
     if (!warned) {
        LOG.warn("Warning");
        warned = true;
     }
   }
}

This is the only access to the variable 'warned', the value change is
deliberately unsynchronized, and monotonic. Am I right to believe that:

* The first call WILL issue a warning.
* Any thread will issue the warning AT MOST once.
* Some (later) threads may not issue the warning, if the updated value
is flushed to the heap and they load it?

Is there a better way to do this without sacrificing performance? Is
this what the mysterious AtomicBoolean.lazySet, or even
weakCompareAndSet is about?

This is right in the middle of something very concurrent which runs for
a long time, so reducing overhead is far more important than
occasionally issuing too many warnings.

Thank you.

S.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:

> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.
Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
On 05/31/2018 11:22 AM, Viktor Klang wrote:

> Aleksey's suggestion(s) is/are definitely cleaner than mine:
>
> Depending on performance requirements the following might be cheaper,
> of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:
>
> class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
>    public void run() {
>      if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
>        LOG.warn("Warning");
>      }
>    }
> }
Or that. I don't think we care about getAndSet vs compareAndSet all that much, since it is one-off
thing. The important thing is the first fast-path check.

Thanks,
-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list


On Thu, May 31, 2018 at 11:26 AM, Aleksey Shipilev <[hidden email]> wrote:
On 05/31/2018 11:22 AM, Viktor Klang wrote:
> Aleksey's suggestion(s) is/are definitely cleaner than mine:
>
> Depending on performance requirements the following might be cheaper,
> of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:
>
> class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
>    public void run() {
>      if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
>        LOG.warn("Warning");
>      }
>    }
> }

Or that. I don't think we care about getAndSet vs compareAndSet all that much, since it is one-off
thing. The important thing is the first fast-path check.

Agreed. The difference in the first case is most likely eclipsed by the cost of the logging call. And contention for the first invocation is likely non-existant.
 

Thanks,
-Aleksey




--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
The original requirement was it’s ok to sometimes log Warning several times. All this hacky atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of the code as is.

Alex

On 31 May 2018, at 10:22, Viktor Klang via Concurrency-interest <[hidden email]> wrote:

Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Or leave the field un-volatile and introduce a release fence before the logging call?

On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]> wrote:
The original requirement was it’s ok to sometimes log Warning several times. All this hacky atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of the code as is.

Alex


On 31 May 2018, at 10:22, Viktor Klang via Concurrency-interest <[hidden email]> wrote:

Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Who cares to optimize the instruction that is going to be executed approximately once?

Alex

On 31 May 2018, at 11:03, Viktor Klang <[hidden email]> wrote:

Or leave the field un-volatile and introduce a release fence before the logging call?

On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]> wrote:
The original requirement was it’s ok to sometimes log Warning several times. All this hacky atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of the code as is.

Alex


On 31 May 2018, at 10:22, Viktor Klang via Concurrency-interest <[hidden email]> wrote:

Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
The OP?

On Thu, May 31, 2018 at 12:05 PM, Alex Otenko <[hidden email]> wrote:
Who cares to optimize the instruction that is going to be executed approximately once?

Alex

On 31 May 2018, at 11:03, Viktor Klang <[hidden email]> wrote:

Or leave the field un-volatile and introduce a release fence before the logging call?

On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]> wrote:
The original requirement was it’s ok to sometimes log Warning several times. All this hacky atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of the code as is.

Alex


On 31 May 2018, at 10:22, Viktor Klang via Concurrency-interest <[hidden email]> wrote:

Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,




--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
The OP’s concern was the use of “normal” variable and guarantees of eventually observing stuff.

In your case just adding a release fence won’t do. Without an acquire fence before the load the fencing effort is futile.

Alex

On 31 May 2018, at 11:10, Viktor Klang <[hidden email]> wrote:

The OP?

On Thu, May 31, 2018 at 12:05 PM, Alex Otenko <[hidden email]> wrote:
Who cares to optimize the instruction that is going to be executed approximately once?

Alex

On 31 May 2018, at 11:03, Viktor Klang <[hidden email]> wrote:

Or leave the field un-volatile and introduce a release fence before the logging call?

On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]> wrote:
The original requirement was it’s ok to sometimes log Warning several times. All this hacky atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of the code as is.

Alex


On 31 May 2018, at 10:22, Viktor Klang via Concurrency-interest <[hidden email]> wrote:

Aleksey's suggestion(s) is/are definitely cleaner than mine:

Depending on performance requirements the following might be cheaper,
of course assuming you can type-wise hide the AtomicBoolean inheritance from consumer code:

class Foo extends AtomicBoolean { // No indirection due to the allocation of AtomicBoolean
   public void run() {
     if (!get() && !getAndSet(true)) { // LOCK XCHG instead of LOCK CMPXCHG
       LOG.warn("Warning");
     }
   }
}

On Thu, May 31, 2018 at 9:51 AM, Aleksey Shipilev via Concurrency-interest <[hidden email]> wrote:
On 05/31/2018 07:07 AM, Shevek via Concurrency-interest wrote:
> Hi,
>
> I'd like to issue a warning message a relatively low number of times in a multi-threaded
> application. My code is this:
>
> class Foo {
>   private boolean warned;
>
>   public void run() {
>     if (!warned) {
>        LOG.warn("Warning");
>        warned = true;
>     }
>   }
> }
>
> This is the only access to the variable 'warned', the value change is deliberately unsynchronized,
> and monotonic. Am I right to believe that:
>
> * The first call WILL issue a warning.

Yes.

> * Any thread will issue the warning AT MOST once.

Yes, I think so. It encroaches on darker corners of JMM, but it still does what you want, methinks.

> * Some (later) threads may not issue the warning, if the updated value is flushed to the heap and
> they load it?

Yes, except that "flushed to heap" part: that one is an implementation detail.


> Is there a better way to do this without sacrificing performance? Is this what the mysterious
> AtomicBoolean.lazySet, or even weakCompareAndSet is about?

The classic way to do this is to do test and test-and-set:

class Foo {
   private final AtomicBoolean warned;

   public void run() {
     if (!warned.get() && warned.compareAndSet(false, true)) {
       LOG.warn("Warning");
     }
   }
}

This gives you global only-once property, without sacrificing performance.

There are options how do you represent "warned". I'd start with AtomicBoolean, and then switched to
AtomicIntegerFieldUpdater over volatile field, or VarHandle if footprint became a problem. With
VarHandles, you can even mix the modes: make the first "test" in plain mode, and then do the CAS, if
first volatile check is too costly. But all of this is red herring until there is a pressing need.
One-off guards are doable with just AtomicBoolean.

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




--
Cheers,




--
Cheers,


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I think Viktor wants to avoid volatile read on the fast path. Assuming that even matters, we can do
this with VarHandle doing the plain fastpath read, and then CAS to get exactly-once semantics.
Since, as you say, that thing would be executed approximately once, there is no loss in doing the
right thing, while we are at it.

E.g. (sketching):

class Foo {
  static final VH = <varhandle-over-x>
  boolean x;

  public void run() {
    if (!VH.get(this) // non-volatile fast-path
           && VH.compareAndSet(this, false, true)) {
      LOG.warn(...);
    }
  }
}

But I tend to think this is an overkill, and the plain field is good enough already. Make it
volatile if unsure.

-Aleksey

On 05/31/2018 12:05 PM, Alex Otenko wrote:

> Who cares to optimize the instruction that is going to be executed approximately once?
>
> Alex
>
>> On 31 May 2018, at 11:03, Viktor Klang <[hidden email] <mailto:[hidden email]>> wrote:
>>
>> Or leave the field un-volatile and introduce a release fence before the logging call?
>>
>> On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]
>> <mailto:[hidden email]>> wrote:
>>
>>     The original requirement was it’s ok to sometimes log Warning several times. All this hacky
>>     atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of
>>     the code as is.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
+1

On Thu, May 31, 2018 at 12:15 PM, Aleksey Shipilev <[hidden email]> wrote:
I think Viktor wants to avoid volatile read on the fast path. Assuming that even matters, we can do
this with VarHandle doing the plain fastpath read, and then CAS to get exactly-once semantics.
Since, as you say, that thing would be executed approximately once, there is no loss in doing the
right thing, while we are at it.

E.g. (sketching):

class Foo {
  static final VH = <varhandle-over-x>
  boolean x;

  public void run() {
    if (!VH.get(this) // non-volatile fast-path
           && VH.compareAndSet(this, false, true)) {
      LOG.warn(...);
    }
  }
}

But I tend to think this is an overkill, and the plain field is good enough already. Make it
volatile if unsure.

-Aleksey

On 05/31/2018 12:05 PM, Alex Otenko wrote:
> Who cares to optimize the instruction that is going to be executed approximately once?
>
> Alex
>
>> On 31 May 2018, at 11:03, Viktor Klang <[hidden email] <mailto:[hidden email]>> wrote:
>>
>> Or leave the field un-volatile and introduce a release fence before the logging call?
>>
>> On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]
>> <mailto:[hidden email]>> wrote:
>>
>>     The original requirement was it’s ok to sometimes log Warning several times. All this hacky
>>     atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of
>>     the code as is.




--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I don’t get this advice.

Do the simple thing, declare it volatile. Optimize further (learning curve + operational subtleties) when that is not fast enough. (VH.get cannot be different from volatile load on x86, can it?..)

Alex

> On 31 May 2018, at 11:15, Aleksey Shipilev <[hidden email]> wrote:
>
> I think Viktor wants to avoid volatile read on the fast path. Assuming that even matters, we can do
> this with VarHandle doing the plain fastpath read, and then CAS to get exactly-once semantics.
> Since, as you say, that thing would be executed approximately once, there is no loss in doing the
> right thing, while we are at it.
>
> E.g. (sketching):
>
> class Foo {
>  static final VH = <varhandle-over-x>
>  boolean x;
>
>  public void run() {
>    if (!VH.get(this) // non-volatile fast-path
>           && VH.compareAndSet(this, false, true)) {
>      LOG.warn(...);
>    }
>  }
> }
>
> But I tend to think this is an overkill, and the plain field is good enough already. Make it
> volatile if unsure.
>
> -Aleksey
>
> On 05/31/2018 12:05 PM, Alex Otenko wrote:
>> Who cares to optimize the instruction that is going to be executed approximately once?
>>
>> Alex
>>
>>> On 31 May 2018, at 11:03, Viktor Klang <[hidden email] <mailto:[hidden email]>> wrote:
>>>
>>> Or leave the field un-volatile and introduce a release fence before the logging call?
>>>
>>> On Thu, May 31, 2018 at 11:58 AM, Alex Otenko <[hidden email]
>>> <mailto:[hidden email]>> wrote:
>>>
>>>    The original requirement was it’s ok to sometimes log Warning several times. All this hacky
>>>    atomicity is unnecessary. Just declare private volatile boolean warned, and leave the rest of
>>>    the code as is.
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
On 05/31/2018 12:19 PM, Alex Otenko wrote:
> I don’t get this advice. Do the simple thing, declare it volatile. Optimize further (learning
> curve + operational subtleties) when that is not fast enough.
My original reply was about that: what OP has does appear to work.

It does not mean OP should use it, though, instead of doing the idiomatic shape: do AtomicX, gain
CAS capability, have fast-path test, on slow-path do CAS to perform the action exactly once.
Optimize from that, if you prove that idiom is not working for you.


> (VH.get cannot be different from volatile load on x86, can it?..)

Of course it can, it is the magic of VarHandles: use-site, not declaration-site memory semantics. So
you can have volatile field and do non-volatile read over it, or you can have non-volatile field and
do volatile read or CAS over it.


-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list

> On 31 May 2018, at 11:27, Aleksey Shipilev <[hidden email]> wrote:
>
> On 05/31/2018 12:19 PM, Alex Otenko wrote:
>> I don’t get this advice. Do the simple thing, declare it volatile. Optimize further (learning
>> curve + operational subtleties) when that is not fast enough.
> My original reply was about that: what OP has does appear to work.
>
> It does not mean OP should use it, though, instead of doing the idiomatic shape: do AtomicX, gain
> CAS capability, have fast-path test, on slow-path do CAS to perform the action exactly once.
> Optimize from that, if you prove that idiom is not working for you.
>
>
>> (VH.get cannot be different from volatile load on x86, can it?..)
>
> Of course it can,

By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing faster than volatile load on x86?


Alex

> it is the magic of VarHandles: use-site, not declaration-site memory semantics.
> So
> you can have volatile field and do non-volatile read over it, or you can have non-volatile field and
> do volatile read or CAS over it.
>
>
> -Aleksey
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
On 05/31/2018 12:32 PM, Alex Otenko wrote:
>>> (VH.get cannot be different from volatile load on x86, can it?..)
>>
>> Of course it can,
>
> By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing
> faster than volatile load on x86?

Because there is more to the performance story than just observing the values. For example, having
the non-volatile access on fast-path means you can optimize the code around it better. What makes
VarHandles magical is that we can make the decision on what memory semantics we want for each
particular use. (Pretty like the internal-jdk-class-that-must-not-be-named).

-Aleksey


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Ah, yes, I see the point. Volatile load would cause other loads to also occur, and not reorderable.

Alex

> On 31 May 2018, at 11:37, Aleksey Shipilev <[hidden email]> wrote:
>
> On 05/31/2018 12:32 PM, Alex Otenko wrote:
>>>> (VH.get cannot be different from volatile load on x86, can it?..)
>>>
>>> Of course it can,
>>
>> By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing
>> faster than volatile load on x86?
>
> Because there is more to the performance story than just observing the values. For example, having
> the non-volatile access on fast-path means you can optimize the code around it better. What makes
> VarHandles magical is that we can make the decision on what memory semantics we want for each
> particular use. (Pretty like the internal-jdk-class-that-must-not-be-named).
>
> -Aleksey
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
But it doesn't? It's just a normal, non-volatile read. Or is this the
same on x86?

- Jonas

On 05/31/2018 12:32 PM, Alex Otenko via Concurrency-interest wrote:

>
>> On 31 May 2018, at 11:27, Aleksey Shipilev <[hidden email]> wrote:
>>
>> On 05/31/2018 12:19 PM, Alex Otenko wrote:
>>> I don’t get this advice. Do the simple thing, declare it volatile. Optimize further (learning
>>> curve + operational subtleties) when that is not fast enough.
>> My original reply was about that: what OP has does appear to work.
>>
>> It does not mean OP should use it, though, instead of doing the idiomatic shape: do AtomicX, gain
>> CAS capability, have fast-path test, on slow-path do CAS to perform the action exactly once.
>> Optimize from that, if you prove that idiom is not working for you.
>>
>>
>>> (VH.get cannot be different from volatile load on x86, can it?..)
>>
>> Of course it can,
>
> By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing faster than volatile load on x86?
>
>
> Alex
>
>> it is the magic of VarHandles: use-site, not declaration-site memory semantics.
>> So
>> you can have volatile field and do non-volatile read over it, or you can have non-volatile field and
>> do volatile read or CAS over it.
>>
>>
>> -Aleksey
>>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
On x86 all reads are totally ordered with respect to each other, and stores never go ahead of reads. So all reads have the same semantics as volatile reads on x86 - once the Java code is translated to the actual instructions, that is. The JVM is free to not translate some reads appearing in Java code into the actual instructions, as is permitted by the JMM.


Volatile reads also have implications on what the JVM can do to the rest of the code. Aleksey is being a bit mysterious about what exactly can be done, but what he is getting at, is something like:

* Once you declare a read as volatile, you also force the JVM to materialize all reads that are after it in program order (can’t use the values still in registers anymore), and forces the JVM to not reorder stores ahead of the volatile read.

* If you are able to tell the JVM that it’s ok to reorder and what not, that all that you need is for that one read to not be eliminated, then you allow for all other code movement and optimizations to occur.


Alex

> On 31 May 2018, at 12:21, Jonas Konrad via Concurrency-interest <[hidden email]> wrote:
>
> But it doesn't? It's just a normal, non-volatile read. Or is this the same on x86?
>
> - Jonas
>
> On 05/31/2018 12:32 PM, Alex Otenko via Concurrency-interest wrote:
>>> On 31 May 2018, at 11:27, Aleksey Shipilev <[hidden email]> wrote:
>>>
>>> On 05/31/2018 12:19 PM, Alex Otenko wrote:
>>>> I don’t get this advice. Do the simple thing, declare it volatile. Optimize further (learning
>>>> curve + operational subtleties) when that is not fast enough.
>>> My original reply was about that: what OP has does appear to work.
>>>
>>> It does not mean OP should use it, though, instead of doing the idiomatic shape: do AtomicX, gain
>>> CAS capability, have fast-path test, on slow-path do CAS to perform the action exactly once.
>>> Optimize from that, if you prove that idiom is not working for you.
>>>
>>>
>>>> (VH.get cannot be different from volatile load on x86, can it?..)
>>>
>>> Of course it can,
>> By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing faster than volatile load on x86?
>> Alex
>>> it is the magic of VarHandles: use-site, not declaration-site memory semantics.
>>> So
>>> you can have volatile field and do non-volatile read over it, or you can have non-volatile field and
>>> do volatile read or CAS over it.
>>>
>>>
>>> -Aleksey
>>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Unsynchronized lazy conditions

JSR166 Concurrency mailing list
Actually, “totally ordered” is the wrong word for reads here. “totally ordered” would imply other CPUs agree on the order of reads, too. But it is just “not reordered by a single CPU”.

Still, the instructions for “normal” reads don’t differ from the instructions for “volatile”.

Alex

> On 31 May 2018, at 13:13, Alex Otenko <[hidden email]> wrote:
>
> On x86 all reads are totally ordered with respect to each other, and stores never go ahead of reads. So all reads have the same semantics as volatile reads on x86 - once the Java code is translated to the actual instructions, that is. The JVM is free to not translate some reads appearing in Java code into the actual instructions, as is permitted by the JMM.
>
>
> Volatile reads also have implications on what the JVM can do to the rest of the code. Aleksey is being a bit mysterious about what exactly can be done, but what he is getting at, is something like:
>
> * Once you declare a read as volatile, you also force the JVM to materialize all reads that are after it in program order (can’t use the values still in registers anymore), and forces the JVM to not reorder stores ahead of the volatile read.
>
> * If you are able to tell the JVM that it’s ok to reorder and what not, that all that you need is for that one read to not be eliminated, then you allow for all other code movement and optimizations to occur.
>
>
> Alex
>
>> On 31 May 2018, at 12:21, Jonas Konrad via Concurrency-interest <[hidden email]> wrote:
>>
>> But it doesn't? It's just a normal, non-volatile read. Or is this the same on x86?
>>
>> - Jonas
>>
>> On 05/31/2018 12:32 PM, Alex Otenko via Concurrency-interest wrote:
>>>> On 31 May 2018, at 11:27, Aleksey Shipilev <[hidden email]> wrote:
>>>>
>>>> On 05/31/2018 12:19 PM, Alex Otenko wrote:
>>>>> I don’t get this advice. Do the simple thing, declare it volatile. Optimize further (learning
>>>>> curve + operational subtleties) when that is not fast enough.
>>>> My original reply was about that: what OP has does appear to work.
>>>>
>>>> It does not mean OP should use it, though, instead of doing the idiomatic shape: do AtomicX, gain
>>>> CAS capability, have fast-path test, on slow-path do CAS to perform the action exactly once.
>>>> Optimize from that, if you prove that idiom is not working for you.
>>>>
>>>>
>>>>> (VH.get cannot be different from volatile load on x86, can it?..)
>>>>
>>>> Of course it can,
>>> By what means? If VH.get guarantees observing cache-coherent value, how can it do that observing faster than volatile load on x86?
>>> Alex
>>>> it is the magic of VarHandles: use-site, not declaration-site memory semantics.
>>>> So
>>>> you can have volatile field and do non-volatile read over it, or you can have non-volatile field and
>>>> do volatile read or CAS over it.
>>>>
>>>>
>>>> -Aleksey
>>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> [hidden email]
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
12