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