vecmem 1.30.0
Loading...
Searching...
No Matches
cuda_device_atomic_ref.ipp
1/*
2 * VecMem project, part of the ACTS project (R&D line)
3 *
4 * (c) 2022-2024 CERN for the benefit of the ACTS project
5 *
6 * Mozilla Public License Version 2.0
7 */
8#pragma once
9
10// System include(s).
11#include <cassert>
12
13namespace vecmem {
14namespace cuda {
15
16template <typename T, device_address_space address>
19 : m_ptr(&ref) {}
20
21template <typename T, device_address_space address>
23 const device_atomic_ref& parent)
24 : m_ptr(parent.m_ptr) {}
25
26template <typename T, device_address_space address>
27VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::operator=(
28 value_type data) const -> value_type {
29
30 store(data);
31 return data;
32}
33
34// Only invoke __threadfence() during device code compilation. Without this,
35// nvcc gets upset about calling this **device only** function from a function
36// labeled HOST_AND_DEVICE. Allow an outside source to set the macros, so that
37// vecmem::hip::device_atomic_ref could have its own logic for setting them up
38// correctly.
39#ifndef __VECMEM_THREADFENCE_GLOBAL
40#ifdef __CUDA_ARCH__
41#define __VECMEM_THREADFENCE_GLOBAL() __threadfence()
42#else
43#define __VECMEM_THREADFENCE_GLOBAL()
44#endif // defined(__CUDA_ARCH__)
45#endif // not defined(__VECMEM_THREADFENCE_GLOBAL)
46#ifndef __VECMEM_THREADFENCE_LOCAL
47#ifdef __CUDA_ARCH__
48#define __VECMEM_THREADFENCE_LOCAL() __threadfence_block()
49#else
50#define __VECMEM_THREADFENCE_LOCAL()
51#endif // defined(__CUDA_ARCH__)
52#endif // not defined(__VECMEM_THREADFENCE_LOCAL)
53
54namespace details {
55template <device_address_space address>
57
58template <>
60 VECMEM_HOST_AND_DEVICE void operator()() const {
61 __VECMEM_THREADFENCE_GLOBAL();
62 }
63};
64
65template <>
67 VECMEM_HOST_AND_DEVICE void operator()() const {
68 __VECMEM_THREADFENCE_LOCAL();
69 }
70};
71} // namespace details
72
73template <typename T, device_address_space address>
74VECMEM_HOST_AND_DEVICE void device_atomic_ref<T, address>::store(
75 value_type data, memory_order) const {
76
77 volatile_pointer addr = m_ptr;
79 *addr = data;
80}
81
82template <typename T, device_address_space address>
83VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::load(
84 memory_order) const -> value_type {
85
86 volatile_pointer addr = m_ptr;
88 const value_type value = *addr;
90 return value;
91}
92
93#undef __VECMEM_THREADFENCE_GLOBAL
94#undef __VECMEM_THREADFENCE_LOCAL
95
96template <typename T, device_address_space address>
97VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::exchange(
98 value_type data, memory_order) const -> value_type {
99
100 return atomicExch(m_ptr, data);
101}
102
103template <typename T, device_address_space address>
104VECMEM_HOST_AND_DEVICE bool
107
108 if (order == memory_order::acq_rel) {
109 return compare_exchange_strong(expected, desired, order,
110 memory_order::acquire);
111 } else if (order == memory_order::release) {
112 return compare_exchange_strong(expected, desired, order,
113 memory_order::relaxed);
114 } else {
115 return compare_exchange_strong(expected, desired, order, order);
116 }
117}
118
119template <typename T, device_address_space address>
120VECMEM_HOST_AND_DEVICE bool
123 memory_order failure) const {
124
125 (void)failure;
126 assert(failure != memory_order::release &&
127 failure != memory_order::acq_rel);
128
129 const value_type r = atomicCAS(m_ptr, expected, desired);
130 // atomicCAS returns the old value, so the change will have succeeded if
131 // the old value was the expected value.
132 if (r == expected) {
133 return true;
134 } else {
135 expected = r;
136 return false;
137 }
138}
139
140template <typename T, device_address_space address>
142 value_type data, memory_order) const -> value_type {
143
144 return atomicAdd(m_ptr, data);
145}
146
147template <typename T, device_address_space address>
149 value_type data, memory_order) const -> value_type {
150
151 return atomicSub(m_ptr, data);
152}
153
154template <typename T, device_address_space address>
156 value_type data, memory_order) const -> value_type {
157
158 return atomicAnd(m_ptr, data);
159}
160
161template <typename T, device_address_space address>
162VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::fetch_or(
163 value_type data, memory_order) const -> value_type {
164
165 return atomicOr(m_ptr, data);
166}
167
168template <typename T, device_address_space address>
170 value_type data, memory_order) const -> value_type {
171
172 return atomicXor(m_ptr, data);
173}
174
175template <typename T, device_address_space address>
176VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::fetch_max(
177 value_type data, memory_order) const -> value_type {
178
179 return atomicMax(m_ptr, data);
180}
181
182template <typename T, device_address_space address>
183VECMEM_HOST_AND_DEVICE auto device_atomic_ref<T, address>::fetch_min(
184 value_type data, memory_order) const -> value_type {
185
186 return atomicMin(m_ptr, data);
187}
188
189} // namespace cuda
190} // namespace vecmem
An allocator class that wraps a memory resource.
Definition allocator.hpp:37
Custom implementation for atomic operations in CUDA device code.
Definition cuda_device_atomic_ref.hpp:34
T value_type
Type managed by the object.
Definition cuda_device_atomic_ref.hpp:41
std::add_lvalue_reference_t< value_type > reference
Reference to a value given by the user.
Definition cuda_device_atomic_ref.hpp:50
std::add_pointer_t< std::add_volatile_t< value_type > > volatile_pointer
Volatile pointer to the value in global/local memory.
Definition cuda_device_atomic_ref.hpp:48
Main namespace for the vecmem classes/functions.
Definition atomic_ref.hpp:16
device_address_space
Custom definition for the device memory adress space.
Definition device_address_space.hpp:12
memory_order
Custom (dummy) definition for the memory order.
Definition memory_order.hpp:31
Definition cuda_device_atomic_ref.ipp:56