Skip to content

Commit b646ba5

Browse files
Testing Existing SVM APIs remaining APIs tests (#2441)
Tests for the following APIs: * clEnqueueSVMMemcpy * clEnqueueSVMMemFill * clEnqueueSVMMap/clEnqueueSVMUnMap * clEnqueueSVMMigrateMem * clEnqueueSVMMemFree * clSetKernelArgSVMPointer * clSetKernelExecInfo --------- Signed-off-by: John Kesapides <john.kesapides@arm.com>
1 parent 69dc9d4 commit b646ba5

10 files changed

Lines changed: 1657 additions & 1 deletion

test_conformance/SVM/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ set(${MODULE_NAME}_SOURCES
2121
test_unified_svm_apis.cpp
2222
test_unified_svm_api_query_defaults.cpp
2323
test_unified_svm_api_suggested_type_index.cpp
24+
test_unified_svm_mem_cpy.cpp
25+
test_unified_svm_mem_fill.cpp
26+
test_unified_svm_migrate.cpp
27+
test_unified_svm_free.cpp
28+
test_unified_svm_setarg.cpp
29+
test_unified_svm_map_unmap.cpp
30+
test_unified_svm_execinfo.cpp
2431
)
2532

2633
set_gnulike_module_compile_flags("-Wno-sometimes-uninitialized -Wno-sign-compare")

test_conformance/SVM/common.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "harness/typeWrappers.h"
2424
#include <vector>
2525
#include <string>
26+
#include <algorithm>
2627

2728
#if (defined(_WIN32) || defined(_WIN64)) && defined(_MSC_VER)
2829
#include <windows.h>
@@ -85,5 +86,25 @@ extern cl_int create_cl_objects(cl_device_id device_from_harness, const char** p
8586

8687
extern const char *linked_list_create_and_verify_kernels[];
8788

89+
static inline cl_int check_event_type(cl_event event,
90+
cl_command_type expectedCommandType)
91+
{
92+
cl_command_type commandType;
93+
cl_int error = clGetEventInfo(event, CL_EVENT_COMMAND_TYPE,
94+
sizeof(cl_command_type), &commandType, NULL);
95+
test_error(error, "clGetEventInfo failed");
96+
97+
return commandType == expectedCommandType ? CL_SUCCESS : CL_INVALID_VALUE;
98+
}
99+
100+
static inline void generate_random_inputs(std::vector<cl_uchar> &v, MTdata d)
101+
{
102+
auto random_generator = [&d]() {
103+
return static_cast<cl_uchar>(genrand_int32(d));
104+
};
105+
106+
std::generate(v.begin(), v.end(), random_generator);
107+
}
108+
88109
#endif // #ifndef __COMMON_H__
89110

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
//
2+
// Copyright (c) 2025 The Khronos Group Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#include "unified_svm_fixture.h"
18+
#include "harness/conversions.h"
19+
#include "harness/testHarness.h"
20+
#include "harness/typeWrappers.h"
21+
#include <vector>
22+
23+
struct UnifiedSVMExecInfo : UnifiedSVMBase
24+
{
25+
using UnifiedSVMBase::UnifiedSVMBase;
26+
27+
// Test reading from USM pointer indirectly using clSetKernelExecInfo.
28+
// The test will perform a memcpy on the device.
29+
cl_int test_svm_exec_info_read(USVMWrapper<cl_uchar> *mem)
30+
{
31+
cl_int err = CL_SUCCESS;
32+
33+
std::vector<cl_uchar> src_data(alloc_count, 0);
34+
35+
auto ptr = mem->get_ptr();
36+
clMemWrapper indirect =
37+
clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
38+
sizeof(ptr), &ptr, &err);
39+
test_error(err, "could not create indirect buffer");
40+
41+
clMemWrapper direct = clCreateBuffer(context, CL_MEM_READ_WRITE,
42+
src_data.size(), nullptr, &err);
43+
test_error(err, "could not create direct buffer");
44+
45+
err = clSetKernelArg(kernel_IndirectAccessRead, 0, sizeof(indirect),
46+
&indirect);
47+
test_error(err, "could not set kernel argument 0");
48+
49+
err = clSetKernelArg(kernel_IndirectAccessRead, 1, sizeof(direct),
50+
&direct);
51+
test_error(err, "could not set kernel argument 1");
52+
53+
size_t test_offsets[] = { 0, alloc_count / 2 };
54+
55+
for (auto offset : test_offsets)
56+
{
57+
// Fill src data with a random pattern
58+
generate_random_inputs(src_data, d);
59+
60+
err = mem->write(src_data);
61+
test_error(err, "could not write to usvm memory");
62+
63+
void *info_ptr = &mem->get_ptr()[offset];
64+
65+
err = clSetKernelExecInfo(kernel_IndirectAccessRead,
66+
CL_KERNEL_EXEC_INFO_SVM_PTRS,
67+
sizeof(void *), &info_ptr);
68+
test_error(err, "could not enable indirect access");
69+
70+
size_t gws{ alloc_count };
71+
err = clEnqueueNDRangeKernel(queue, kernel_IndirectAccessRead, 1,
72+
nullptr, &gws, nullptr, 0, nullptr,
73+
nullptr);
74+
test_error(err, "clEnqueueNDRangeKernel failed");
75+
76+
err = clFinish(queue);
77+
test_error(err, "clFinish failed");
78+
79+
std::vector<cl_uchar> result_data(alloc_count, 0);
80+
err = clEnqueueReadBuffer(queue, direct, CL_TRUE, 0,
81+
result_data.size(), result_data.data(), 0,
82+
nullptr, nullptr);
83+
test_error(err, "clEnqueueReadBuffer failed");
84+
85+
// Validate result
86+
if (result_data != src_data)
87+
{
88+
for (size_t i = 0; i < alloc_count; i++)
89+
{
90+
if (src_data[i] != result_data[i])
91+
{
92+
log_error(
93+
"While attempting indirect read "
94+
"clSetKernelExecInfo with "
95+
"offset:%zu size:%zu \n"
96+
"Data verification mismatch at %zu expected: %d "
97+
"got: %d\n",
98+
offset, alloc_count, i, src_data[i],
99+
result_data[i]);
100+
return TEST_FAIL;
101+
}
102+
}
103+
}
104+
}
105+
return CL_SUCCESS;
106+
}
107+
108+
// Test writing to USM pointer indirectly using clSetKernelExecInfo.
109+
// The test will perform a memcpy on the device.
110+
cl_int test_svm_exec_info_write(USVMWrapper<cl_uchar> *mem)
111+
{
112+
cl_int err = CL_SUCCESS;
113+
114+
std::vector<cl_uchar> src_data(alloc_count, 0);
115+
116+
size_t test_offsets[] = { 0, alloc_count / 2 };
117+
118+
auto ptr = mem->get_ptr();
119+
clMemWrapper indirect =
120+
clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
121+
sizeof(ptr), &ptr, &err);
122+
test_error(err, "could not create indirect buffer");
123+
124+
clMemWrapper direct = clCreateBuffer(context, CL_MEM_READ_WRITE,
125+
alloc_count, nullptr, &err);
126+
test_error(err, "could not create direct buffer");
127+
128+
err = clSetKernelArg(kernel_IndirectAccessWrite, 0, sizeof(indirect),
129+
&indirect);
130+
test_error(err, "could not set kernel argument 0");
131+
132+
err = clSetKernelArg(kernel_IndirectAccessWrite, 1, sizeof(direct),
133+
&direct);
134+
test_error(err, "could not set kernel argument 1");
135+
136+
for (auto offset : test_offsets)
137+
{
138+
// Fill src data with a random pattern
139+
generate_random_inputs(src_data, d);
140+
141+
err = clEnqueueWriteBuffer(queue, direct, CL_NON_BLOCKING, 0,
142+
src_data.size(), src_data.data(), 0,
143+
nullptr, nullptr);
144+
test_error(err, "clEnqueueReadBuffer failed");
145+
146+
void *info_ptr = &mem->get_ptr()[offset];
147+
148+
err = clSetKernelExecInfo(kernel_IndirectAccessWrite,
149+
CL_KERNEL_EXEC_INFO_SVM_PTRS,
150+
sizeof(void *), &info_ptr);
151+
test_error(err, "could not enable indirect access");
152+
153+
size_t gws{ alloc_count };
154+
err = clEnqueueNDRangeKernel(queue, kernel_IndirectAccessWrite, 1,
155+
nullptr, &gws, nullptr, 0, nullptr,
156+
nullptr);
157+
test_error(err, "clEnqueueNDRangeKernel failed");
158+
159+
err = clFinish(queue);
160+
test_error(err, "clFinish failed");
161+
162+
std::vector<cl_uchar> result_data(alloc_count, 0);
163+
err = mem->read(result_data);
164+
test_error(err, "could not read from usvm memory");
165+
166+
// Validate result
167+
if (result_data != src_data)
168+
{
169+
for (size_t i = 0; i < alloc_count; i++)
170+
{
171+
if (src_data[i] != result_data[i])
172+
{
173+
log_error(
174+
"While attempting indirect write "
175+
"clSetKernelExecInfo with "
176+
"offset:%zu size:%zu \n"
177+
"Data verification mismatch at %zu expected: %d "
178+
"got: %d\n",
179+
offset, alloc_count, i, src_data[i],
180+
result_data[i]);
181+
return TEST_FAIL;
182+
}
183+
}
184+
}
185+
}
186+
return CL_SUCCESS;
187+
}
188+
189+
cl_int setup() override
190+
{
191+
cl_int err = UnifiedSVMBase::setup();
192+
if (CL_SUCCESS != err)
193+
{
194+
return err;
195+
}
196+
197+
return createIndirectAccessKernel();
198+
}
199+
200+
cl_int run() override
201+
{
202+
cl_int err;
203+
cl_uint max_ti = static_cast<cl_uint>(deviceUSVMCaps.size());
204+
205+
for (cl_uint ti = 0; ti < max_ti; ti++)
206+
{
207+
auto mem = get_usvm_wrapper<cl_uchar>(ti);
208+
209+
err = mem->allocate(alloc_count);
210+
test_error(err, "SVM allocation failed");
211+
212+
log_info(" testing clSetKernelArgSVMPointer() SVM type %u \n",
213+
ti);
214+
err = test_svm_exec_info_read(mem.get());
215+
if (CL_SUCCESS != err)
216+
{
217+
return err;
218+
}
219+
220+
err = test_svm_exec_info_write(mem.get());
221+
if (CL_SUCCESS != err)
222+
{
223+
return err;
224+
}
225+
226+
err = mem->free();
227+
test_error(err, "SVM free failed");
228+
}
229+
230+
return CL_SUCCESS;
231+
}
232+
233+
cl_int createIndirectAccessKernel()
234+
{
235+
cl_int err;
236+
237+
const char *programString = R"(
238+
struct s { const global unsigned char* ptr; };
239+
kernel void test_IndirectAccessRead(const global struct s* src, global unsigned char* dst)
240+
{
241+
dst[get_global_id(0)] = src->ptr[get_global_id(0)];
242+
}
243+
244+
struct d { global unsigned char* ptr; };
245+
kernel void test_IndirectAccessWrite(global struct d* dst, const global unsigned char* src)
246+
{
247+
dst->ptr[get_global_id(0)] = src[get_global_id(0)];
248+
}
249+
)";
250+
251+
clProgramWrapper program;
252+
err = create_single_kernel_helper(
253+
context, &program, &kernel_IndirectAccessRead, 1, &programString,
254+
"test_IndirectAccessRead");
255+
test_error(err, "could not create IndirectAccessRead kernel");
256+
257+
kernel_IndirectAccessWrite =
258+
clCreateKernel(program, "test_IndirectAccessWrite", &err);
259+
test_error(err, "could not create IndirectAccessWrite kernel");
260+
261+
return CL_SUCCESS;
262+
}
263+
264+
clKernelWrapper kernel_IndirectAccessRead;
265+
clKernelWrapper kernel_IndirectAccessWrite;
266+
267+
static constexpr size_t alloc_count = 1024;
268+
};
269+
270+
REGISTER_TEST(unified_svm_exec_info)
271+
{
272+
if (!is_extension_available(device, "cl_khr_unified_svm"))
273+
{
274+
log_info("cl_khr_unified_svm is not supported, skipping test.\n");
275+
return TEST_SKIPPED_ITSELF;
276+
}
277+
278+
cl_int err;
279+
280+
clContextWrapper contextWrapper;
281+
clCommandQueueWrapper queueWrapper;
282+
283+
// For now: create a new context and queue.
284+
// If we switch to a new test executable and run the tests without
285+
// forceNoContextCreation then this can be removed, and we can just use the
286+
// context and the queue from the harness.
287+
if (context == nullptr)
288+
{
289+
contextWrapper =
290+
clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
291+
test_error(err, "clCreateContext failed");
292+
context = contextWrapper;
293+
}
294+
295+
if (queue == nullptr)
296+
{
297+
queueWrapper = clCreateCommandQueue(context, device, 0, &err);
298+
test_error(err, "clCreateCommandQueue failed");
299+
queue = queueWrapper;
300+
}
301+
302+
UnifiedSVMExecInfo Test(context, device, queue, num_elements);
303+
err = Test.setup();
304+
test_error(err, "test setup failed");
305+
306+
err = Test.run();
307+
test_error(err, "test failed");
308+
309+
return TEST_PASS;
310+
}

0 commit comments

Comments
 (0)