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

Commit 2d72042

Browse files
authored
[SYCL][ESIMD] Add tests for accessor-based gather/scatter and scalar access. (#43)
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent c1d0c1c commit 2d72042

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//==------- accessor_gather_scatter.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+
// TODO enable on Windows
9+
// REQUIRES: linux && gpu && opencl
10+
// RUN: %clangxx-esimd -fsycl %s -o %t.out
11+
// RUN: %ESIMD_RUN_PLACEHOLDER %t.out
12+
//
13+
// The test checks functionality of the gather/scatter accessor-based ESIMD
14+
// intrinsics.
15+
16+
#include "esimd_test_utils.hpp"
17+
18+
#include <CL/sycl.hpp>
19+
#include <CL/sycl/INTEL/esimd.hpp>
20+
#include <iostream>
21+
22+
using namespace cl::sycl;
23+
24+
template <typename T>
25+
using Acc =
26+
accessor<T, 1, access_mode::read_write, access::target::global_buffer>;
27+
28+
#define MASKED_LANE_NUM_REV 1
29+
30+
template <typename T, unsigned VL, unsigned STRIDE> struct Kernel {
31+
Acc<T> acc;
32+
Kernel(Acc<T> acc) : acc(acc) {}
33+
34+
void operator()(id<1> i) const SYCL_ESIMD_KERNEL {
35+
using namespace sycl::INTEL::gpu;
36+
uint32_t ii = static_cast<uint32_t>(i.get(0));
37+
// every STRIDE threads (subgroups with sg_size=1) access contiguous block
38+
// of STRIDE*VL elements
39+
uint32_t global_offset = (ii / STRIDE) * VL * STRIDE + ii % STRIDE;
40+
simd<uint32_t, VL> offsets(0, STRIDE);
41+
simd<T, VL> v = gather<T, VL>(acc, offsets, global_offset);
42+
v += ii;
43+
simd<uint16_t, VL> pred = 1;
44+
pred.template select<1, 1>(VL - MASKED_LANE_NUM_REV) =
45+
0; // mask out the last lane
46+
scatter<T, VL>(acc, v, offsets, global_offset, pred);
47+
}
48+
};
49+
50+
template <typename T, unsigned VL, unsigned STRIDE> bool test(queue q) {
51+
size_t size = VL * STRIDE * 117;
52+
53+
std::cout << "Testing T=" << typeid(T).name() << " VL=" << VL
54+
<< " STRIDE=" << STRIDE << "...\n";
55+
T *A = new T[size];
56+
57+
for (unsigned i = 0; i < size; ++i) {
58+
A[i] = (T)i;
59+
}
60+
61+
{
62+
buffer<T, 1> buf(A, range<1>(size));
63+
range<1> glob_range{size / VL};
64+
65+
auto e = q.submit([&](handler &cgh) {
66+
auto acc = buf.template get_access<access::mode::read_write>(cgh);
67+
Kernel<T, VL, STRIDE> kernel(acc);
68+
cgh.parallel_for(glob_range, kernel);
69+
});
70+
}
71+
72+
int err_cnt = 0;
73+
74+
for (unsigned i = 0; i < size; ++i) {
75+
T gold = (T)i;
76+
// the sequential number of sub group block (STRIDE in each) i falls into
77+
unsigned sg_block_num = i / (VL * STRIDE);
78+
// the start of the i index block this sg block covers
79+
unsigned sg_block_start_i = sg_block_num * VL * STRIDE;
80+
// the local id (within block) of the sg covering this i
81+
unsigned sg_local_id = (i - sg_block_start_i) % STRIDE;
82+
// the global id of the sg covering this i
83+
unsigned sg_global_id = sg_local_id + sg_block_num * STRIDE;
84+
85+
unsigned lane_id = ((i % (VL * STRIDE)) - sg_local_id) / STRIDE;
86+
87+
gold += lane_id == VL - MASKED_LANE_NUM_REV ? 0 : sg_global_id;
88+
89+
if (A[i] != gold) {
90+
if (++err_cnt < 35) {
91+
std::cout << "failed at index " << i << ": " << A[i] << " != " << gold
92+
<< " (gold)\n";
93+
}
94+
}
95+
}
96+
if (err_cnt > 0) {
97+
std::cout << " pass rate: "
98+
<< ((float)(size - err_cnt) / (float)size) * 100.0f << "% ("
99+
<< (size - err_cnt) << "/" << size << ")\n";
100+
}
101+
102+
delete[] A;
103+
104+
std::cout << (err_cnt > 0 ? " FAILED\n" : " Passed\n");
105+
return err_cnt > 0 ? false : true;
106+
}
107+
108+
int main(void) {
109+
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
110+
111+
auto dev = q.get_device();
112+
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";
113+
114+
bool passed = true;
115+
passed &= test<char, 8, 1>(q);
116+
passed &= test<char, 16, 3>(q);
117+
passed &= test<short, 8, 8>(q);
118+
passed &= test<short, 16, 1>(q);
119+
passed &= test<int, 8, 2>(q);
120+
passed &= test<int, 16, 1>(q);
121+
passed &= test<float, 8, 2>(q);
122+
passed &= test<float, 16, 1>(q);
123+
return passed ? 0 : 1;
124+
}

SYCL/ESIMD/accessor_load_store.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//==------- accessor_load_store.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+
// TODO enable on Windows
9+
// REQUIRES: linux && gpu && opencl
10+
// RUN: %clangxx-esimd -fsycl %s -o %t.out
11+
// RUN: %ESIMD_RUN_PLACEHOLDER %t.out
12+
//
13+
// The test checks functionality of the scalar load/store accessor-based ESIMD
14+
// intrinsics.
15+
16+
#include "esimd_test_utils.hpp"
17+
18+
#include <CL/sycl.hpp>
19+
#include <CL/sycl/INTEL/esimd.hpp>
20+
#include <iostream>
21+
22+
using namespace cl::sycl;
23+
24+
template <typename T>
25+
using Acc =
26+
accessor<T, 1, access_mode::read_write, access::target::global_buffer>;
27+
28+
template <typename T> struct Kernel {
29+
Acc<T> acc;
30+
Kernel(Acc<T> acc) : acc(acc) {}
31+
32+
void operator()(id<1> i) const SYCL_ESIMD_KERNEL {
33+
using namespace sycl::INTEL::gpu;
34+
uint32_t ii = static_cast<uint32_t>(i.get(0));
35+
T v = scalar_load<T>(acc, ii);
36+
v += ii;
37+
scalar_store<T>(acc, ii, v);
38+
}
39+
};
40+
41+
template <typename T> struct char_to_int {
42+
using type = typename std::conditional<
43+
sizeof(T) == 1,
44+
typename std::conditional<std::is_signed<T>::value, int, unsigned>::type,
45+
T>::type;
46+
};
47+
48+
template <typename T> bool test(queue q, size_t size) {
49+
std::cout << "Testing T=" << typeid(T).name() << "...\n";
50+
T *A = new T[size];
51+
52+
for (unsigned i = 0; i < size; ++i) {
53+
A[i] = (T)i;
54+
}
55+
56+
{
57+
buffer<T, 1> buf(A, range<1>(size));
58+
range<1> glob_range{size};
59+
60+
auto e = q.submit([&](handler &cgh) {
61+
auto acc = buf.template get_access<access::mode::read_write>(cgh);
62+
Kernel<T> kernel(acc);
63+
cgh.parallel_for(glob_range, kernel);
64+
});
65+
}
66+
67+
int err_cnt = 0;
68+
69+
for (unsigned i = 0; i < size; ++i) {
70+
T gold = (T)i + (T)i;
71+
72+
if (A[i] != gold) {
73+
if (++err_cnt < 10) {
74+
using T1 = typename char_to_int<T>::type;
75+
std::cout << "failed at index " << i << ": " << (T1)A[i]
76+
<< " != " << (T1)gold << " (gold)\n";
77+
}
78+
}
79+
}
80+
if (err_cnt > 0) {
81+
std::cout << " pass rate: "
82+
<< ((float)(size - err_cnt) / (float)size) * 100.0f << "% ("
83+
<< (size - err_cnt) << "/" << size << ")\n";
84+
}
85+
86+
delete[] A;
87+
88+
std::cout << (err_cnt > 0 ? " FAILED\n" : " Passed\n");
89+
return err_cnt > 0 ? false : true;
90+
}
91+
92+
int main(int argc, char **argv) {
93+
// TODO the test fails with 1- and 2-byte types when size is not multiple
94+
// of 4. Supposed reason - wrapping the memory buffer into image1d_buffer
95+
size_t size = 128; // 117 - fails for char and short
96+
97+
if (argc > 1) {
98+
size = atoi(argv[1]);
99+
size = size == 0 ? 128 : size;
100+
}
101+
std::cout << "Using size=" << size << "\n";
102+
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
103+
104+
auto dev = q.get_device();
105+
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";
106+
107+
bool passed = true;
108+
passed &= test<char>(q, size);
109+
passed &= test<unsigned char>(q, size);
110+
passed &= test<short>(q, size);
111+
passed &= test<unsigned short>(q, size);
112+
passed &= test<int>(q, size);
113+
passed &= test<unsigned int>(q, size);
114+
passed &= test<float>(q, size);
115+
return passed ? 0 : 1;
116+
}

0 commit comments

Comments
 (0)