Skip to content

Commit fd3c17b

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 fd3c17b

2 files changed

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

0 commit comments

Comments
 (0)