1//===------- Offload API tests - gtest fixtures --==-----------------------===//
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
9#include <OffloadAPI.h>
10#include <OffloadPrint.hpp>
11#include <gtest/gtest.h>
12
13#include "Environment.hpp"
14
15#pragma once
16
17#ifndef ASSERT_SUCCESS
18#define ASSERT_SUCCESS(ACTUAL) \
19 do { \
20 ol_result_t Res = ACTUAL; \
21 if (Res && Res->Code != OL_ERRC_SUCCESS) { \
22 GTEST_FAIL() << #ACTUAL " returned " << Res->Code << ": " \
23 << Res->Details; \
24 } \
25 } while (0)
26#endif
27
28// TODO: rework this so the EXPECTED/ACTUAL results are readable
29#ifndef ASSERT_ERROR
30#define ASSERT_ERROR(EXPECTED, ACTUAL) \
31 do { \
32 ol_result_t Res = ACTUAL; \
33 ASSERT_TRUE(Res && (Res->Code == EXPECTED)); \
34 } while (0)
35#endif
36
37#ifndef ASSERT_ANY_ERROR
38#define ASSERT_ANY_ERROR(ACTUAL) \
39 do { \
40 ol_result_t Res = ACTUAL; \
41 ASSERT_TRUE(Res); \
42 } while (0)
43#endif
44
45#define RETURN_ON_FATAL_FAILURE(...) \
46 __VA_ARGS__; \
47 if (this->HasFatalFailure() || this->IsSkipped()) { \
48 return; \
49 } \
50 (void)0
51
52inline std::string SanitizeString(const std::string &Str) {
53 auto NewStr = Str;
54 std::replace_if(
55 first: NewStr.begin(), last: NewStr.end(), pred: [](char C) { return !std::isalnum(C); },
56 new_value: '_');
57 return NewStr;
58}
59
60struct OffloadTest : ::testing::Test {
61 ol_device_handle_t Host = TestEnvironment::getHostDevice();
62};
63
64struct OffloadDeviceTest
65 : OffloadTest,
66 ::testing::WithParamInterface<TestEnvironment::Device> {
67 void SetUp() override {
68 RETURN_ON_FATAL_FAILURE(OffloadTest::SetUp());
69
70 auto DeviceParam = GetParam();
71 Device = DeviceParam.Handle;
72 if (Device == nullptr)
73 GTEST_SKIP() << "No available devices.";
74 }
75
76 ol_platform_backend_t getPlatformBackend() const {
77 ol_platform_handle_t Platform = nullptr;
78 if (olGetDeviceInfo(Device, OL_DEVICE_INFO_PLATFORM,
79 sizeof(ol_platform_handle_t), &Platform))
80 return OL_PLATFORM_BACKEND_UNKNOWN;
81 ol_platform_backend_t Backend;
82 if (olGetPlatformInfo(Platform, OL_PLATFORM_INFO_BACKEND,
83 sizeof(ol_platform_backend_t), &Backend))
84 return OL_PLATFORM_BACKEND_UNKNOWN;
85 return Backend;
86 }
87
88 ol_device_handle_t Device = nullptr;
89};
90
91struct OffloadPlatformTest : OffloadDeviceTest {
92 void SetUp() override {
93 RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
94
95 ASSERT_SUCCESS(olGetDeviceInfo(Device, OL_DEVICE_INFO_PLATFORM,
96 sizeof(Platform), &Platform));
97 ASSERT_NE(Platform, nullptr);
98 }
99
100 ol_platform_handle_t Platform = nullptr;
101};
102
103// Fixture for a generic program test. If you want a different program, use
104// offloadQueueTest and create your own program handle with the binary you want.
105struct OffloadProgramTest : OffloadDeviceTest {
106 void SetUp() override { SetUpWith("foo"); }
107
108 void SetUpWith(const char *ProgramName) {
109 RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
110 ASSERT_TRUE(
111 TestEnvironment::loadDeviceBinary(ProgramName, Device, DeviceBin));
112 ASSERT_GE(DeviceBin->getBufferSize(), 0lu);
113 ASSERT_SUCCESS(olCreateProgram(Device, DeviceBin->getBufferStart(),
114 DeviceBin->getBufferSize(), &Program));
115 }
116
117 void TearDown() override {
118 if (Program) {
119 olDestroyProgram(Program);
120 }
121 RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::TearDown());
122 }
123
124 ol_program_handle_t Program = nullptr;
125 std::unique_ptr<llvm::MemoryBuffer> DeviceBin;
126};
127
128struct OffloadKernelTest : OffloadProgramTest {
129 void SetUp() override {
130 RETURN_ON_FATAL_FAILURE(OffloadProgramTest::SetUp());
131 ASSERT_SUCCESS(olGetSymbol(Program, "foo", OL_SYMBOL_KIND_KERNEL, &Kernel));
132 }
133
134 void TearDown() override {
135 RETURN_ON_FATAL_FAILURE(OffloadProgramTest::TearDown());
136 }
137
138 ol_symbol_handle_t Kernel = nullptr;
139};
140
141struct OffloadGlobalTest : OffloadProgramTest {
142 void SetUp() override {
143 RETURN_ON_FATAL_FAILURE(OffloadProgramTest::SetUpWith("global"));
144 ASSERT_SUCCESS(olGetSymbol(Program, "global",
145 OL_SYMBOL_KIND_GLOBAL_VARIABLE, &Global));
146 }
147
148 void TearDown() override {
149 RETURN_ON_FATAL_FAILURE(OffloadProgramTest::TearDown());
150 }
151
152 ol_symbol_handle_t Global = nullptr;
153};
154
155struct OffloadQueueTest : OffloadDeviceTest {
156 void SetUp() override {
157 RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::SetUp());
158 ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
159 }
160
161 void TearDown() override {
162 if (Queue) {
163 olDestroyQueue(Queue);
164 }
165 RETURN_ON_FATAL_FAILURE(OffloadDeviceTest::TearDown());
166 }
167
168 ol_queue_handle_t Queue = nullptr;
169};
170
171struct OffloadEventTest : OffloadQueueTest {
172 void SetUp() override {
173 RETURN_ON_FATAL_FAILURE(OffloadQueueTest::SetUp());
174 if (getPlatformBackend() == OL_PLATFORM_BACKEND_AMDGPU)
175 GTEST_SKIP() << "AMDGPU synchronize event not implemented";
176
177 // Get an event from a memcpy. We can still use it in olGetEventInfo etc
178 // after it has been waited on.
179 void *Alloc;
180 uint32_t Value = 42;
181 ASSERT_SUCCESS(
182 olMemAlloc(Device, OL_ALLOC_TYPE_DEVICE, sizeof(Value), &Alloc));
183 ASSERT_SUCCESS(
184 olMemcpy(Queue, Alloc, Device, &Value, Host, sizeof(Value), &Event));
185 ASSERT_SUCCESS(olWaitEvent(Event));
186 ASSERT_SUCCESS(olMemFree(Alloc));
187 }
188
189 void TearDown() override {
190 if (Event)
191 olDestroyEvent(Event);
192 RETURN_ON_FATAL_FAILURE(OffloadQueueTest::TearDown());
193 }
194
195 ol_event_handle_t Event = nullptr;
196};
197
198#define OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(FIXTURE) \
199 INSTANTIATE_TEST_SUITE_P( \
200 , FIXTURE, ::testing::ValuesIn(TestEnvironment::getDevices()), \
201 [](const ::testing::TestParamInfo<TestEnvironment::Device> &info) { \
202 return SanitizeString(info.param.Name); \
203 })
204

source code of offload/unittests/OffloadAPI/common/Fixtures.hpp