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

[ESIMD] Add ahead-of-time compilation test. #523

Merged
merged 1 commit into from
Oct 20, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions SYCL/ESIMD/aot_mixed.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
//==---------------- aot_mixed.cpp - DPC++ ESIMD on-device test -----------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// REQUIRES: gpu
// UNSUPPORTED: cuda || hip
// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen -Xsycl-target-backend=spir64_gen "-device gen9" -o %t.sycl.out -DENABLE_SYCL=0 %s
// RUN: %GPU_RUN_PLACEHOLDER %t.sycl.out
// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen -Xsycl-target-backend=spir64_gen "-device gen9" -o %t.out %s
// RUN: %GPU_RUN_PLACEHOLDER %t.out
// XFAIL: *
// TODO: remove XFAIL once ocloc support for automatic scalar/vector SPIRV
// module dispatching is available in public drivers. Also change 'gen9' (safe
// variant to reliably get unexpected PASS when ocloc is fixed) to '*' (which
// stresses ocloc).

// This test checks ESIMD ahead-of-time compilation scenarios:
// 1) When the application contains both SYCL and ESIMD kernel, thus requiring
// different GPU back-ends (scalar and vector) to kick-in at compile-time.
// 2) When the application contains only ESIMD kernel.

#include "esimd_test_utils.hpp"

#include <CL/sycl.hpp>
#include <iostream>
#include <sycl/ext/intel/experimental/esimd.hpp>

using namespace cl::sycl;

#ifndef ENABLE_SIMD

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unclear here, why this macro is needed? It is just turned on in the next line all the time because it is not set in the compilation line. Is it supposed to be disabled some time later? It may be good to have a TODO comment here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ENABLE_SIMD/ENABLE_SYCL are used to enable/disable corresponding parts in the test. e.g. -DENABLE_SYCL=0 disables the SYCL part, which is used in one of the RUN: commands above.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see how ENABLE_SYCL is either set to 0 or unset in the command line, but ENABLE_SIMD is not used in the command line right now, so it is always set to 1 in the line 34, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. ENABLE_SIMD is just for convenience for somebody who would want to try.

#define ENABLE_SIMD 1
#endif

#ifndef ENABLE_SYCL
#define ENABLE_SYCL 1
#endif

bool verify(float *A, float *B, float *C, size_t Size) {
int err_cnt = 0;

for (unsigned i = 0; i < Size; ++i) {
if (A[i] + B[i] != C[i]) {
if (++err_cnt < 10) {
std::cout << "failed at index " << i << ", " << C[i] << " != " << A[i]
<< " + " << B[i] << "\n";
}
}
}
if (err_cnt > 0) {
std::cout << " pass rate: "
<< ((float)(Size - err_cnt) / (float)Size) * 100.0f << "% ("
<< (Size - err_cnt) << "/" << Size << ")\n";
}
return err_cnt == 0;
}

constexpr unsigned Size = 1024 * 128;
constexpr unsigned VL = 16;

#if ENABLE_SIMD
bool test_esimd(queue q) {
std::cout << "Running ESIMD kernel...\n";
float *A = new float[Size];
float *B = new float[Size];
float *C = new float[Size];

for (unsigned i = 0; i < Size; ++i) {
A[i] = B[i] = i;
C[i] = 0.0f;
}

try {
buffer<float, 1> bufa(A, range<1>(Size));
buffer<float, 1> bufb(B, range<1>(Size));
buffer<float, 1> bufc(C, range<1>(Size));

auto e = q.submit([&](handler &cgh) {
auto PA = bufa.get_access<access::mode::read>(cgh);
auto PB = bufb.get_access<access::mode::read>(cgh);
auto PC = bufc.get_access<access::mode::write>(cgh);
cgh.parallel_for<class TestESIMD>(
Size / VL, [=](id<1> i) SYCL_ESIMD_KERNEL {
using namespace sycl::ext::intel::experimental::esimd;
unsigned int offset = i * VL * sizeof(float);
simd<float, VL> va;
va.copy_from(PA, offset);
simd<float, VL> vb;
vb.copy_from(PB, offset);
simd<float, VL> vc = va + vb;
vc.copy_to(PC, offset);
});
});
e.wait();
} catch (cl::sycl::exception const &e) {
std::cout << "SYCL exception caught: " << e.what() << '\n';

delete[] A;
delete[] B;
delete[] C;

return false;
}
bool passed = verify(A, B, C, Size);

delete[] A;
delete[] B;
delete[] C;
return passed;
}
#endif

#if ENABLE_SYCL
bool test_sycl(queue q) {
std::cout << "Running SYCL kernel...\n";
float *A = new float[Size];
float *B = new float[Size];
float *C = new float[Size];

for (unsigned i = 0; i < Size; ++i) {
A[i] = B[i] = i;
C[i] = 0.0f;
}

try {
buffer<float, 1> bufa(A, range<1>(Size));
buffer<float, 1> bufb(B, range<1>(Size));
buffer<float, 1> bufc(C, range<1>(Size));

auto e = q.submit([&](handler &cgh) {
auto PA = bufa.get_access<access::mode::read>(cgh);
auto PB = bufb.get_access<access::mode::read>(cgh);
auto PC = bufc.get_access<access::mode::write>(cgh);
cgh.parallel_for<class TestSYCL>(Size,
[=](id<1> i) { PC[i] = PA[i] + PB[i]; });
});
e.wait();
} catch (cl::sycl::exception const &e) {
std::cout << "SYCL exception caught: " << e.what() << '\n';

delete[] A;
delete[] B;
delete[] C;

return false;
}
bool passed = verify(A, B, C, Size);

delete[] A;
delete[] B;
delete[] C;
return passed;
}
#endif

int main(void) {
queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler());
auto dev = q.get_device();
std::cout << "Running on " << dev.get_info<info::device::name>() << "\n";

bool passed = true;
#if ENABLE_SIMD
passed &= test_esimd(q);
#endif
#if ENABLE_SYCL
passed &= test_sycl(q);
#endif

std::cout << (passed ? "TEST Passed\n" : "TEST FAILED\n");
return passed ? 0 : 1;
}