Skip to content

Commit 3c10e5b

Browse files
[OpenMP] Add unit tests for nextgen plugins (#74398)
This patch add three GTest unit tests that test plugin read and write operations. Tests can be compiled with `ninja -C runtimes/runtimes-bins LibomptUnitTests`.
1 parent c6f29db commit 3c10e5b

File tree

4 files changed

+193
-0
lines changed

4 files changed

+193
-0
lines changed

openmp/libomptarget/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,9 @@ add_subdirectory(${LIBOMPTARGET_SRC_DIR})
150150

151151
# Add tests.
152152
add_subdirectory(test)
153+
154+
# Add unit tests if GMock/GTest is present
155+
if (EXISTS ${LLVM_THIRD_PARTY_DIR}/unittest)
156+
add_subdirectory(${LLVM_THIRD_PARTY_DIR}/unittest ${CMAKE_CURRENT_BINARY_DIR}/third-party/unittest)
157+
add_subdirectory(unittests)
158+
endif()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
add_custom_target(LibomptUnitTests)
2+
set_target_properties(LibomptUnitTests PROPERTIES FOLDER "Tests/UnitTests")
3+
4+
function(add_libompt_unittest test_dirname)
5+
add_unittest(LibomptUnitTests ${test_dirname} ${ARGN})
6+
endfunction()
7+
8+
add_subdirectory(Plugins)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set(PLUGINS_TEST_COMMON omptarget OMPT omptarget.devicertl)
2+
set(PLUGINS_TEST_SOURCES NextgenPluginsTest.cpp)
3+
set(PLUGINS_TEST_INCLUDE ${LIBOMPTARGET_INCLUDE_DIR})
4+
5+
foreach(PLUGIN IN LISTS LIBOMPTARGET_TESTED_PLUGINS)
6+
libomptarget_say("Building plugin unit tests for ${PLUGIN}")
7+
add_libompt_unittest("${PLUGIN}.unittests" ${PLUGINS_TEST_SOURCES})
8+
add_dependencies("${PLUGIN}.unittests" ${PLUGINS_TEST_COMMON} ${PLUGIN})
9+
target_link_libraries("${PLUGIN}.unittests" PRIVATE ${PLUGINS_TEST_COMMON} ${PLUGIN})
10+
target_include_directories("${PLUGIN}.unittests" PRIVATE ${PLUGINS_TEST_INCLUDE})
11+
endforeach()
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
//===------- unittests/Plugins/NextgenPluginsTest.cpp - Plugin tests ------===//
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 "Shared/PluginAPI.h"
10+
#include "omptarget.h"
11+
#include "gtest/gtest.h"
12+
13+
#include <unordered_set>
14+
15+
const int DEVICE_ID = 0;
16+
std::unordered_set<int> setup_map;
17+
18+
int init_test_device(int ID) {
19+
if (setup_map.find(ID) != setup_map.end()) {
20+
return OFFLOAD_SUCCESS;
21+
}
22+
if (__tgt_rtl_init_plugin() == OFFLOAD_FAIL ||
23+
__tgt_rtl_init_device(ID) == OFFLOAD_FAIL) {
24+
return OFFLOAD_FAIL;
25+
}
26+
setup_map.insert(ID);
27+
return OFFLOAD_SUCCESS;
28+
}
29+
30+
// Test plugin initialization
31+
TEST(NextgenPluginsTest, PluginInit) {
32+
EXPECT_EQ(OFFLOAD_SUCCESS, init_test_device(DEVICE_ID));
33+
}
34+
35+
// Test GPU allocation and R/W
36+
TEST(NextgenPluginsTest, PluginAlloc) {
37+
int32_t test_value = 23;
38+
int32_t host_value = -1;
39+
int64_t var_size = sizeof(int32_t);
40+
41+
// Init plugin and device
42+
EXPECT_EQ(OFFLOAD_SUCCESS, init_test_device(DEVICE_ID));
43+
44+
// Allocate memory
45+
void *device_ptr =
46+
__tgt_rtl_data_alloc(DEVICE_ID, var_size, nullptr, TARGET_ALLOC_DEFAULT);
47+
48+
// Check that the result is not null
49+
EXPECT_NE(device_ptr, nullptr);
50+
51+
// Submit data to device
52+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_submit(DEVICE_ID, device_ptr,
53+
&test_value, var_size));
54+
55+
// Read data from device
56+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_retrieve(DEVICE_ID, &host_value,
57+
device_ptr, var_size));
58+
59+
// Compare values
60+
EXPECT_EQ(host_value, test_value);
61+
62+
// Cleanup data
63+
EXPECT_EQ(OFFLOAD_SUCCESS,
64+
__tgt_rtl_data_delete(DEVICE_ID, device_ptr, TARGET_ALLOC_DEFAULT));
65+
}
66+
67+
// Test async GPU allocation and R/W
68+
TEST(NextgenPluginsTest, PluginAsyncAlloc) {
69+
int32_t test_value = 47;
70+
int32_t host_value = -1;
71+
int64_t var_size = sizeof(int32_t);
72+
__tgt_async_info *info;
73+
74+
// Init plugin and device
75+
EXPECT_EQ(OFFLOAD_SUCCESS, init_test_device(DEVICE_ID));
76+
77+
// Check if device supports async
78+
// Platforms like x86_64 don't support it
79+
if (__tgt_rtl_init_async_info(DEVICE_ID, &info) == OFFLOAD_SUCCESS) {
80+
// Allocate memory
81+
void *device_ptr = __tgt_rtl_data_alloc(DEVICE_ID, var_size, nullptr,
82+
TARGET_ALLOC_DEFAULT);
83+
84+
// Check that the result is not null
85+
EXPECT_NE(device_ptr, nullptr);
86+
87+
// Submit data to device asynchronously
88+
EXPECT_EQ(OFFLOAD_SUCCESS,
89+
__tgt_rtl_data_submit_async(DEVICE_ID, device_ptr, &test_value,
90+
var_size, info));
91+
92+
// Wait for async request to process
93+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_synchronize(DEVICE_ID, info));
94+
95+
// Read data from device
96+
EXPECT_EQ(OFFLOAD_SUCCESS,
97+
__tgt_rtl_data_retrieve_async(DEVICE_ID, &host_value, device_ptr,
98+
var_size, info));
99+
100+
// Wait for async request to process
101+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_synchronize(DEVICE_ID, info));
102+
103+
// Compare values
104+
EXPECT_EQ(host_value, test_value);
105+
106+
// Cleanup data
107+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_delete(DEVICE_ID, device_ptr,
108+
TARGET_ALLOC_DEFAULT));
109+
}
110+
}
111+
112+
// Test GPU data exchange
113+
TEST(NextgenPluginsTest, PluginDataSwap) {
114+
int32_t test_value = 23;
115+
int32_t host_value = -1;
116+
int64_t var_size = sizeof(int32_t);
117+
118+
// Look for compatible device
119+
int DEVICE_TWO = -1;
120+
for (int i = 1; i < __tgt_rtl_number_of_devices(); i++) {
121+
if (__tgt_rtl_is_data_exchangable(DEVICE_ID, i)) {
122+
DEVICE_TWO = i;
123+
break;
124+
}
125+
}
126+
127+
// Only run test if we have multiple GPUs to test
128+
// GPUs must be compatible for test to work
129+
if (DEVICE_TWO >= 1) {
130+
// Init both GPUs
131+
EXPECT_EQ(OFFLOAD_SUCCESS, init_test_device(DEVICE_ID));
132+
EXPECT_EQ(OFFLOAD_SUCCESS, init_test_device(DEVICE_TWO));
133+
134+
// Allocate memory on both GPUs
135+
// DEVICE_ID will be the source
136+
// DEVICE_TWO will be the destination
137+
void *source_ptr = __tgt_rtl_data_alloc(DEVICE_ID, var_size, nullptr,
138+
TARGET_ALLOC_DEFAULT);
139+
void *dest_ptr = __tgt_rtl_data_alloc(DEVICE_TWO, var_size, nullptr,
140+
TARGET_ALLOC_DEFAULT);
141+
142+
// Check for success in allocation
143+
EXPECT_NE(source_ptr, nullptr);
144+
EXPECT_NE(dest_ptr, nullptr);
145+
146+
// Write data to source
147+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_submit(DEVICE_ID, source_ptr,
148+
&test_value, var_size));
149+
150+
// Transfer data between devices
151+
EXPECT_EQ(OFFLOAD_SUCCESS,
152+
__tgt_rtl_data_exchange(DEVICE_ID, source_ptr, DEVICE_TWO,
153+
dest_ptr, var_size));
154+
155+
// Read from destination device (DEVICE_TWO) memory
156+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_retrieve(DEVICE_TWO, &host_value,
157+
dest_ptr, var_size));
158+
159+
// Ensure match
160+
EXPECT_EQ(host_value, test_value);
161+
162+
// Cleanup
163+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_delete(DEVICE_ID, source_ptr,
164+
TARGET_ALLOC_DEFAULT));
165+
EXPECT_EQ(OFFLOAD_SUCCESS, __tgt_rtl_data_delete(DEVICE_TWO, dest_ptr,
166+
TARGET_ALLOC_DEFAULT));
167+
}
168+
}

0 commit comments

Comments
 (0)