Cuda battery library
Loading...
Searching...
No Matches
memory.hpp
Go to the documentation of this file.
1// Copyright 2022 Pierre Talbot
2
3#ifndef CUDA_BATTERY_MEMORY_HPP
4#define CUDA_BATTERY_MEMORY_HPP
5
6/** \file memory.hpp
7 * An abstraction of memory load and store useful to write a single version of an algorithm working either sequentially or in parallel, and on CPU or GPU.
8 * Note that these classes are mainly designed to work with a relaxed memory ordering; we are unsure of their applicability to other kinds of memory ordering.
9 */
10
11#include <cassert>
12#include <type_traits>
13#include <utility>
14
15#ifdef __CUDACC__
16 #include <cuda/atomic>
17#else
18 #include <atomic>
19#endif
20
21#include "utility.hpp"
22
23namespace battery {
24
25template <class A>
26class copyable_atomic: public A {
27public:
28 copyable_atomic() = default;
29 CUDA copyable_atomic(typename A::value_type x): A(x) {}
30 copyable_atomic(const copyable_atomic& other): A(other.load()) {}
31 copyable_atomic(copyable_atomic&& other): A(other.load()) {}
33 this->store(other.load());
34 return *this;
35 }
37 this->store(other.load());
38 return *this;
39 }
40};
41
42/** Represent the memory of a variable that cannot be accessed by multiple threads. */
43template <bool read_only>
44class memory {
45public:
46 template <class T> using atomic_type = T;
47
48 /** Indicate this memory is written by a single thread. */
49 constexpr static const bool sequential = true;
50
51public:
52 template <class T>
53 CUDA INLINE static constexpr T load(const atomic_type<T>& a) {
54 return a;
55 }
56
57 template <class T>
58 CUDA INLINE static constexpr std::enable_if_t<!read_only, void> store(atomic_type<T>& a, T v) {
59 a = v;
60 }
61
62 template <class T>
63 CUDA INLINE static constexpr std::enable_if_t<!read_only, T> exchange(atomic_type<T>& a, T v) {
64 return std::exchange(a, std::move(v));
65 }
66};
67
70
71#ifdef __CUDACC__
72
73/** Memory load and store operations relative to a cuda scope (per-thread, block, grid, ...) and given a certain memory order (by default relaxed). */
74template <cuda::thread_scope scope, cuda::memory_order mem_order = cuda::memory_order_relaxed>
75class atomic_memory_scoped {
76public:
77 template <class T> using atomic_type = copyable_atomic<cuda::atomic<T, scope>>;
78 constexpr static const bool sequential = false;
79
80 template <class T>
81 CUDA INLINE static T load(const atomic_type<T>& a) {
82 return a.load(mem_order);
83 }
84
85 template <class T>
86 CUDA INLINE static void store(atomic_type<T>& a, T v) {
87 a.store(v, mem_order);
88 }
89
90 template <class T>
91 CUDA INLINE static T exchange(atomic_type<T>& a, T v) {
92 return a.exchange(v, mem_order);
93 }
94};
95
96using atomic_memory_block = atomic_memory_scoped<cuda::thread_scope_block>;
97using atomic_memory_grid = atomic_memory_scoped<cuda::thread_scope_device>;
98using atomic_memory_multi_grid = atomic_memory_scoped<cuda::thread_scope_system>;
99
100#endif // __CUDACC__
101
102#ifdef __CUDACC__
103 /// @private
104 namespace impl {
105 template <class T>
106 using atomic_t = cuda::std::atomic<T>;
107 }
108 /// @private
109 using memory_order = cuda::std::memory_order;
110 /// @private
111 constexpr memory_order memory_order_relaxed = cuda::std::memory_order_relaxed;
112 /// @private
113 constexpr memory_order memory_order_seq_cst = cuda::std::memory_order_seq_cst;
114#else
115 /// @private
116 namespace impl {
117 template <class T>
118 using atomic_t = std::atomic<T>;
119 }
120 /// @private
121 using memory_order = std::memory_order;
122 /// @private
123 constexpr memory_order memory_order_relaxed = std::memory_order_relaxed;
124 /// @private
125 constexpr memory_order memory_order_seq_cst = std::memory_order_seq_cst;
126#endif
127
128/** Use the standard C++ atomic type, either provided by libcudacxx if we compile with a CUDA compiler, or through the STL otherwise. */
129template <memory_order mem_order = memory_order_relaxed>
131public:
133 constexpr static const bool sequential = false;
134
135 template <class T>
136 CUDA INLINE static T load(const atomic_type<T>& a) {
137 return a.load(mem_order);
138 }
139
140 template <class T>
141 CUDA INLINE static void store(atomic_type<T>& a, T v) {
142 a.store(v, mem_order);
143 }
144
145 template <class T>
146 CUDA INLINE static T exchange(atomic_type<T>& a, T v) {
147 return a.exchange(v, mem_order);
148 }
149};
150
151}
152
153#endif
Definition memory.hpp:130
CUDA static INLINE void store(atomic_type< T > &a, T v)
Definition memory.hpp:141
CUDA static INLINE T load(const atomic_type< T > &a)
Definition memory.hpp:136
static constexpr const bool sequential
Definition memory.hpp:133
CUDA static INLINE T exchange(atomic_type< T > &a, T v)
Definition memory.hpp:146
Definition memory.hpp:26
copyable_atomic(copyable_atomic &&other)
Definition memory.hpp:31
copyable_atomic(const copyable_atomic &other)
Definition memory.hpp:30
copyable_atomic & operator=(copyable_atomic &&other)
Definition memory.hpp:36
copyable_atomic & operator=(const copyable_atomic &other)
Definition memory.hpp:32
CUDA copyable_atomic(typename A::value_type x)
Definition memory.hpp:29
Definition memory.hpp:44
CUDA static INLINE constexpr T load(const atomic_type< T > &a)
Definition memory.hpp:53
static constexpr const bool sequential
Definition memory.hpp:49
T atomic_type
Definition memory.hpp:46
CUDA static INLINE constexpr std::enable_if_t<!read_only, void > store(atomic_type< T > &a, T v)
Definition memory.hpp:58
CUDA static INLINE constexpr std::enable_if_t<!read_only, T > exchange(atomic_type< T > &a, T v)
Definition memory.hpp:63
Definition algorithm.hpp:10
#define INLINE
Definition utility.hpp:63
#define CUDA
Definition utility.hpp:59