Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-09 02:22:21

0001 #ifndef HeterogeneousCore_AlpakaInterface_interface_AtomicPairCounter_h
0002 #define HeterogeneousCore_AlpakaInterface_interface_AtomicPairCounter_h
0003 
0004 #include <cstdint>
0005 
0006 #include <alpaka/alpaka.hpp>
0007 
0008 namespace cms::alpakatools {
0009 
0010   class AtomicPairCounter {
0011   public:
0012     using DoubleWord = uint64_t;
0013 
0014     ALPAKA_FN_HOST_ACC constexpr AtomicPairCounter() : counter_{0} {}
0015     ALPAKA_FN_HOST_ACC constexpr AtomicPairCounter(uint32_t first, uint32_t second) : counter_{pack(first, second)} {}
0016     ALPAKA_FN_HOST_ACC constexpr AtomicPairCounter(DoubleWord values) : counter_{values} {}
0017 
0018     ALPAKA_FN_HOST_ACC constexpr AtomicPairCounter& operator=(DoubleWord values) {
0019       counter_.as_doubleword = values;
0020       return *this;
0021     }
0022 
0023     struct Counters {
0024       uint32_t first;   // in a "One to Many" association is the number of "One"
0025       uint32_t second;  // in a "One to Many" association is the total number of associations
0026     };
0027 
0028     ALPAKA_FN_HOST_ACC constexpr Counters get() const { return counter_.as_counters; }
0029 
0030     // atomically add as_counters, and return the previous value
0031     template <typename TAcc>
0032     ALPAKA_FN_ACC ALPAKA_FN_INLINE constexpr Counters add(const TAcc& acc, Counters c) {
0033       Packer value{pack(c.first, c.second)};
0034       Packer ret{0};
0035       ret.as_doubleword =
0036           alpaka::atomicAdd(acc, &counter_.as_doubleword, value.as_doubleword, alpaka::hierarchy::Blocks{});
0037       return ret.as_counters;
0038     }
0039 
0040     // atomically increment first and add i to second, and return the previous value
0041     template <typename TAcc>
0042     ALPAKA_FN_ACC ALPAKA_FN_INLINE Counters constexpr inc_add(const TAcc& acc, uint32_t i) {
0043       return add(acc, {1u, i});
0044     }
0045 
0046   private:
0047     union Packer {
0048       DoubleWord as_doubleword;
0049       Counters as_counters;
0050       constexpr Packer(DoubleWord _as_doubleword) : as_doubleword(_as_doubleword) { ; };
0051       constexpr Packer(Counters _as_counters) : as_counters(_as_counters) { ; };
0052     };
0053 
0054     // pack two uint32_t values in a DoubleWord (aka uint64_t)
0055     // this is needed because in c++17 a union can only be aggregate-initialised to its first type
0056     // it can be probably removed with c++20, and replace with a designated initialiser
0057     static constexpr DoubleWord pack(uint32_t first, uint32_t second) {
0058       Packer ret{0};
0059       ret.as_counters = {first, second};
0060       return ret.as_doubleword;
0061     }
0062 
0063     Packer counter_;
0064   };
0065 
0066 }  // namespace cms::alpakatools
0067 
0068 #endif  // HeterogeneousCore_AlpakaInterface_interface_AtomicPairCounter_h