RFR: 8236778: Add Atomic::fetch_and_add
David Holmes
david.holmes at oracle.com
Fri Jan 10 02:05:01 UTC 2020
Hi Stefan,
On 10/01/2020 8:17 am, Stefan Karlsson wrote:
> Updated webrev:
> https://cr.openjdk.java.net/~stefank/8236778/webrev.02.delta
> https://cr.openjdk.java.net/~stefank/8236778/webrev.02
That all seems okay to me (not that I fully understand the details of
the template code). I'll leave you and Kim to work out the details of
the commentary.
Thanks,
David
> Comments below:
>
> On 2020-01-09 01:00, Kim Barrett wrote:
>>> On Jan 8, 2020, at 10:34 AM, Stefan Karlsson
>>> <stefan.karlsson at oracle.com> wrote:
>>>
>>> Hi all,
>>>
>>> Please review this patch to introduce Atomic::fetch_and_add.
>>>
>>> https://cr.openjdk.java.net/~stefank/8236778/webrev.01
>>> https://bugs.openjdk.java.net/browse/JDK-8236778
>>>
>>> There are a number of places where we have this pattern:
>>> int result = Atomic::add(_index, amount) - amount;
>>>
>>> I'd like to introduce Atomic::fetch_and_add so that we can write:
>>> int result = Atomic::fetch_and_add(_index, amount);
>> ------------------------------------------------------------------------------
>>
>> src/hotspot/share/runtime/atomic.hpp
>> Removed:
>> 240 // - platform_add is an object of type PlatformAdd<sizeof(D)>.
>> 241 //
>> 242 // Then
>> 243 // platform_add(dest, add_value)
>> 244 // must be a valid expression, returning a result convertible
>> to D.
>>
>> and
>>
>> 250 // Helper base classes for defining PlatformAdd. To use, define
>> ...
>> 275 // caller.
>>
>> These comments should have been updated to describe the new protocol
>> for PlatformAdd, rather than simply removed. Documentation of
>> extension points like this is important.
>
> The comments seemed to already have started deteriorating. It's seems to
> be missing an *if* that matches the *then, and it doesn't mention
> *order*. So, instead of trying to figure out what the comment tried to
> say, I opted from getting rid of those problems by getting rid of that
> part of the comment. I thought the code was pretty self-explanatory, and
> didn't need that part. I'm not opposed to fixing the comments if you
> have suggestions.
>
>> Something like
>>
>> // - platform_add is an object of type PlatformAdd<sizeof(D)>.
>> //
>> // Then both
>> // platform_add.add_and_fetch(dest, add_value)
>> // platform_add.fetch_and_add(dest, add_value)
>> // must be valid expressions returning a result convertible to D.
>> //
>> // add_and_fetch atomically adds add_value to the value of dest,
>> // returning the new value.
>> //
>> // fetch_and_add atomically adds add_value to the value of dest,
>> // returning the old value.
>> //
>> // When D is a pointer type P*, both add_and_fetch and fetch_and_add
>> // treat it as if it were an uintptr_t; they do not perform any
>> // scaling of add_value, as that has already been done by the caller.
>
> I'll update the code verbatim with what you've suggested.
>
>>
>> ------------------------------------------------------------------------------
>>
>> src/hotspot/share/runtime/atomic.hpp
>> 679 static I scale_addend(I add_value) {
>> 680 return add_value * sizeof(P);
>> 681 }
>> 682
>> 683 static P* add_and_fetch(P* volatile* dest, I add_value,
>> atomic_memory_order order) {
>> 684 CI addend = add_value;
>> 685 return PlatformAdd<sizeof(P*)>().add_and_fetch(dest,
>> scale_addend(addend), order);
>> 686 }
>>
>> This is converting add_value from I to CI then back to I, the latter
>> possibly being a narrowing conversion. Better would be
>>
>> static CI scale_addend(CI add_value) {
>> return add_value * sizeof(P);
>> }
>>
>> and then either
>>
>> static P* add_and_fetch(P* volatile* dest, I add_value,
>> atomic_memory_order order) {
>> CI addend = scale_addend(add_value);
>> return PlatformAdd<sizeof(P*)>().add_and_fetch(dest, addend, order);
>> }
>>
>> or don't bother with the addend variable and just pass the scaled
>> result directly to add_and_fetch / fetch_and_add.
>
> Thanks. This was an unintentional change from the original code.
>>
>> ------------------------------------------------------------------------------
>>
>> src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp
>> 54 #pragma warning(disable: 4035) // Disables warnings reporting
>> missing return statement
>>
>> Pre-existing: This warning suppression (and the corresponding
>> restoration) appears to only be needed for the !defined(AMD64) case
>> (where __asm statements are being used), and should be moved accordingly.
>
> Will you create a bug report for that?
>
>>
>> ------------------------------------------------------------------------------
>>
>>
>>> The current implementation already has support for both "add and
>>> fetch" and "fetch and add" but it's not exposed to the upper layers.
>>>
>>> Previously, the platform-specific code either implemented "add and
>>> fetch" or "fetch and add", and then exposed it as an "add and fetch"
>>> implementation by using CRTP and inheriting from either AddAndFetch
>>> or FetchAndAdd.
>>>
>>> My first implementation of this continued in this track, but got
>>> push-back because the code was non-intuitive and/or used
>>> non-intuitive names. Therefore, I've removed FetchAndAdd/AddAndFetch
>>> and opted to duplicate the trivial functionality in the platform
>>> files instead. For example:
>>>
>>> + template<typename D, typename I>
>>> + D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order
>>> order) const {
>>> + return fetch_and_add(dest, add_value, order) + add_value;
>>> + }
>> For the record, I would have been fine with (and actually preferred; I
>> dislike roughly a dozen copies of one or the other of the translation
>> functions) CRTP-based AddAndFetch and FetchAndAdd that provided one
>> operation in terms of the other.
>>
>> The move of the scaling of add_value in the pointer case to AddImpl is
>> an improvement (even on the pre-existing code) that might have made
>> such a CRTP approach clearer, possibly with some name changes. Then
>> the helper CRTP base class just provides one of the functions in terms
>> of Derived's other function, and nothing else.
>>
>> Perhaps the hardest part of that approach is naming the helper base
>> classes. FetchAndAddUsingAddAndFetch is explicit but quite a
>> mouthful. Perhaps FetchAndAddHelper, which provides fetch_and_add in
>> terms of Derived's add_and_fetch?
>>
>> Apologies for not having followed the internal pre-review discussion
>> of this and so not commenting there.
>>
>>> There has been some thoughts that maybe we should have:
>>>
>>> void Atomic::add(...)
>>> D Atomic::add_and_fetch(...)
>>> D Atomic::fetch_and_add(...)
>>>
>>> Not sure if it's worth changing to this, but if others think this is
>>> good, I can do that change.
>> I would be okay with renaming "add" to "add_and_fetch", though I don't
>> at the moment have a strong preference either way. I'm not sure also
>> providing "add" that returns void is really all that useful. We have
>> "inc" and "dec" that return void; my recollection is that they were at
>> one time thought to provide an opportunity for a more efficient
>> implementation on some platforms, but discussion during the
>> templatization project showed that compilers could eliminate an unused
>> return value anyway.
>>
>> For symmetry it seems like we should have fetch_and_sub, but I don't
>> see any current uses of sub that would need that.
>>
>> If add_and_fetch is added (either instead of or in addition to add),
>> then we should definitely treat the subtraction case similarly.
>
> I'll interpret your comments above that there might be opportunities to
> do more changes, but none of those needs to be done for this patch.
>
>>
>>> Tested with tier123, but only compiled on platforms I have access to.
>> mach5 has the ability to cross-compile to several OpenJDK platforms
>> not otherwise supported by Oracle, though can't run tests. That can
>> be a useful smoke test to at least avoid things like typos that don't
>> build. For example, "-b linux-aarch64-debug”.
>
> Right. I wasn't explicit about it, but I've compiled locally (linux) for
> aarch64, arm32, ppc64, s390, zero, minimal.
>
> Thanks,
> StefanK
>>
>
More information about the hotspot-dev
mailing list