RFR: 8186476: Generalize Atomic::add with templates
David Holmes
david.holmes at oracle.com
Tue Aug 29 07:28:46 UTC 2017
<trimming>
On 29/08/2017 5:13 PM, Erik Österlund wrote:
> Hi Coleen, David,
>
> On 2017-08-29 09:05, David Holmes wrote:
>> On 29/08/2017 5:33 AM, coleen.phillimore at oracle.com wrote:
>>> On 8/28/17 12:33 PM, Erik Osterlund wrote:
>>>>> What is the distinction between FetchAndAdd and AddAndFetch? Does
>>>>> one assume that the value is in a register and is based on the
>>>>> underlying platform implementation? Can you put a comment in
>>>>> atomic.hpp why one vs the other? These platform inconsistencies
>>>>> are really painful since nobody can't test all the platforms. I
>>>>> don't need to see another version of this change, the rest looks ok
>>>>> to me.
>>>> The distinction is whether the platform specialization returns the
>>>> value before or after the add, i.e., whether whether the returned
>>>> fetched value corresponds to the old or new value, as indicated by
>>>> the corresponding name. This is a standard convention used by e.g.
>>>> GCC intrinsics.
>>>
>>> Oh, I see. Since nothing generally uses the return value, the
>>> inconsistency doesn't matter?
>>
>> The Atomic::add API specifies that the returned value is the updated
>> value. I must confess I'm now a bit confused here as it seems to me
>> that PlatformAdd should always be a "AddAndFetch" to ensure the
>> correct semantics. ???
>
> Yes, you are right that the public API uses add_and_fetch semantics. But
> AddAndFetch and FetchAndAdd are only adapters to the platform layer for
> internal use. The platform layer has a specialization that is specified
> as either FetchAndAdd or AddAndFetch, which is converted to the intended
> add_and_fetch semantics expected by the public API in
> Atomic::FetchAndAdd<Derived>::operator() and
> Atomic::AddAndFetch<Derived>::operator() correspondingly. So it is only
> a helper for the platform layer.
Okay I'm completely lost here - sorry. I'm expecting to see a
PlatformAdd that has the semantics of Atomic::add - which does an
add_and_fetch. So this looks fine:
src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
{
template<typename I, typename D>
D add_and_fetch(I add_value, D volatile* dest) const;
};
while this looks wrong:
src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::FetchAndAdd<Atomic::PlatformAdd<byte_size> >
{
template<typename I, typename D>
D fetch_and_add(I add_value, D volatile* dest) const;
};
???
Thanks,
David
> Thanks,
> /Erik
>
>> David
>> -----
>>
>>
>>>>
>>>> Unfortunately I have already pushed the change as David and Andrew
>>>> said I was good to go. I am sorry about that. I will add a short
>>>> comment in a subsequent inc/dec patch for you.
>>>
>>> Okay.
>>> Coleen
>>>
>>>> Thanks for the review.
>>>>
>>>> Thanks,
>>>> /Erik
>>>>
>>>>> Thanks,
>>>>> Coleen
>>>>>
>>>>>
>>>>>> On 8/20/17 2:16 AM, Kim Barrett wrote:
>>>>>> Please review this change to Atomic::add, making it a function
>>>>>> template with a per-platform underlying implementation.
>>>>>>
>>>>>> This change is similar to 8186166: "Generalize Atomic::cmpxchg with
>>>>>> templates", with similar goals and taking a similar approach.
>>>>>>
>>>>>> This change deprecates add_ptr. Followup changes will convert
>>>>>> existing uses of cmpxchg_ptr and eventually remove it. Followup
>>>>>> changes will also update uses of cmpxchg that can be simplified
>>>>>> because of the generalized API. Only changes to usage that were
>>>>>> required by the new implementation have been made so far.
>>>>>>
>>>>>> The add function calls private Atomic::AddImpl, to select among
>>>>>> several cases, based on the argument types. Each case performs some
>>>>>> checking and possibly conversion to reach a standard form of the
>>>>>> arguments (or fail and report a compile time error), which are then
>>>>>> passed to private Atomic::PlatformAdd.
>>>>>>
>>>>>> Only safe conversions of the first (add_value) argument are made by
>>>>>> the AddImpl layer. add_value must be integral, and is never
>>>>>> narrowed.
>>>>>> dest's value type must be either integral or a pointer type. When
>>>>>> both are integral, they must be of the same signedness. If smaller,
>>>>>> add_value will be promited to the same size as dest's value type.
>>>>>>
>>>>>> The PlatformAdd class is provided by each platform, and performs
>>>>>> additional case analysis to generate the appropriate code for the
>>>>>> platform. Most PlatformAdd implementations use one of two helper
>>>>>> base
>>>>>> classes, Atomic::FetchAndAdd and Atomic::AddAndFetch. These provide
>>>>>> common parts of the implementation in terms of a support function
>>>>>> provided by the derived PlatformAdd, accessed using CRTP.
>>>>>>
>>>>>> This change involves modifications to all of the existing platform
>>>>>> implementations of Atomic::add. I've updated all of the platforms,
>>>>>> but only tested those supported by Oracle. I'll need help from the
>>>>>> various platform maintainers to check and test my changes.
>>>>>>
>>>>>> Changes to files can be categorized as follows:
>>>>>>
>>>>>> [No new metaprogramming tools!]
>>>>>>
>>>>>> Change add to a template:
>>>>>> atomic.hpp
>>>>>>
>>>>>> Oracle-supported platforms:
>>>>>> atomic_bsd_x86.hpp - 64bit only
>>>>>> atomic_linux_arm.hpp
>>>>>> atomic_linux_x86.hpp
>>>>>> atomic_solaris_sparc.hpp
>>>>>> solaris_sparc.il
>>>>>> atomic_solaris_x86.hpp
>>>>>> atomic_windows_x86
>>>>>>
>>>>>> Non-Oracle platform changes:
>>>>>> atomic_aix_ppc.hpp
>>>>>> atomic_bsd_x86.hpp - 32bit
>>>>>> atomic_bsd_zero.hpp
>>>>>> atomic_linux_aarch.hpp
>>>>>> atomic_linux_ppc.hpp
>>>>>> atomic_linux_s390.hpp
>>>>>> atomic_linux_sparc.hpp
>>>>>> atomic_linux_zero.hpp
>>>>>>
>>>>>> Usage changes required by API change:
>>>>>> g1CardLiveData.cpp
>>>>>> g1ConcurrentMark.cpp
>>>>>> g1HotCardCache.cpp
>>>>>> g1HotCardCache.hpp
>>>>>> g1RemSet.cpp
>>>>>> symbol.cpp
>>>>>> mallocTracker.hpp
>>>>>>
>>>>>> A few specific items:
>>>>>>
>>>>>> - atomic_linux_arm.hpp
>>>>>>
>>>>>> Neither add variant has "cc" in the clobbers list, even though the
>>>>>> condition codes are modified. That seems like a pre-existing bug.
>>>>>>
>>>>>> - atomic_linux_sparc.hpp
>>>>>>
>>>>>> Neither add variant has "cc" in the clobbers list, even though the
>>>>>> condition codes are modified. That seems like a pre-existing bug.
>>>>>>
>>>>>> The 32-bit add was using intptr_t as the rv type. Probably a harmless
>>>>>> copy-paste mistake. Now using template parameter type.
>>>>>>
>>>>>> Uses hard-coded machine registers and assumes the inline-asm
>>>>>> processing assigns the values to the corresponding machine registers,
>>>>>> even though the given constraints are just generic register requests.
>>>>>> I don't understand how this can work.
>>>>>>
>>>>>> - atomic_solaris_sparc.hpp
>>>>>>
>>>>>> Atomic::add was implemented using asm code in solaris_sparc.il. I
>>>>>> was
>>>>>> going to change it to use gcc-style inline-asm, but the linux_sparc
>>>>>> version wasn't helpful this time (unlike for cmpxchg) (see above).
>>>>>> Instead, I wrote the CAS-loop in C++, using Atomic::cmpxchg; much
>>>>>> simpler code, and should be no less efficient, assuming the compiler
>>>>>> does it's job.
>>>>>>
>>>>>> CR:
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8186476
>>>>>>
>>>>>> Webrev:
>>>>>> http://cr.openjdk.java.net/~kbarrett/8186476/hotspot.00/
>>>>>>
>>>>>> Testing:
>>>>>> Ad hoc hotspot nightly test.
>>>>>>
>>>>>>
>>>
>
More information about the hotspot-dev
mailing list