Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Commit 5ed4bac

Browse files
authored
[ESIMD] Add gather/scatter_rgba smoke test, can be used as an example. (#835)
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent 15dd222 commit 5ed4bac

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

SYCL/ESIMD/api/esimd_rgba_smoke.cpp

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
//==---------------- esimd_rgba_smoke.cpp - DPC++ ESIMD on-device test ----==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// REQUIRES: gpu
9+
// UNSUPPORTED: cuda || hip
10+
// RUN: %clangxx -fsycl %s -o %t.out
11+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
12+
13+
// Smoke test for scatter/gather also illustrating correct use of these APIs
14+
15+
#include "../esimd_test_utils.hpp"
16+
17+
#include <CL/sycl.hpp>
18+
#include <sycl/ext/intel/experimental/esimd.hpp>
19+
20+
#include <iostream>
21+
22+
using namespace cl::sycl;
23+
using namespace sycl::ext::intel::experimental::esimd;
24+
25+
static constexpr unsigned NAllChs =
26+
get_num_channels_enabled(rgba_channel_mask::ABGR);
27+
28+
template <class T> void print_ch(T *ch) {
29+
unsigned int v = (unsigned int)(*ch);
30+
std::cout << (char)(v >> 16) << (v & 0xFF);
31+
}
32+
33+
template <class T> void print_pixels(const char *title, T *p0, int N) {
34+
35+
std::cout << title << ": ";
36+
for (unsigned i = 0; i < N; ++i) {
37+
T *p = p0 + i * NAllChs;
38+
39+
std::cout << "{";
40+
for (unsigned ch = 0; ch < NAllChs; ++ch) {
41+
print_ch(p + ch);
42+
43+
if (ch < NAllChs - 1) {
44+
std::cout << ",";
45+
}
46+
}
47+
std::cout << "}";
48+
std::cout << " ";
49+
}
50+
std::cout << "\n";
51+
}
52+
53+
void print_mask(rgba_channel_mask m) {
54+
const char ch_names[] = {'R', 'G', 'B', 'A'};
55+
const rgba_channel ch_vals[] = {rgba_channel::R, rgba_channel::G,
56+
rgba_channel::B, rgba_channel::A};
57+
58+
for (int ch = 0; ch < sizeof(ch_names) / sizeof(ch_names[0]); ++ch) {
59+
if (is_channel_enabled(m, ch_vals[ch])) {
60+
std::cout << ch_names[ch];
61+
}
62+
}
63+
}
64+
65+
template <class, int, int> class TestID;
66+
67+
template <rgba_channel_mask ChMask, unsigned NPixels, class T>
68+
bool test_impl(queue q) {
69+
constexpr unsigned NOnChs = get_num_channels_enabled(ChMask);
70+
unsigned SizeIn = NPixels * NAllChs;
71+
unsigned SizeOut = NPixels * NOnChs;
72+
73+
std::cout << "Testing mask=";
74+
print_mask(ChMask);
75+
std::cout << ", T=" << typeid(T).name() << ", NPixels=" << NPixels << "\n";
76+
77+
T *A = malloc_shared<T>(SizeIn, q);
78+
T *B = malloc_shared<T>(SizeOut, q);
79+
T *C = malloc_shared<T>(SizeOut, q);
80+
81+
for (unsigned p = 0; p < NPixels; ++p) {
82+
char ch_names[] = {'R', 'G', 'B', 'A'};
83+
84+
for (int ch = 0; ch < sizeof(ch_names) / sizeof(ch_names[0]); ++ch) {
85+
A[p * NAllChs + ch] =
86+
(ch_names[ch] << 16) | p; // R0 G0 B0 A0 R1 G1 B1 ...
87+
B[p * NAllChs + ch] = 0;
88+
C[p * NAllChs + ch] = 0;
89+
}
90+
}
91+
try {
92+
auto e = q.submit([&](handler &cgh) {
93+
cgh.single_task<TestID<T, NPixels, static_cast<int>(ChMask)>>(
94+
[=]() SYCL_ESIMD_KERNEL {
95+
constexpr unsigned NElems = NPixels * NOnChs;
96+
simd<T, NPixels> offsets(0, sizeof(T) * NAllChs);
97+
simd<T, NElems> p = gather_rgba<T, NPixels, ChMask>(A, offsets);
98+
// simply scatter back to B - should give same results as A in
99+
// enabled channels, the rest should remain zero:
100+
scatter_rgba<T, NPixels, ChMask>(B, offsets, p);
101+
// copy instead of scattering to C - thus getting AOS to SOA layout
102+
// layout conversion:
103+
// R0 R1 ... G0 G1 ... B0 B1 ... A0 A1 ...
104+
// or, if say R and B are disables (rgba_channel_mask::AG is used):
105+
// G0 G1 ... A0 A1 ... 0 0 0 ...
106+
p.copy_to(C);
107+
});
108+
});
109+
e.wait();
110+
} catch (sycl::exception const &e) {
111+
std::cout << "SYCL exception caught: " << e.what() << '\n';
112+
free(A, q);
113+
free(B, q);
114+
free(C, q);
115+
return 1;
116+
}
117+
print_pixels(" A", A, NPixels);
118+
print_pixels(" B", B, NPixels);
119+
print_pixels(" C", C, NPixels);
120+
int err_cnt = 0;
121+
122+
// Total count of A's enabled channels iterated through at given moment
123+
unsigned on_ch_cnt_all = 0;
124+
125+
// clang-format off
126+
//Testing mask=RA, T=unsigned int, NPixels=8
127+
// A: {R0,G0,B0,A0} {R1,G1,B1,A1} {R2,G2,B2,A2} {R3,G3,B3,A3} {R4,G4,B4,A4} {R5,G5,B5,A5} {R6,G6,B6,A6} {R7,G7,B7,A7}
128+
// B: {R0, 0, 0,A0} {R1, 0, 0,A1} {R2, 0, 0,A2} {R3, 0, 0,A3} {R4, 0, 0,A4} {R5, 0, 0,A5} {R6, 0, 0,A6} {R7, 0, 0,A7}
129+
// C: {R0,R1,R2,R3} {R4,R5,R6,R7} {A0,A1,A2,A3} {A4,A5,A6,A7} { 0, 0, 0, 0} { 0, 0, 0, 0} { 0, 0, 0, 0} { 0, 0, 0, 0}
130+
// clang-format on
131+
132+
for (unsigned p = 0; p < NPixels; ++p) {
133+
const char ch_names[] = {'R', 'G', 'B', 'A'};
134+
const rgba_channel ch_vals[] = {rgba_channel::R, rgba_channel::G,
135+
rgba_channel::B, rgba_channel::A};
136+
// Counts enabled channels in current A's pixel
137+
unsigned ch_on_cnt = 0;
138+
139+
for (int ch = 0; ch < sizeof(ch_names) / sizeof(ch_names[0]); ++ch) {
140+
unsigned ch_off = p * NAllChs + ch;
141+
142+
// check C
143+
// Are we past the payload in C and at the trailing 0 area?
144+
bool c_done = on_ch_cnt_all >= NPixels * NOnChs;
145+
146+
if (c_done) {
147+
if ((T)0 != C[ch_off]) {
148+
++err_cnt;
149+
std::cout << " error in C: non-zero at pixel=" << p
150+
<< " channel=" << ch_names[ch] << "\n";
151+
}
152+
}
153+
if (is_channel_enabled(ChMask, ch_vals[ch])) {
154+
// check B
155+
if (A[ch_off] != B[ch_off]) {
156+
++err_cnt;
157+
std::cout << " error in B at pixel=" << p
158+
<< " channel=" << ch_names[ch] << ": ";
159+
print_ch(B + ch_off);
160+
std::cout << " != ";
161+
print_ch(A + ch_off);
162+
std::cout << " (gold)\n";
163+
}
164+
// check C
165+
on_ch_cnt_all++;
166+
unsigned ch_off_c = NPixels * ch_on_cnt + p;
167+
ch_on_cnt++;
168+
if (A[ch_off] != C[ch_off_c]) {
169+
++err_cnt;
170+
std::cout << " error in C at pixel=" << p
171+
<< " channel=" << ch_names[ch] << ": ";
172+
print_ch(C + ch_off_c);
173+
std::cout << " != ";
174+
print_ch(A + ch_off);
175+
std::cout << " (gold)\n";
176+
}
177+
} else {
178+
// check B
179+
if ((T)0 != B[ch_off]) {
180+
++err_cnt;
181+
std::cout << " error in B: non-zero at pixel=" << p
182+
<< " channel=" << ch_names[ch] << "\n";
183+
}
184+
}
185+
}
186+
}
187+
188+
free(A, q);
189+
free(B, q);
190+
free(C, q);
191+
std::cout << (err_cnt > 0 ? " FAILED\n" : " Passed\n");
192+
return err_cnt == 0;
193+
}
194+
195+
template <rgba_channel_mask ChMask> bool test(queue q) {
196+
bool passed = true;
197+
passed &= test_impl<ChMask, 8, unsigned int>(q);
198+
passed &= test_impl<ChMask, 16, float>(q);
199+
passed &= test_impl<ChMask, 32, int>(q);
200+
return passed;
201+
}
202+
203+
int main(void) {
204+
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
205+
206+
auto dev = q.get_device();
207+
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";
208+
bool passed = true;
209+
passed &= test<rgba_channel_mask::ABGR>(q);
210+
passed &= test<rgba_channel_mask::AR>(q);
211+
passed &= test<rgba_channel_mask::A>(q);
212+
passed &= test<rgba_channel_mask::R>(q);
213+
passed &= test<rgba_channel_mask::B>(q);
214+
215+
std::cout << (passed ? "Test passed\n" : "Test FAILED\n");
216+
return passed ? 0 : 1;
217+
}

0 commit comments

Comments
 (0)