Skip to content

Commit 15a1493

Browse files
kbobrovsbb-sycl
authored andcommitted
[ESIMD] Add smoke test for 2D simd_view_impl::select. (intel#805)
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent 4b29acb commit 15a1493

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//==------- simd_view_select_2d.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 -fsycl-device-code-split=per_kernel -o %t.out
11+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
12+
//
13+
// Smoke test for 2D region select API which can be used to represent 2D tiles.
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;
24+
using namespace sycl::ext::intel::experimental::esimd;
25+
26+
template <typename T> struct char_to_int {
27+
using type = typename std::conditional<
28+
sizeof(T) == 1,
29+
typename std::conditional<std::is_signed<T>::value, int, unsigned>::type,
30+
T>::type;
31+
};
32+
33+
template <class T, int... I> class test_id;
34+
35+
// This function:
36+
// - Creates 3 matrices - A[M x K], B[K x N] and C[M x N].
37+
// - Selects a subregion from each using 2D select:
38+
// tile_a[Wm x Wn], tile_b[Wk x Wn] and tile_c[Wm x Wn].
39+
// When selecting along each dimension - M, N and K -
40+
// offsets off_m, off_n, off_k and strides Sm, Sn and Sk are used.
41+
// - multiplies tile_a x tile_b as matrices and writes result to tile_c.
42+
//
43+
template <
44+
// element type:
45+
class T,
46+
// input/output matrix sizes:
47+
int M, int N, int K,
48+
// input/output matrix region sizes (widths) being multiplied:
49+
// A[Wm x Wk] x B[Wk x Wn] = C[Wm x Wn]
50+
int Wm, int Wn, int Wk,
51+
// strides used to select the regions:
52+
int Sm, int Sn, int Sk>
53+
bool test_impl(queue q, int off_m, int off_n, int off_k) {
54+
assert((off_m + Wm * Sm <= M) && (off_n + Wn * Sn <= N) &&
55+
(off_k + Wk * Sk <= K));
56+
57+
std::cout << "Testing T=" << typeid(T).name() << " [M,N,K]=[" << M << "," << N
58+
<< "," << K << "]"
59+
<< " [Wm,Wn,Wk]=[" << Wm << "," << Wn << "," << Wk << "]"
60+
<< " [Sm,Sn,Sk]=[" << Sm << "," << Sn << "," << Sk << "]"
61+
<< " [off_m,off_n,off_k]=[" << off_m << "," << off_n << "," << off_k
62+
<< "]"
63+
<< "\n";
64+
65+
T *mat_a = sycl::malloc_shared<T>(M * K, q);
66+
T *mat_b = sycl::malloc_shared<T>(K * N, q);
67+
T *mat_c = sycl::malloc_shared<T>(M * N, q);
68+
T *gold = new T[M * N];
69+
70+
for (int a = 0; a < M * K; a++) {
71+
// 1 1 1 ...
72+
// 2 2 2 ...
73+
// . . .
74+
// M M M ...
75+
mat_a[a] = (T)(a / K + 1);
76+
}
77+
for (int b = 0; b < K * N; b++) {
78+
// 1 1 1 ...
79+
// 2 2 2 ...
80+
// . . .
81+
// N N N ...
82+
mat_b[b] = (T)(b / N + 1);
83+
}
84+
for (int c = 0; c < M * N; c++) {
85+
mat_c[c] = (T)1;
86+
gold[c] = (T)1;
87+
}
88+
// Create gold data
89+
for (int m = 0; m < Wm; m++) {
90+
for (int n = 0; n < Wn; n++) {
91+
int ind_c = (off_m + m * Sm) * N + off_n + n * Sn;
92+
T acc = gold[ind_c];
93+
94+
for (int k = 0; k < Wk; k++) {
95+
int ind_a = (off_m + m * Sm) * K + off_k + k * Sk;
96+
int ind_b = (off_k + k * Sk) * N + off_n + n * Sn;
97+
acc += mat_a[ind_a] * mat_b[ind_b];
98+
}
99+
gold[ind_c] = acc;
100+
}
101+
}
102+
103+
try {
104+
auto e = q.submit([&](handler &cgh) {
105+
cgh.single_task<test_id<T, M, N, K, Wm, Wn, Wk, Sm, Sn, Sk>>(
106+
[=]() SYCL_ESIMD_KERNEL {
107+
simd<T, M * K> a(mat_a);
108+
simd<T, K * N> b(mat_b);
109+
simd<T, M * N> c(mat_c);
110+
111+
auto tile_a = a.template bit_cast_view<T, M, K>()
112+
.template select<Wm, Sm, Wk, Sk>(off_m, off_k);
113+
auto tile_b = b.template bit_cast_view<T, K, N>()
114+
.template select<Wk, Sk, Wn, Sn>(off_k, off_n);
115+
auto tile_c = c.template bit_cast_view<T, M, N>()
116+
.template select<Wm, Sm, Wn, Sn>(off_m, off_n);
117+
118+
for (int m = 0; m < Wm; m++) {
119+
for (int n = 0; n < Wn; n++) {
120+
tile_c.template select<1, 1, 1, 1>(m, n) +=
121+
reduce<T>(tile_a.row(m) * tile_b.column(n), std::plus<>{});
122+
}
123+
}
124+
c.copy_to(mat_c);
125+
});
126+
});
127+
e.wait_and_throw();
128+
} catch (cl::sycl::exception const &e) {
129+
std::cout << " SYCL exception caught: " << e.what() << '\n';
130+
sycl::free(mat_a, q);
131+
sycl::free(mat_b, q);
132+
sycl::free(mat_c, q);
133+
delete[] gold;
134+
return false;
135+
}
136+
int err_cnt = 0;
137+
138+
for (int m = 0; m < M; m++) {
139+
for (int n = 0; n < N; n++) {
140+
T gold_val = gold[m * N + n];
141+
T val = mat_c[m * N + n];
142+
using ValT = typename char_to_int<T>::type;
143+
144+
if ((val != gold_val) && (++err_cnt < 20)) {
145+
std::cout << " ERROR at [" << m << "," << n << "]: " << (ValT)val
146+
<< " != " << (ValT)gold_val << "(gold)\n";
147+
}
148+
}
149+
}
150+
if (err_cnt > 0) {
151+
int NN = M * N;
152+
std::cout << " pass rate: " << ((float)(NN - err_cnt) / (float)NN) * 100.0f
153+
<< "% (" << (NN - err_cnt) << "/" << NN << ")\n";
154+
}
155+
std::cout << (err_cnt > 0 ? " FAILED\n" : " Passed\n");
156+
sycl::free(mat_a, q);
157+
sycl::free(mat_b, q);
158+
sycl::free(mat_c, q);
159+
delete[] gold;
160+
return err_cnt > 0 ? false : true;
161+
}
162+
163+
template <class T> bool test(queue q) {
164+
bool passed = true;
165+
passed &= test_impl<T, 8, 8, 8, /**/ 8, 8, 8, /**/ 1, 1, 1>(q, 0, 0, 0);
166+
passed &= test_impl<T, 8, 16, 8, /**/ 3, 3, 2, /**/ 2, 3, 4>(q, 2, 1, 0);
167+
passed &= test_impl<T, 8, 16, 4, /**/ 3, 5, 2, /**/ 2, 3, 1>(q, 2, 1, 0);
168+
if constexpr (sizeof(T) > 1) // TODO w/a vISA builder bug
169+
passed &= test_impl<T, 9, 17, 5, /**/ 3, 5, 2, /**/ 2, 3, 1>(q, 2, 1, 0);
170+
return passed;
171+
}
172+
173+
int main(int argc, char **argv) {
174+
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
175+
auto dev = q.get_device();
176+
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";
177+
178+
bool passed = true;
179+
passed &= test<char>(q);
180+
passed &= test<unsigned short>(q);
181+
passed &= test<half>(q);
182+
passed &= test<int>(q);
183+
passed &= test<float>(q);
184+
passed &= test<double>(q);
185+
passed &= test<uint64_t>(q);
186+
187+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
188+
return passed ? 0 : 1;
189+
}

0 commit comments

Comments
 (0)