RFR 8158039 VarHandle float/double field/array access should support CAS/set/add atomics
Paul Sandoz
paul.sandoz at oracle.com
Fri Jun 10 22:39:54 UTC 2016
Hi Joe,
It’s my turn to catch up on email…
> On 6 Jun 2016, at 17:47, Joseph D. Darcy <Joe.Darcy at oracle.com> wrote:
>
> Hello,
>
> Catching up on email, there are several different notions on floating-point equality one might want to use. [1]
>
> One notion is the built-in "==" operator on float and double. This has the wrinkle of not defining an equivalence relation because of NaN values (not reflexive) and signed zeros (distinguishable values compare as equal).
>
> When I write floating-point tests, I'll use a notion of equality close to
>
> Float.compare(x, y) == 0
>
> which means all NaN values are treated as the same and Float.compare(NaN, NaN) == 0 is true. This also distinguishes the signed zeros from each other.
>
> So comparing based on the non-raw bitwise conversion can give resonable semantics, at the cost of not preserving any payload stored in the NaN significand.
>
And potentially a performance hit too [*].
Pedantically since (NaN == NaN) is false, one could argue that it should not possible to CAS with an expected NaN value and/or a witness NaN value. Such behaviour might be considered BaNaNas :-) (sorry). I don’t think we can or should enforce that, but we should strongly advise against it and mention the pitfalls, and i will need to specify that the atomic ops perform bit-wise equality with suitable “as if” text.
Paul.
[*] For example, the double[] accepting Arrays.equals method used to compare each element as:
2762 for (int i=0; i<length; i++)
2763 if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
2764 return false;
In the interim of my adding vectorized mismatch support i changed that to:
3057 for (int i=0; i<length; i++) {
3058 double v1 = a[i], v2 = a2[i];
3059 if (Double.doubleToRawLongBits(v1) != Double.doubleToRawLongBits(v2))
3060 if (!Double.isNaN(v1) || !Double.isNaN(v2))
3061 return false;
3062 }
Which boosted the performance similar to that of comparing long[] (when no NaNs are present).
> HTH,
>
> -Joe
>
> [1] "Notions of Floating-Point Equality ," https://blogs.oracle.com/darcy/entry/notions_of_floating_point_equality
>
> On 6/2/2016 1:34 AM, Paul Sandoz wrote:
>>> On 2 Jun 2016, at 09:13, David Holmes <david.holmes at oracle.com> wrote:
>>>
>>> On 2/06/2016 1:24 AM, Paul Sandoz wrote:
>>>> (Please note this work is or will be covered with FC exception)
>>>>
>>>> Hi,
>>>>
>>>> Please review the VarHandles/Unsafe support for atomic ops on double/float fields/arrays.
>>> I think this is misguided. If the user wants CAS for float/double they can do the conversion to int/long in a context where they know that conversion makes sense and where they can deal with NaNs appropriately.
>>>
>> I would still like to support some clearly defined default behaviour if at all possible, since this is not easy to get right so we can add some value here. The user can use int/long if that behaviour is not suitable.
>>
>>
>>> At a minimum the fact this deals with raw bit patterns not semantic values needs to be exposed somehow. ie the handling of NaN needs to be explicit.
>>>
>> Yes, it’s multiple NaN values that collapse to a single NaN value.
>>
>> It would be good if our resident floating point expert Mr. Joe Darcy could chime in this respect.
>>
>> On Float.intBitsToFloat:
>>
>> * <p>Note that this method may not be able to return a
>> * {@code float} NaN with exactly same bit pattern as the
>> * {@code int} argument. IEEE 754 distinguishes between two
>> * kinds of NaNs, quiet NaNs and <i>signaling NaNs</i>. The
>> * differences between the two kinds of NaN are generally not
>> * visible in Java. Arithmetic operations on signaling NaNs turn
>> * them into quiet NaNs with a different, but often similar, bit
>> * pattern. However, on some processors merely copying a
>> * signaling NaN also performs that conversion. In particular,
>> * copying a signaling NaN to return it to the calling method may
>> * perform this conversion. So {@code intBitsToFloat} may
>> * not be able to return a {@code float} with a signaling NaN
>> * bit pattern. Consequently, for some {@code int} values,
>> * {@code floatToRawIntBits(intBitsToFloat(start))} may
>> * <i>not</i> equal {@code start}. Moreover, which
>> * particular bit patterns represent signaling NaNs is platform
>> * dependent; although all NaN bit patterns, quiet or signaling,
>> * must be in the NaN range identified above.
>>
>>
>>
>> I am concerned that the CAS loops could in some cases loop without termination:
>>
>> @ForceInline
>> public final float getAndAddFloat(Object o, long offset, float delta) {
>> float v;
>> do {
>> v = getFloatVolatile(o, offset);
>> } while (!weakCompareAndSwapFloatVolatile(o, offset, v, v + delta));
>> return v;
>> }
>>
>>
>> I think this should be:
>>
>> @ForceInline
>> public final float getAndAddFloat(Object o, long offset, float delta) {
>> int expectedBits;
>> float v;
>> do {
>> expectedBits = getIntVolatile(o, offset);
>> v = Float.intBitsToFloat(bits); // May not preserve a NaN value with the same bit pattern as expectedBits
>> } while (!weakCompareAndSwapIntVolatile(o, offset, expectedBits, Float.floatToRawIntBits(v + delta)));
>> return v;
>> }
>>
>> and likewise for the atomic get-and-set methods.
>>
>> Paul.
>>
>>> David
>>> -----
>>>
>>>> http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8158039-float-double-field-array-cas.jdk/webrev/ <http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8158039-float-double-field-array-cas.jdk/webrev/>
>>>> http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8158039-float-double-field-array-cas.hotspot/webrev/ <http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8158039-float-double-field-array-cas.hotspot/webrev/>
>>>>
>>>> These patches are based on those of for sub-word CAS
>>>>
>>>> https://bugs.openjdk.java.net/browse/JDK-8157726 <https://bugs.openjdk.java.net/browse/JDK-8157726>
>>>> http://cr.openjdk.java.net/~shade/8157726/webrev.hs.03/ <http://cr.openjdk.java.net/~shade/8157726/webrev.hs.03/>
>>>> http://cr.openjdk.java.net/~shade/8157726/webrev.jdk.03/ <http://cr.openjdk.java.net/~shade/8157726/webrev.jdk.03/>
>>>>
>>>> And the two patches combined expand the support of fields/arrays.
>>>>
>>>>
>>>> New float/double CAS methods are added to Unsafe that defer to int/long equivalents. Then the other atomic methods are built from weak CAS loops.
>>>>
>>>> No changes are required to HotSpot, but changes are required to the Unsafe tests in the hotspot repository.
>>>>
>>>> In general the changes to VHs and tests are minimal since it is triggered from changes to the generating scripts that now include float/double into the CAS category.
>>>>
>>>> There are some minor specification changes and a CCC has been initiated.
>>>>
>>>> JPRT tests results show no relevant failures for hotspot and core test sets.
>>>>
>>>> Thanks,
>>>> Paul.
>>>>
>
More information about the jdk9-dev
mailing list