1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 //                        Kokkos v. 3.0
6 //       Copyright (2020) National Technology & Engineering
7 //               Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #ifndef KOKKOS_SHARED_ALLOC_HPP
46 #define KOKKOS_SHARED_ALLOC_HPP
47 
48 #include <Kokkos_Macros.hpp>
49 #include <Kokkos_Core_fwd.hpp>
50 #include <impl/Kokkos_Error.hpp>  // Impl::throw_runtime_exception
51 
52 #include <cstdint>
53 #include <string>
54 
55 #if defined(KOKKOS_ENABLE_OPENMPTARGET)
56 // Base function.
kokkos_omp_on_host()57 static constexpr bool kokkos_omp_on_host() { return true; }
58 #if defined(KOKKOS_COMPILER_PGI)
59 #define KOKKOS_IMPL_IF_ON_HOST if (!__builtin_is_device_code())
60 #else
61 // Note: OpenMPTarget enforces C++17 at configure time
62 #pragma omp begin declare variant match(device = {kind(host)})
kokkos_omp_on_host()63 static constexpr bool kokkos_omp_on_host() { return true; }
64 #pragma omp end declare variant
65 
66 #pragma omp begin declare variant match(device = {kind(nohost)})
kokkos_omp_on_host()67 static constexpr bool kokkos_omp_on_host() { return false; }
68 #pragma omp end declare variant
69 
70 #define KOKKOS_IMPL_IF_ON_HOST if constexpr (kokkos_omp_on_host())
71 #endif
72 #else
73 #define KOKKOS_IMPL_IF_ON_HOST if (true)
74 #endif
75 
76 namespace Kokkos {
77 namespace Impl {
78 
79 template <class MemorySpace = void, class DestroyFunctor = void>
80 class SharedAllocationRecord;
81 
82 template <class MemorySpace>
83 class SharedAllocationRecordCommon;
84 
85 class SharedAllocationHeader {
86  private:
87   using Record = SharedAllocationRecord<void, void>;
88 
89   static constexpr unsigned maximum_label_length =
90       (1u << 7 /* 128 */) - sizeof(Record*);
91 
92   template <class, class>
93   friend class SharedAllocationRecord;
94   template <class>
95   friend class SharedAllocationRecordCommon;
96   template <class>
97   friend class HostInaccessibleSharedAllocationRecordCommon;
98 
99   Record* m_record;
100   char m_label[maximum_label_length];
101 
102  public:
103   /* Given user memory get pointer to the header */
get_header(void * alloc_ptr)104   KOKKOS_INLINE_FUNCTION static const SharedAllocationHeader* get_header(
105       void* alloc_ptr) {
106     return reinterpret_cast<SharedAllocationHeader*>(
107         reinterpret_cast<char*>(alloc_ptr) - sizeof(SharedAllocationHeader));
108   }
109 
110   KOKKOS_INLINE_FUNCTION
label() const111   const char* label() const { return m_label; }
112 };
113 
114 template <>
115 class SharedAllocationRecord<void, void> {
116  protected:
117   static_assert(sizeof(SharedAllocationHeader) == (1u << 7 /* 128 */),
118                 "sizeof(SharedAllocationHeader) != 128");
119 
120   template <class, class>
121   friend class SharedAllocationRecord;
122   template <class>
123   friend class SharedAllocationRecordCommon;
124   template <class>
125   friend class HostInaccessibleSharedAllocationRecordCommon;
126 
127   using function_type = void (*)(SharedAllocationRecord<void, void>*);
128 
129   SharedAllocationHeader* const m_alloc_ptr;
130   size_t const m_alloc_size;
131   function_type const m_dealloc;
132 #ifdef KOKKOS_ENABLE_DEBUG
133   SharedAllocationRecord* const m_root;
134   SharedAllocationRecord* m_prev;
135   SharedAllocationRecord* m_next;
136 #endif
137   int m_count;
138 
139   SharedAllocationRecord(SharedAllocationRecord&&)      = delete;
140   SharedAllocationRecord(const SharedAllocationRecord&) = delete;
141   SharedAllocationRecord& operator=(SharedAllocationRecord&&) = delete;
142   SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete;
143 
144   /**\brief  Construct and insert into 'arg_root' tracking set.
145    *         use_count is zero.
146    */
147   SharedAllocationRecord(
148 #ifdef KOKKOS_ENABLE_DEBUG
149       SharedAllocationRecord* arg_root,
150 #endif
151       SharedAllocationHeader* arg_alloc_ptr, size_t arg_alloc_size,
152       function_type arg_dealloc);
153  private:
154   static KOKKOS_THREAD_LOCAL int t_tracking_enabled;
155 
156  public:
get_label() const157   virtual std::string get_label() const { return std::string("Unmanaged"); }
158 
159 #ifdef KOKKOS_IMPL_ENABLE_OVERLOAD_HOST_DEVICE
160   /* Device tracking_enabled -- always disabled */
161   KOKKOS_IMPL_DEVICE_FUNCTION
tracking_enabled()162   static int tracking_enabled() { return 0; }
163 #endif
164 
165   KOKKOS_IMPL_HOST_FUNCTION
tracking_enabled()166   static int tracking_enabled() {
167     KOKKOS_IMPL_IF_ON_HOST { return t_tracking_enabled; }
168     else {
169       return 0;
170     }
171   }
172 
173   /**\brief A host process thread claims and disables the
174    *        shared allocation tracking flag.
175    */
tracking_disable()176   static void tracking_disable() {
177     KOKKOS_IMPL_IF_ON_HOST { t_tracking_enabled = 0; }
178   }
179 
180   /**\brief A host process thread releases and enables the
181    *        shared allocation tracking flag.
182    */
tracking_enable()183   static void tracking_enable() {
184     KOKKOS_IMPL_IF_ON_HOST { t_tracking_enabled = 1; }
185   }
186 
187   virtual ~SharedAllocationRecord() = default;
188 
SharedAllocationRecord()189   SharedAllocationRecord()
190       : m_alloc_ptr(nullptr),
191         m_alloc_size(0),
192         m_dealloc(nullptr)
193 #ifdef KOKKOS_ENABLE_DEBUG
194         ,
195         m_root(this),
196         m_prev(this),
197         m_next(this)
198 #endif
199         ,
200         m_count(0) {
201   }
202 
203   static constexpr unsigned maximum_label_length =
204       SharedAllocationHeader::maximum_label_length;
205 
206   KOKKOS_INLINE_FUNCTION
head() const207   const SharedAllocationHeader* head() const { return m_alloc_ptr; }
208 
209   /* User's memory begins at the end of the header */
210   KOKKOS_INLINE_FUNCTION
data() const211   void* data() const { return reinterpret_cast<void*>(m_alloc_ptr + 1); }
212 
213   /* User's memory begins at the end of the header */
size() const214   size_t size() const { return m_alloc_size - sizeof(SharedAllocationHeader); }
215 
216   /* Cannot be 'constexpr' because 'm_count' is volatile */
use_count() const217   int use_count() const { return *static_cast<const volatile int*>(&m_count); }
218 
219 #ifdef KOKKOS_IMPL_ENABLE_OVERLOAD_HOST_DEVICE
220   /* Device tracking_enabled -- always disabled */
221   KOKKOS_IMPL_DEVICE_FUNCTION
increment(SharedAllocationRecord *)222   static void increment(SharedAllocationRecord*){};
223 #endif
224 
225   /* Increment use count */
226   KOKKOS_IMPL_HOST_FUNCTION
227   static void increment(SharedAllocationRecord*);
228 
229 #ifdef KOKKOS_IMPL_ENABLE_OVERLOAD_HOST_DEVICE
230   /* Device tracking_enabled -- always disabled */
231   KOKKOS_IMPL_DEVICE_FUNCTION
decrement(SharedAllocationRecord *)232   static void decrement(SharedAllocationRecord*){};
233 #endif
234 
235   /* Decrement use count. If 1->0 then remove from the tracking list and invoke
236    * m_dealloc */
237   KOKKOS_IMPL_HOST_FUNCTION
238   static SharedAllocationRecord* decrement(SharedAllocationRecord*);
239 
240   /* Given a root record and data pointer find the record */
241   static SharedAllocationRecord* find(SharedAllocationRecord* const,
242                                       void* const);
243 
244   /*  Sanity check for the whole set of records to which the input record
245    * belongs. Locks the set's insert/erase operations until the sanity check is
246    * complete.
247    */
248   static bool is_sane(SharedAllocationRecord*);
249 
250   /*  Print host-accessible records */
251   static void print_host_accessible_records(
252       std::ostream&, const char* const space_name,
253       const SharedAllocationRecord* const root, const bool detail);
254 };
255 
256 template <class MemorySpace>
257 class SharedAllocationRecordCommon : public SharedAllocationRecord<void, void> {
258  private:
259   using derived_t     = SharedAllocationRecord<MemorySpace, void>;
260   using record_base_t = SharedAllocationRecord<void, void>;
self()261   derived_t& self() { return *static_cast<derived_t*>(this); }
self() const262   derived_t const& self() const { return *static_cast<derived_t const*>(this); }
263 
264  protected:
265   using record_base_t::record_base_t;
266 
267   void _fill_host_accessible_header_info(SharedAllocationHeader& arg_header,
268                                          std::string const& arg_label);
269 
270   static void deallocate(record_base_t* arg_rec);
271 
272  public:
273   static auto allocate(MemorySpace const& arg_space,
274                        std::string const& arg_label, size_t arg_alloc_size)
275       -> derived_t*;
276   /**\brief  Allocate tracked memory in the space */
277   static void* allocate_tracked(MemorySpace const& arg_space,
278                                 std::string const& arg_alloc_label,
279                                 size_t arg_alloc_size);
280   /**\brief  Reallocate tracked memory in the space */
281   static void deallocate_tracked(void* arg_alloc_ptr);
282   /**\brief  Deallocate tracked memory in the space */
283   static void* reallocate_tracked(void* arg_alloc_ptr, size_t arg_alloc_size);
284   static auto get_record(void* alloc_ptr) -> derived_t*;
285   std::string get_label() const;
286   static void print_records(std::ostream& s, MemorySpace const&,
287                             bool detail = false);
288 };
289 
290 template <class MemorySpace>
291 class HostInaccessibleSharedAllocationRecordCommon
292     : public SharedAllocationRecordCommon<MemorySpace> {
293  private:
294   using base_t        = SharedAllocationRecordCommon<MemorySpace>;
295   using derived_t     = SharedAllocationRecord<MemorySpace, void>;
296   using record_base_t = SharedAllocationRecord<void, void>;
297 
298  protected:
299   using base_t::base_t;
300 
301  public:
302   static void print_records(std::ostream& s, MemorySpace const&,
303                             bool detail = false);
304   static auto get_record(void* alloc_ptr) -> derived_t*;
305   std::string get_label() const;
306 };
307 
308 namespace {
309 
310 /* Taking the address of this function so make sure it is unique */
311 template <class MemorySpace, class DestroyFunctor>
deallocate(SharedAllocationRecord<void,void> * record_ptr)312 void deallocate(SharedAllocationRecord<void, void>* record_ptr) {
313   using base_type = SharedAllocationRecord<MemorySpace, void>;
314   using this_type = SharedAllocationRecord<MemorySpace, DestroyFunctor>;
315 
316   this_type* const ptr =
317       static_cast<this_type*>(static_cast<base_type*>(record_ptr));
318 
319   ptr->m_destroy.destroy_shared_allocation();
320 
321   delete ptr;
322 }
323 
324 }  // namespace
325 
326 /*
327  *  Memory space specialization of SharedAllocationRecord< Space , void >
328  * requires :
329  *
330  *  SharedAllocationRecord< Space , void > : public SharedAllocationRecord< void
331  * , void >
332  *  {
333  *    // delete allocated user memory via static_cast to this type.
334  *    static void deallocate( const SharedAllocationRecord<void,void> * );
335  *    Space m_space ;
336  *  }
337  */
338 template <class MemorySpace, class DestroyFunctor>
339 class SharedAllocationRecord
340     : public SharedAllocationRecord<MemorySpace, void> {
341  private:
SharedAllocationRecord(const MemorySpace & arg_space,const std::string & arg_label,const size_t arg_alloc)342   SharedAllocationRecord(const MemorySpace& arg_space,
343                          const std::string& arg_label, const size_t arg_alloc)
344       /*  Allocate user memory as [ SharedAllocationHeader , user_memory ] */
345       : SharedAllocationRecord<MemorySpace, void>(
346             arg_space, arg_label, arg_alloc,
347             &Kokkos::Impl::deallocate<MemorySpace, DestroyFunctor>),
348         m_destroy() {}
349 
350   SharedAllocationRecord()                              = delete;
351   SharedAllocationRecord(const SharedAllocationRecord&) = delete;
352   SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete;
353 
354  public:
355   DestroyFunctor m_destroy;
356 
357   // Allocate with a zero use count.  Incrementing the use count from zero to
358   // one inserts the record into the tracking list.  Decrementing the count from
359   // one to zero removes from the trakcing list and deallocates.
allocate(const MemorySpace & arg_space,const std::string & arg_label,const size_t arg_alloc)360   KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate(
361       const MemorySpace& arg_space, const std::string& arg_label,
362       const size_t arg_alloc) {
363 #if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST)
364     return new SharedAllocationRecord(arg_space, arg_label, arg_alloc);
365 #else
366     (void)arg_space;
367     (void)arg_label;
368     (void)arg_alloc;
369     return (SharedAllocationRecord*)0;
370 #endif
371   }
372 };
373 
374 template <class MemorySpace>
375 class SharedAllocationRecord<MemorySpace, void>
376     : public SharedAllocationRecord<void, void> {};
377 
378 union SharedAllocationTracker {
379  private:
380   using Record = SharedAllocationRecord<void, void>;
381 
382   enum : uintptr_t { DO_NOT_DEREF_FLAG = 0x01ul };
383 
384   // The allocation record resides in Host memory space
385   uintptr_t m_record_bits;
386   Record* m_record;
387 
388  public:
389   // Use macros instead of inline functions to reduce
390   // pressure on compiler optimization by reducing
391   // number of symbols and inline functions.
392 
393 #if defined(KOKKOS_IMPL_ENABLE_OVERLOAD_HOST_DEVICE)
394 
395 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_ENABLED Record::tracking_enabled()
396 
397 #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST
398 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_CONDITION \
399   (!(m_record_bits & DO_NOT_DEREF_FLAG))
400 #else
401 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_CONDITION (0)
402 #endif
403 
404 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT \
405   if (KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_CONDITION)  \
406     KOKKOS_IMPL_IF_ON_HOST Record::increment(m_record);
407 
408 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT \
409   if (KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_CONDITION)  \
410     KOKKOS_IMPL_IF_ON_HOST Record::decrement(m_record);
411 
412 #elif defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST)
413 
414 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_ENABLED Record::tracking_enabled()
415 
416 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT \
417   if (!(m_record_bits & DO_NOT_DEREF_FLAG))             \
418     KOKKOS_IMPL_IF_ON_HOST Record::increment(m_record);
419 
420 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT \
421   if (!(m_record_bits & DO_NOT_DEREF_FLAG))             \
422     KOKKOS_IMPL_IF_ON_HOST Record::decrement(m_record);
423 
424 #else
425 
426 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_ENABLED 0
427 
428 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT /* */
429 
430 #define KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT /* */
431 
432 #endif
433 
434 #define KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS(rhs,               \
435                                                         override_tracking) \
436   (((!override_tracking) || (rhs.m_record_bits & DO_NOT_DEREF_FLAG) ||     \
437     (!KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_ENABLED))                      \
438        ? rhs.m_record_bits | DO_NOT_DEREF_FLAG                             \
439        : rhs.m_record_bits)
440 
441   /** \brief  Assign a specialized record */
assign_allocated_record_to_uninitialized(Record * arg_record)442   inline void assign_allocated_record_to_uninitialized(Record* arg_record) {
443     if (arg_record) {
444       Record::increment(m_record = arg_record);
445     } else {
446       m_record_bits = DO_NOT_DEREF_FLAG;
447     }
448   }
449 
450   template <class MemorySpace>
get_record() const451   constexpr SharedAllocationRecord<MemorySpace, void>* get_record() const
452       noexcept {
453     return (m_record_bits & DO_NOT_DEREF_FLAG)
454                ? nullptr
455                : static_cast<SharedAllocationRecord<MemorySpace, void>*>(
456                      m_record);
457   }
458 
459   template <class MemorySpace>
get_label() const460   std::string get_label() const {
461     return (m_record_bits == DO_NOT_DEREF_FLAG)
462                ? std::string()
463                : reinterpret_cast<SharedAllocationRecord<MemorySpace, void>*>(
464                      m_record_bits & ~DO_NOT_DEREF_FLAG)
465                      ->get_label();
466   }
467 
468   KOKKOS_INLINE_FUNCTION
use_count() const469   int use_count() const {
470 #if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST)
471     Record* const tmp =
472         reinterpret_cast<Record*>(m_record_bits & ~DO_NOT_DEREF_FLAG);
473     return (tmp ? tmp->use_count() : 0);
474 #else
475     return 0;
476 #endif
477   }
478 
479   KOKKOS_INLINE_FUNCTION
has_record() const480   bool has_record() const {
481     return (m_record_bits & (~DO_NOT_DEREF_FLAG)) != 0;
482   }
483 
484   KOKKOS_FORCEINLINE_FUNCTION
clear()485   void clear() {
486     // If this is tracking then must decrement
487     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
488     // Reset to default constructed value.
489     m_record_bits = DO_NOT_DEREF_FLAG;
490   }
491 
492   // Copy:
493   KOKKOS_FORCEINLINE_FUNCTION
~SharedAllocationTracker()494   ~SharedAllocationTracker(){KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT}
495 
SharedAllocationTracker()496   KOKKOS_FORCEINLINE_FUNCTION constexpr SharedAllocationTracker()
497       : m_record_bits(DO_NOT_DEREF_FLAG) {}
498 
499   // Move:
500 
501   KOKKOS_FORCEINLINE_FUNCTION
SharedAllocationTracker(SharedAllocationTracker && rhs)502   SharedAllocationTracker(SharedAllocationTracker&& rhs)
503       : m_record_bits(rhs.m_record_bits) {
504     rhs.m_record_bits = DO_NOT_DEREF_FLAG;
505   }
506 
507   KOKKOS_FORCEINLINE_FUNCTION
operator =(SharedAllocationTracker && rhs)508   SharedAllocationTracker& operator=(SharedAllocationTracker&& rhs) {
509     auto swap_tmp     = m_record_bits;
510     m_record_bits     = rhs.m_record_bits;
511     rhs.m_record_bits = swap_tmp;
512     return *this;
513   }
514 
515   // Copy:
516 
517   KOKKOS_FORCEINLINE_FUNCTION
SharedAllocationTracker(const SharedAllocationTracker & rhs)518   SharedAllocationTracker(const SharedAllocationTracker& rhs)
519       : m_record_bits(KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS(
520             rhs, true)){KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT}
521 
522         /** \brief  Copy construction may disable tracking. */
SharedAllocationTracker(const SharedAllocationTracker & rhs,const bool enable_tracking)523         KOKKOS_FORCEINLINE_FUNCTION SharedAllocationTracker(
524             const SharedAllocationTracker& rhs, const bool enable_tracking)
525       : m_record_bits(KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS(
526             rhs,
527             enable_tracking)){KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT}
528 
529         KOKKOS_FORCEINLINE_FUNCTION SharedAllocationTracker
530         &
operator =(const SharedAllocationTracker & rhs)531         operator=(const SharedAllocationTracker& rhs) {
532     // If this is tracking then must decrement
533     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
534     m_record_bits = KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS(rhs, true);
535     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT
536     return *this;
537   }
538 
539   /*  The following functions (assign_direct and assign_force_disable)
540    *  are the result of deconstructing the
541    *  KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS macro.  This
542    *  allows the caller to do the check for tracking enabled and managed
543    *  apart from the assignement of the record because the tracking
544    *  enabled / managed question may be important for other tasks as well
545    */
546 
547   /** \brief  Copy assignment without the carry bits logic
548    *         This assumes that externally defined tracking is explicitly enabled
549    */
550   KOKKOS_FORCEINLINE_FUNCTION
assign_direct(const SharedAllocationTracker & rhs)551   void assign_direct(const SharedAllocationTracker& rhs) {
552     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
553     m_record_bits = rhs.m_record_bits;
554     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT
555   }
556 
557   /** \brief  Copy assignment without the increment
558    *         we cannot assume that current record is unmanaged
559    *         but with externally defined tracking explicitly disabled
560    *         we can go straight to the do not deref flag     */
561   KOKKOS_FORCEINLINE_FUNCTION
assign_force_disable(const SharedAllocationTracker & rhs)562   void assign_force_disable(const SharedAllocationTracker& rhs) {
563     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
564     m_record_bits = rhs.m_record_bits | DO_NOT_DEREF_FLAG;
565   }
566 
567   // report if record is tracking or not
568   KOKKOS_FORCEINLINE_FUNCTION
tracking_enabled()569   bool tracking_enabled() { return (!(m_record_bits & DO_NOT_DEREF_FLAG)); }
570 
571   /** \brief  Copy assignment may disable tracking */
572   KOKKOS_FORCEINLINE_FUNCTION
assign(const SharedAllocationTracker & rhs,const bool enable_tracking)573   void assign(const SharedAllocationTracker& rhs, const bool enable_tracking) {
574     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
575     m_record_bits =
576         KOKKOS_IMPL_SHARED_ALLOCATION_CARRY_RECORD_BITS(rhs, enable_tracking);
577     KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT
578   }
579 
580 #undef KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_ENABLED
581 #undef KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_INCREMENT
582 #undef KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT
583 };
584 
585 } /* namespace Impl */
586 } /* namespace Kokkos */
587 #endif
588