Skip to content

Commit 2bc62ed

Browse files
committed
Fix atomic CAS functionality in CUDA
Currently, the functionality is `compare_exchange_strong` is broken because it relies on the CUDA `atomicCAS` builtin which functions fundamentally differently from the C++ STL version of the equivalent code. Indeed, the C++ version returns true on a succesful swap and false otherwise. The CUDA version always returns the old value. As such, if the old value is false-like, e.g. 0, the `compare_exchange_strong` function will always appear to fail, even if it succeeded. This commit fixes the above issue. Also increases the robustness of other atomic operations, adds new concepts, and adds new tests.
1 parent 70801ff commit 2bc62ed

File tree

7 files changed

+542
-60
lines changed

7 files changed

+542
-60
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* VecMem project, part of the ACTS project (R&D line)
3+
*
4+
* (c) 2022-2023 CERN for the benefit of the ACTS project
5+
*
6+
* Mozilla Public License Version 2.0
7+
*/
8+
#pragma once
9+
10+
#if __cpp_concepts >= 201907L
11+
#include <concepts>
12+
13+
#include "vecmem/memory/device_atomic_ref.hpp"
14+
#endif
15+
16+
namespace vecmem::concepts {
17+
#if __cpp_concepts >= 201907L
18+
/*
19+
* Concept to verify that a type functions as an atomic reference.
20+
*/
21+
template <typename T>
22+
concept atomic_ref = requires {
23+
typename T::value_type;
24+
25+
requires requires(const T& r, typename T::value_type v) {
26+
{ r = v }
27+
->std::same_as<typename T::value_type>;
28+
};
29+
30+
requires requires(const T& r, memory_order o) {
31+
{ r.load(o) }
32+
->std::same_as<typename T::value_type>;
33+
};
34+
35+
requires requires(const T& r, typename T::value_type v, memory_order o) {
36+
{ r.store(v, o) }
37+
->std::same_as<void>;
38+
{ r.exchange(v, o) }
39+
->std::same_as<typename T::value_type>;
40+
{ r.fetch_add(v, o) }
41+
->std::same_as<typename T::value_type>;
42+
{ r.fetch_sub(v, o) }
43+
->std::same_as<typename T::value_type>;
44+
{ r.fetch_and(v, o) }
45+
->std::same_as<typename T::value_type>;
46+
{ r.fetch_or(v, o) }
47+
->std::same_as<typename T::value_type>;
48+
{ r.fetch_xor(v, o) }
49+
->std::same_as<typename T::value_type>;
50+
};
51+
52+
requires requires(const T& r, typename T::value_type& e,
53+
typename T::value_type d, memory_order o1,
54+
memory_order o2) {
55+
{ r.compare_exchange_strong(e, d, o1, o2) }
56+
->std::same_as<bool>;
57+
{ r.compare_exchange_strong(e, d, o1) }
58+
->std::same_as<bool>;
59+
};
60+
};
61+
#endif
62+
} // namespace vecmem::concepts

core/include/vecmem/memory/device_atomic_ref.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,17 @@ class device_atomic_ref {
213213
// Include the implementation.
214214
#include "vecmem/memory/impl/device_atomic_ref.ipp"
215215

216+
#if __cpp_concepts >= 201907L
217+
#include "vecmem/concepts/atomic_ref.hpp"
218+
static_assert(
219+
vecmem::concepts::atomic_ref<vecmem::device_atomic_ref<uint32_t> >,
220+
"Atomic reference on uint32_t is incompletely defined.");
221+
static_assert(
222+
vecmem::concepts::atomic_ref<vecmem::device_atomic_ref<uint64_t> >,
223+
"Atomic reference on uint64_t is incompletely defined.");
224+
static_assert(
225+
vecmem::concepts::atomic_ref<vecmem::device_atomic_ref<std::size_t> >,
226+
"Atomic reference on std::size_t is incompletely defined.");
227+
#endif
228+
216229
#endif // Platform selection

0 commit comments

Comments
 (0)