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

Commit 8bc731b

Browse files
authored
[SYCL][ESIMD] Add a test for extended math operations. (#186)
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent b2d2fd6 commit 8bc731b

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

SYCL/ESIMD/ext_math.cpp

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//==---------------- ext_math.cpp - DPC++ ESIMD extended math 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
10+
// RUN: %clangxx-esimd -fsycl %s -o %t.out
11+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
12+
13+
// This test checks extended math operations.
14+
15+
#include "esimd_test_utils.hpp"
16+
17+
#include <CL/sycl.hpp>
18+
#include <CL/sycl/INTEL/esimd.hpp>
19+
#include <iostream>
20+
21+
using namespace cl::sycl;
22+
using namespace sycl::INTEL::gpu;
23+
24+
// --- Data initialization functions
25+
26+
struct InitDataFuncWide {
27+
void operator()(float *In, float *Out, size_t Size) const {
28+
for (auto I = 0; I < Size; ++I) {
29+
In[I] = I + 1.0;
30+
Out[I] = (float)0.0;
31+
}
32+
}
33+
};
34+
35+
struct InitDataFuncNarrow {
36+
void operator()(float *In, float *Out, size_t Size) const {
37+
for (auto I = 0; I < Size; ++I) {
38+
In[I] = 2.0f + 16.0f * ((float)I / (float)(Size - 1)); // in [2..16] range
39+
Out[I] = (float)0.0;
40+
}
41+
}
42+
};
43+
44+
// --- Math operation identification
45+
46+
enum class MathOp { sin, cos, exp, sqrt, inv, log, rsqrt };
47+
48+
// --- Template functions calculating given math operation on host and device
49+
50+
template <int VL, MathOp Op> struct DeviceMathFunc;
51+
template <MathOp Op> float HostMathFunc(float X);
52+
53+
// --- Specializations per each extended math operation
54+
55+
#define DEFINE_OP(Op, HostOp) \
56+
template <> float HostMathFunc<MathOp::Op>(float X) { return HostOp(X); } \
57+
template <int VL> struct DeviceMathFunc<VL, MathOp::Op> { \
58+
simd<float, VL> \
59+
operator()(const simd<float, VL> &X) const SYCL_ESIMD_FUNCTION { \
60+
return esimd_##Op<VL>(X); \
61+
} \
62+
}
63+
64+
DEFINE_OP(sin, sin);
65+
DEFINE_OP(cos, cos);
66+
DEFINE_OP(exp, exp);
67+
DEFINE_OP(log, log);
68+
DEFINE_OP(inv, 1.0f /);
69+
DEFINE_OP(sqrt, sqrt);
70+
DEFINE_OP(rsqrt, 1.0f / sqrt);
71+
72+
// --- Generic kernel calculating an extended math operation on array elements
73+
74+
template <MathOp Op, int VL, typename AccIn, typename AccOut>
75+
struct DeviceFunc {
76+
AccIn In;
77+
AccOut Out;
78+
79+
DeviceFunc(AccIn &In, AccOut &Out) : In(In), Out(Out) {}
80+
81+
void operator()(id<1> I) const SYCL_ESIMD_KERNEL {
82+
unsigned int Offset = I * VL * sizeof(float);
83+
simd<float, VL> Vx = block_load<float, VL>(In, Offset);
84+
DeviceMathFunc<VL, Op> DevF{};
85+
Vx = DevF(Vx);
86+
block_store(Out, Offset, Vx);
87+
};
88+
};
89+
90+
// --- Generic test function for an extended math operation
91+
92+
template <MathOp Op, int VL, typename InitF = InitDataFuncNarrow>
93+
bool test(queue &Q, const std::string &Name,
94+
InitF InitData = InitDataFuncNarrow{}) {
95+
96+
constexpr size_t Size = 1024 * 128;
97+
98+
float *A = new float[Size];
99+
float *B = new float[Size];
100+
InitData(A, B, Size);
101+
std::cout << " Running " << Name << " test, VL=" << VL << "...\n";
102+
103+
try {
104+
buffer<float, 1> BufA(A, range<1>(Size));
105+
buffer<float, 1> BufB(B, range<1>(Size));
106+
107+
// number of workgroups
108+
cl::sycl::range<1> GlobalRange{Size / VL};
109+
110+
// threads (workitems) in each workgroup
111+
cl::sycl::range<1> LocalRange{1};
112+
113+
auto E = Q.submit([&](handler &CGH) {
114+
auto PA = BufA.get_access<access::mode::read>(CGH);
115+
auto PB = BufB.get_access<access::mode::write>(CGH);
116+
DeviceFunc<Op, VL, decltype(PA), decltype(PB)> Kernel(PA, PB);
117+
CGH.parallel_for(nd_range<1>{GlobalRange, LocalRange}, Kernel);
118+
});
119+
E.wait();
120+
} catch (sycl::exception &Exc) {
121+
std::cout << " *** ERROR. SYCL exception caught: << " << Exc.what()
122+
<< "\n";
123+
return false;
124+
}
125+
126+
int ErrCnt = 0;
127+
128+
for (unsigned I = 0; I < Size; ++I) {
129+
float Gold = A[I];
130+
Gold = HostMathFunc<Op>(Gold);
131+
float Test = B[I];
132+
133+
if (abs(Test - Gold) > 0.0001) {
134+
if (++ErrCnt < 10) {
135+
std::cout << " failed at index " << I << ", " << Test
136+
<< " != " << Gold << " (gold)\n";
137+
}
138+
}
139+
}
140+
delete[] A;
141+
delete[] B;
142+
143+
if (ErrCnt > 0) {
144+
std::cout << " pass rate: "
145+
<< ((float)(Size - ErrCnt) / (float)Size) * 100.0f << "% ("
146+
<< (Size - ErrCnt) << "/" << Size << ")\n";
147+
}
148+
149+
std::cout << (ErrCnt > 0 ? " FAILED\n" : " Passed\n");
150+
return ErrCnt == 0;
151+
}
152+
153+
// --- Tests all extended math operations with given vector length
154+
155+
template <int VL> bool test(queue &Q) {
156+
bool Pass = true;
157+
158+
Pass &= test<MathOp::sqrt, VL>(Q, "sqrt", InitDataFuncWide{});
159+
Pass &= test<MathOp::inv, VL>(Q, "inv");
160+
Pass &= test<MathOp::rsqrt, VL>(Q, "rsqrt");
161+
// TODO enable these tests after the implementation is fixed
162+
#if ENABLE_SIN_COS_EXP_LOG
163+
Pass &= test<MathOp::sin, VL>(Q, "sin", InitDataFuncWide{});
164+
Pass &= test<MathOp::cos, VL>(Q, "cos", InitDataFuncWide{});
165+
Pass &= test<MathOp::exp, VL>(Q, "exp");
166+
Pass &= test<MathOp::log, VL>(Q, "log", InitDataFuncWide{});
167+
#endif
168+
return Pass;
169+
}
170+
171+
// --- The entry point
172+
173+
int main(void) {
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+
bool Pass = true;
178+
Pass &= test<8>(Q);
179+
Pass &= test<16>(Q);
180+
Pass &= test<32>(Q);
181+
std::cout << (Pass ? "Test Passed\n" : "Test FAILED\n");
182+
return Pass ? 0 : 1;
183+
}

0 commit comments

Comments
 (0)