Skip to content

Commit 9c9df0c

Browse files
committed
USVM test for multithreaded alloc & free
Allocation and free entry-points USVM entry-points should be threadsafe as they may be used in a threaded manner. Stresses the bug found in the USVM emulation layer bashbaug/SimpleOpenCLSamples#165
1 parent 089e02c commit 9c9df0c

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

test_conformance/SVM/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ set(${MODULE_NAME}_SOURCES
2929
test_unified_svm_setarg.cpp
3030
test_unified_svm_map_unmap.cpp
3131
test_unified_svm_execinfo.cpp
32+
test_unified_svm_threading.cpp
3233
)
3334

3435
set_gnulike_module_compile_flags("-Wno-sometimes-uninitialized -Wno-sign-compare")
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//
2+
// Copyright (c) 2026 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 <cinttypes>
19+
#include <memory>
20+
#include <thread>
21+
22+
void worker(USVMWrapper<cl_int>* mem, cl_int* alloc_ret, cl_int* free_ret)
23+
{
24+
*alloc_ret = mem->allocate(4);
25+
*free_ret = mem->free();
26+
}
27+
28+
struct UnifiedSVMThreadedAllocFree : UnifiedSVMBase
29+
{
30+
UnifiedSVMThreadedAllocFree(cl_context context, cl_device_id device,
31+
cl_command_queue queue, int num_elements)
32+
: UnifiedSVMBase(context, device, queue, num_elements)
33+
{}
34+
35+
cl_int run() override
36+
{
37+
for (cl_uint ti = 0; ti < static_cast<cl_uint>(deviceUSVMCaps.size());
38+
ti++)
39+
{
40+
log_info(" testing SVM type %u\n", ti);
41+
42+
auto mem = get_usvm_wrapper<cl_int>(ti);
43+
const unsigned num_threads = 10;
44+
std::vector<std::thread> threads;
45+
std::vector<std::pair<cl_int, cl_int>> ret_codes(num_threads);
46+
47+
for (int i = 0; i < num_threads; ++i)
48+
{
49+
cl_int& alloc = ret_codes[i].first;
50+
cl_int& free = ret_codes[i].second;
51+
threads.push_back(
52+
std::thread(worker, mem.get(), &alloc, &free));
53+
}
54+
55+
for (auto& thread : threads)
56+
{
57+
thread.join();
58+
}
59+
60+
for (const auto& [alloc_ret, free_ret] : ret_codes)
61+
{
62+
test_error(alloc_ret, "USVM allocation failed");
63+
test_error(free_ret, "USVM free failed");
64+
}
65+
}
66+
67+
return CL_SUCCESS;
68+
}
69+
};
70+
71+
REGISTER_TEST(unified_svm_threading_alloc_free)
72+
{
73+
if (!is_extension_available(device, "cl_khr_unified_svm"))
74+
{
75+
log_info("cl_khr_unified_svm is not supported, skipping test.\n");
76+
return TEST_SKIPPED_ITSELF;
77+
}
78+
79+
cl_int err;
80+
81+
clContextWrapper contextWrapper;
82+
clCommandQueueWrapper queueWrapper;
83+
84+
// For now: create a new context and queue.
85+
// If we switch to a new test executable and run the tests without
86+
// forceNoContextCreation then this can be removed, and we can just use the
87+
// context and the queue from the harness.
88+
if (context == nullptr)
89+
{
90+
contextWrapper =
91+
clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
92+
test_error(err, "clCreateContext failed");
93+
context = contextWrapper;
94+
}
95+
96+
if (queue == nullptr)
97+
{
98+
queueWrapper = clCreateCommandQueue(context, device, 0, &err);
99+
test_error(err, "clCreateCommandQueue failed");
100+
queue = queueWrapper;
101+
}
102+
103+
UnifiedSVMThreadedAllocFree Test(context, device, queue, num_elements);
104+
err = Test.setup();
105+
test_error(err, "test setup failed");
106+
107+
err = Test.run();
108+
test_error(err, "test failed");
109+
110+
return TEST_PASS;
111+
}

0 commit comments

Comments
 (0)