Skip to content

Commit 84dc8d3

Browse files
authored
[SYCL] Add tests for atomic_fence_capabilities. (#8853)
Adds E2E tests for `sycl::info::device::atomic_fence_order_capabilities` and `sycl::info::device::atomic_fence_scope_capabilities`. --------- Signed-off-by: Maronas, Marcos <[email protected]>
1 parent 589618e commit 84dc8d3

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out
2+
// RUN: %CPU_RUN_PLACEHOLDER %t.out
3+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
4+
// RUN: %ACC_RUN_PLACEHOLDER %t.out
5+
6+
// NOTE: General tests for atomic fence capabilities.
7+
8+
#include <algorithm>
9+
#include <cassert>
10+
#include <iostream>
11+
#include <sycl/sycl.hpp>
12+
13+
using namespace sycl;
14+
15+
bool is_supported_order(const std::vector<memory_order> &capabilities,
16+
memory_order mem_order) {
17+
return std::find(capabilities.begin(), capabilities.end(), mem_order) !=
18+
capabilities.end();
19+
}
20+
21+
bool is_supported_scope(const std::vector<memory_scope> &capabilities,
22+
memory_scope mem_scope) {
23+
return std::find(capabilities.begin(), capabilities.end(), mem_scope) !=
24+
capabilities.end();
25+
}
26+
27+
void checkFenceBehaviour(memory_order order, memory_scope scope) {
28+
auto q = queue();
29+
// Both read and write being release or acquire is wrong. In case order is
30+
// release or acquire we need read to be acquire and write to be release.
31+
// If we flip both acquire and release, we will be checking the same case
32+
// (read == acquire, write == release) twice, so we just skip one case and
33+
// flip for the other.
34+
if (order == memory_order::acquire)
35+
return;
36+
memory_order order_read = order;
37+
memory_order order_write = order;
38+
if (order == memory_order::release) {
39+
order_read = memory_order::acquire;
40+
}
41+
42+
// Count of retries in the check cycle
43+
constexpr size_t RETRY_COUNT = 256;
44+
constexpr int expected_val = 42;
45+
46+
bool res = true;
47+
int sync = 0;
48+
int data = 0;
49+
int value = expected_val;
50+
51+
// These global_range and local_range values provide a check in one group
52+
// when test_type = single_group, and between four groups when
53+
// test_type = between_groups
54+
range<1> global_range(2);
55+
range<1> local_range(2);
56+
57+
{
58+
buffer<bool> res_buf(&res, range<1>(1));
59+
buffer<int> sync_buffer(&sync, range<1>(1));
60+
buffer<int> data_buffer(&data, range<1>(1));
61+
q.submit([&](handler &cgh) {
62+
auto res_acc = res_buf.template get_access<access_mode::write>(cgh);
63+
auto sync_flag_acc =
64+
sync_buffer.template get_access<sycl::access_mode::read_write>(cgh);
65+
auto data_acc =
66+
data_buffer.template get_access<sycl::access_mode::read_write>(cgh);
67+
cgh.parallel_for(
68+
nd_range<1>(global_range, local_range), [=](nd_item<1> nditem) {
69+
atomic_ref<int, memory_order::relaxed, memory_scope::work_group>
70+
sync_flag(sync_flag_acc[0]);
71+
int *data = &data_acc[0];
72+
// Only one nditem should perform non-atomic write.
73+
// All other nditems should perform non-atomic
74+
// reads
75+
if (nditem.get_global_linear_id() == 0) {
76+
// Non-atomic write to data
77+
*data = value;
78+
// Used atomic_fence to guarantee the order
79+
// instructions execution
80+
atomic_fence(order_write, scope);
81+
// Used atomic sync flag to avoid data racing
82+
sync_flag = 1;
83+
} else {
84+
bool write_happened = false;
85+
for (size_t i = 0; i < RETRY_COUNT; i++) {
86+
if (sync_flag == 1) {
87+
write_happened = true;
88+
break;
89+
}
90+
}
91+
atomic_fence(order_read, scope);
92+
// After the fence safe non-atomic reading
93+
if (write_happened) {
94+
// Non-atomic read of data
95+
if (*data != value)
96+
res_acc[0] = false;
97+
}
98+
}
99+
});
100+
});
101+
}
102+
assert(res);
103+
}
104+
105+
int main() {
106+
queue q;
107+
108+
std::vector<memory_order> supported_memory_orders =
109+
q.get_device().get_info<info::device::atomic_fence_order_capabilities>();
110+
111+
// Relaxed, acquire, release and acq_rel memory order must be supported.
112+
assert(is_supported_order(supported_memory_orders, memory_order::relaxed));
113+
assert(is_supported_order(supported_memory_orders, memory_order::acquire));
114+
assert(is_supported_order(supported_memory_orders, memory_order::release));
115+
assert(is_supported_order(supported_memory_orders, memory_order::acq_rel));
116+
117+
std::vector<memory_scope> supported_memory_scopes =
118+
q.get_device().get_info<info::device::atomic_fence_scope_capabilities>();
119+
120+
// Work_group, sub_group and work_item memory order must be supported.
121+
assert(is_supported_scope(supported_memory_scopes, memory_scope::work_item));
122+
assert(is_supported_scope(supported_memory_scopes, memory_scope::sub_group));
123+
assert(is_supported_scope(supported_memory_scopes, memory_scope::work_group));
124+
125+
for (auto order : supported_memory_orders)
126+
for (auto scope : supported_memory_scopes)
127+
checkFenceBehaviour(order, scope);
128+
129+
std::cout << "Test passed." << std::endl;
130+
}

0 commit comments

Comments
 (0)