switch SVM tests to the new test registration framework (#2168)

Switches the SVM tests to the new test registration framework.

The first commit is the best to review and contains the actual changes.
The second commit purely has formatting changes.

Note that several of these changes were a bit more than mechanical
because many of the SVM tests create a new context vs. using the context
provided by the harness and passed to each test function. The previous
code named the context provided by the harness differently, and hence
could use the name "context" in each test function, but with the new
test registration framework this is no longer possible. Instead, I am
creating the new context using the name "contextWrapper" and then
assigning it to the "context" passed to the test function, which seems
like the best way to avoid using the wrong context unintentionally. I am
open to suggestions to do this differently.

I have verified that the same calls are made before and after these
changes, and specifically that there are no context leaks.
This commit is contained in:
Ben Ashbaugh
2024-12-03 14:51:23 -08:00
committed by GitHub
parent e361b387d9
commit d99b302f90
16 changed files with 1066 additions and 854 deletions

View File

@@ -70,244 +70,282 @@ void CL_CALLBACK callback_svm_free(cl_command_queue queue, cl_uint num_svm_point
data->status.store(1, std::memory_order_release);
}
int test_svm_enqueue_api(cl_device_id deviceID, cl_context c, cl_command_queue queue, int num_elements)
REGISTER_TEST(svm_enqueue_api)
{
clContextWrapper context = NULL;
clCommandQueueWrapper queues[MAXQ];
cl_uint num_devices = 0;
const size_t elementNum = 1024;
const size_t numSVMBuffers = 32;
cl_int error = CL_SUCCESS;
RandomSeed seed(0);
clContextWrapper contextWrapper = NULL;
clCommandQueueWrapper queues[MAXQ];
cl_uint num_devices = 0;
const size_t elementNum = 1024;
const size_t numSVMBuffers = 32;
cl_int error = CL_SUCCESS;
RandomSeed seed(0);
error = create_cl_objects(deviceID, NULL, &context, NULL, &queues[0], &num_devices, CL_DEVICE_SVM_COARSE_GRAIN_BUFFER);
if(error) return TEST_FAIL;
error = create_cl_objects(deviceID, NULL, &contextWrapper, NULL, &queues[0],
&num_devices, CL_DEVICE_SVM_COARSE_GRAIN_BUFFER);
context = contextWrapper;
if (error) return TEST_FAIL;
queue = queues[0];
queue = queues[0];
//all possible sizes of vectors and scalars
size_t typeSizes[] = {
sizeof(cl_uchar),
sizeof(cl_uchar2),
sizeof(cl_uchar3),
sizeof(cl_uchar4),
sizeof(cl_uchar8),
sizeof(cl_uchar16),
sizeof(cl_ushort),
sizeof(cl_ushort2),
sizeof(cl_ushort3),
sizeof(cl_ushort4),
sizeof(cl_ushort8),
sizeof(cl_ushort16),
sizeof(cl_uint),
sizeof(cl_uint2),
sizeof(cl_uint3),
sizeof(cl_uint4),
sizeof(cl_uint8),
sizeof(cl_uint16),
sizeof(cl_ulong),
sizeof(cl_ulong2),
sizeof(cl_ulong3),
sizeof(cl_ulong4),
sizeof(cl_ulong8),
sizeof(cl_ulong16),
};
// all possible sizes of vectors and scalars
size_t typeSizes[] = {
sizeof(cl_uchar), sizeof(cl_uchar2), sizeof(cl_uchar3),
sizeof(cl_uchar4), sizeof(cl_uchar8), sizeof(cl_uchar16),
sizeof(cl_ushort), sizeof(cl_ushort2), sizeof(cl_ushort3),
sizeof(cl_ushort4), sizeof(cl_ushort8), sizeof(cl_ushort16),
sizeof(cl_uint), sizeof(cl_uint2), sizeof(cl_uint3),
sizeof(cl_uint4), sizeof(cl_uint8), sizeof(cl_uint16),
sizeof(cl_ulong), sizeof(cl_ulong2), sizeof(cl_ulong3),
sizeof(cl_ulong4), sizeof(cl_ulong8), sizeof(cl_ulong16),
};
enum allocationTypes {
host,
svm
};
struct TestType {
allocationTypes srcAlloc;
allocationTypes dstAlloc;
TestType(allocationTypes type1, allocationTypes type2): srcAlloc(type1), dstAlloc(type2){}
};
std::vector<TestType> testTypes;
testTypes.push_back(TestType(host, host));
testTypes.push_back(TestType(host, svm));
testTypes.push_back(TestType(svm, host));
testTypes.push_back(TestType(svm, svm));
for (const auto test_case : testTypes)
{
log_info("clEnqueueSVMMemcpy case: src_alloc = %s, dst_alloc = %s\n", test_case.srcAlloc == svm ? "svm" : "host", test_case.dstAlloc == svm ? "svm" : "host");
for (size_t i = 0; i < ARRAY_SIZE(typeSizes); ++i)
enum allocationTypes
{
//generate initial data
std::vector<cl_uchar> fillData0(typeSizes[i]), fillData1(typeSizes[i]);
generate_data(fillData0, typeSizes[i], seed);
generate_data(fillData1, typeSizes[i], seed);
size_t data_size = elementNum * typeSizes[i];
std::vector<cl_uchar> srcHostData(data_size, 0);
std::vector<cl_uchar> dstHostData(data_size, 0);
generate_data(srcHostData, srcHostData.size(), seed);
generate_data(dstHostData, dstHostData.size(), seed);
host,
svm
};
cl_uchar *srcBuffer = (cl_uchar *)clSVMAlloc(context, CL_MEM_READ_WRITE, data_size, 0);
cl_uchar *dstBuffer = (cl_uchar *)clSVMAlloc(context, CL_MEM_READ_WRITE, data_size, 0);
struct TestType
{
allocationTypes srcAlloc;
allocationTypes dstAlloc;
TestType(allocationTypes type1, allocationTypes type2)
: srcAlloc(type1), dstAlloc(type2)
{}
};
clEventWrapper userEvent = clCreateUserEvent(context, &error);
test_error(error, "clCreateUserEvent failed");
clEventWrapper eventMemFillList[2];
std::vector<TestType> testTypes;
error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData0[0], typeSizes[i], data_size, 1, &userEvent, &eventMemFillList[0]);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemFill(queue, dstBuffer, &fillData1[0], typeSizes[i], data_size, 1, &userEvent, &eventMemFillList[1]);
test_error(error, "clEnqueueSVMMemFill failed");
testTypes.push_back(TestType(host, host));
testTypes.push_back(TestType(host, svm));
testTypes.push_back(TestType(svm, host));
testTypes.push_back(TestType(svm, svm));
error = clSetUserEventStatus(userEvent, CL_COMPLETE);
test_error(error, "clSetUserEventStatus failed");
for (const auto test_case : testTypes)
{
log_info("clEnqueueSVMMemcpy case: src_alloc = %s, dst_alloc = %s\n",
test_case.srcAlloc == svm ? "svm" : "host",
test_case.dstAlloc == svm ? "svm" : "host");
for (size_t i = 0; i < ARRAY_SIZE(typeSizes); ++i)
{
// generate initial data
std::vector<cl_uchar> fillData0(typeSizes[i]),
fillData1(typeSizes[i]);
generate_data(fillData0, typeSizes[i], seed);
generate_data(fillData1, typeSizes[i], seed);
size_t data_size = elementNum * typeSizes[i];
std::vector<cl_uchar> srcHostData(data_size, 0);
std::vector<cl_uchar> dstHostData(data_size, 0);
generate_data(srcHostData, srcHostData.size(), seed);
generate_data(dstHostData, dstHostData.size(), seed);
cl_uchar * src_ptr;
cl_uchar * dst_ptr;
if (test_case.srcAlloc == host) {
src_ptr = srcHostData.data();
} else if (test_case.srcAlloc == svm) {
src_ptr = srcBuffer;
}
if (test_case.dstAlloc == host) {
dst_ptr = dstHostData.data();
} else if (test_case.dstAlloc == svm) {
dst_ptr = dstBuffer;
}
clEventWrapper eventMemcpy;
error = clEnqueueSVMMemcpy(queue, CL_FALSE, dst_ptr, src_ptr, data_size, 2, &eventMemFillList[0], &eventMemcpy);
test_error(error, "clEnqueueSVMMemcpy failed");
cl_uchar *srcBuffer = (cl_uchar *)clSVMAlloc(
context, CL_MEM_READ_WRITE, data_size, 0);
cl_uchar *dstBuffer = (cl_uchar *)clSVMAlloc(
context, CL_MEM_READ_WRITE, data_size, 0);
//coarse grain only supported. Synchronization required using map
clEventWrapper eventMap[2];
clEventWrapper userEvent = clCreateUserEvent(context, &error);
test_error(error, "clCreateUserEvent failed");
clEventWrapper eventMemFillList[2];
error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, srcBuffer, data_size, 1, &eventMemcpy, &eventMap[0]);
test_error(error, "clEnqueueSVMMap srcBuffer failed");
error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData0[0],
typeSizes[i], data_size, 1, &userEvent,
&eventMemFillList[0]);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemFill(queue, dstBuffer, &fillData1[0],
typeSizes[i], data_size, 1, &userEvent,
&eventMemFillList[1]);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, dstBuffer, data_size, 1, &eventMemcpy, &eventMap[1]);
test_error(error, "clEnqueueSVMMap dstBuffer failed");
error = clSetUserEventStatus(userEvent, CL_COMPLETE);
test_error(error, "clSetUserEventStatus failed");
error = clWaitForEvents(2, &eventMap[0]);
test_error(error, "clWaitForEvents failed");
cl_uchar *src_ptr;
cl_uchar *dst_ptr;
if (test_case.srcAlloc == host)
{
src_ptr = srcHostData.data();
}
else if (test_case.srcAlloc == svm)
{
src_ptr = srcBuffer;
}
if (test_case.dstAlloc == host)
{
dst_ptr = dstHostData.data();
}
else if (test_case.dstAlloc == svm)
{
dst_ptr = dstBuffer;
}
clEventWrapper eventMemcpy;
error =
clEnqueueSVMMemcpy(queue, CL_FALSE, dst_ptr, src_ptr, data_size,
2, &eventMemFillList[0], &eventMemcpy);
test_error(error, "clEnqueueSVMMemcpy failed");
//data verification
for (size_t j = 0; j < data_size; ++j)
{
if (dst_ptr[j] != src_ptr[j]) {
log_error("Invalid data at index %zu, dst_ptr %d, src_ptr %d\n", j,
dst_ptr[j], src_ptr[j]);
// coarse grain only supported. Synchronization required using map
clEventWrapper eventMap[2];
error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, srcBuffer,
data_size, 1, &eventMemcpy, &eventMap[0]);
test_error(error, "clEnqueueSVMMap srcBuffer failed");
error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, dstBuffer,
data_size, 1, &eventMemcpy, &eventMap[1]);
test_error(error, "clEnqueueSVMMap dstBuffer failed");
error = clWaitForEvents(2, &eventMap[0]);
test_error(error, "clWaitForEvents failed");
// data verification
for (size_t j = 0; j < data_size; ++j)
{
if (dst_ptr[j] != src_ptr[j])
{
log_error(
"Invalid data at index %zu, dst_ptr %d, src_ptr %d\n",
j, dst_ptr[j], src_ptr[j]);
return TEST_FAIL;
}
}
clEventWrapper eventUnmap[2];
error =
clEnqueueSVMUnmap(queue, srcBuffer, 0, nullptr, &eventUnmap[0]);
test_error(error, "clEnqueueSVMUnmap srcBuffer failed");
error =
clEnqueueSVMUnmap(queue, dstBuffer, 0, nullptr, &eventUnmap[1]);
test_error(error, "clEnqueueSVMUnmap dstBuffer failed");
error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData1[0],
typeSizes[i], data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemFill(queue, dstBuffer + data_size / 2,
&fillData1[0], typeSizes[i],
data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemcpy(queue, CL_FALSE, dstBuffer, srcBuffer,
data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemcpy failed");
error = clEnqueueSVMMemcpy(
queue, CL_TRUE, dstBuffer + data_size / 2,
srcBuffer + data_size / 2, data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemcpy failed");
void *ptrs[] = { (void *)srcBuffer, (void *)dstBuffer };
clEventWrapper eventFree;
error = clEnqueueSVMFree(queue, 2, ptrs, 0, 0, 0, 0, &eventFree);
test_error(error, "clEnqueueSVMFree failed");
error = clWaitForEvents(1, &eventFree);
test_error(error, "clWaitForEvents failed");
// event info verification for new SVM commands
cl_command_type commandType;
for (auto &check_event : eventMemFillList)
{
error =
clGetEventInfo(check_event, CL_EVENT_COMMAND_TYPE,
sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MEMFILL)
{
log_error("Invalid command type returned for "
"clEnqueueSVMMemFill\n");
return TEST_FAIL;
}
}
error = clGetEventInfo(eventMemcpy, CL_EVENT_COMMAND_TYPE,
sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MEMCPY)
{
log_error(
"Invalid command type returned for clEnqueueSVMMemcpy\n");
return TEST_FAIL;
}
for (size_t map_id = 0; map_id < ARRAY_SIZE(eventMap); map_id++)
{
error =
clGetEventInfo(eventMap[map_id], CL_EVENT_COMMAND_TYPE,
sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MAP)
{
log_error(
"Invalid command type returned for clEnqueueSVMMap\n");
return TEST_FAIL;
}
error =
clGetEventInfo(eventUnmap[map_id], CL_EVENT_COMMAND_TYPE,
sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_UNMAP)
{
log_error("Invalid command type returned for "
"clEnqueueSVMUnmap\n");
return TEST_FAIL;
}
}
error = clGetEventInfo(eventFree, CL_EVENT_COMMAND_TYPE,
sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_FREE)
{
log_error(
"Invalid command type returned for clEnqueueSVMFree\n");
return TEST_FAIL;
}
}
}
std::vector<void *> buffers(numSVMBuffers, 0);
for (size_t i = 0; i < numSVMBuffers; ++i)
buffers[i] = clSVMAlloc(context, CL_MEM_READ_WRITE, elementNum, 0);
// verify if callback is triggered correctly
CallbackData data;
data.status = 0;
error = clEnqueueSVMFree(queue, buffers.size(), &buffers[0],
callback_svm_free, &data, 0, 0, 0);
test_error(error, "clEnqueueSVMFree failed");
error = clFinish(queue);
test_error(error, "clFinish failed");
// wait for the callback
while (data.status.load(std::memory_order_acquire) == 0)
{
usleep(1);
}
// check if number of SVM pointers returned in the callback matches with
// expected
if (data.num_svm_pointers != buffers.size())
{
log_error("Invalid number of SVM pointers returned in the callback, "
"expected: %zu, got: %d\n",
buffers.size(), data.num_svm_pointers);
return TEST_FAIL;
}
// check if pointers returned in callback are correct
for (size_t i = 0; i < buffers.size(); ++i)
{
if (data.svm_pointers[i] != buffers[i])
{
log_error(
"Invalid SVM pointer returned in the callback, idx: %zu\n", i);
return TEST_FAIL;
}
}
clEventWrapper eventUnmap[2];
error = clEnqueueSVMUnmap(queue, srcBuffer, 0, nullptr, &eventUnmap[0]);
test_error(error, "clEnqueueSVMUnmap srcBuffer failed");
error = clEnqueueSVMUnmap(queue, dstBuffer, 0, nullptr, &eventUnmap[1]);
test_error(error, "clEnqueueSVMUnmap dstBuffer failed");
error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData1[0], typeSizes[i], data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemFill(queue, dstBuffer + data_size / 2, &fillData1[0], typeSizes[i], data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemFill failed");
error = clEnqueueSVMMemcpy(queue, CL_FALSE, dstBuffer, srcBuffer, data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemcpy failed");
error = clEnqueueSVMMemcpy(queue, CL_TRUE, dstBuffer + data_size / 2, srcBuffer + data_size / 2, data_size / 2, 0, 0, 0);
test_error(error, "clEnqueueSVMMemcpy failed");
void *ptrs[] = { (void *)srcBuffer, (void *)dstBuffer };
clEventWrapper eventFree;
error = clEnqueueSVMFree(queue, 2, ptrs, 0, 0, 0, 0, &eventFree);
test_error(error, "clEnqueueSVMFree failed");
error = clWaitForEvents(1, &eventFree);
test_error(error, "clWaitForEvents failed");
//event info verification for new SVM commands
cl_command_type commandType;
for (auto &check_event : eventMemFillList) {
error = clGetEventInfo(check_event, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MEMFILL)
{
log_error("Invalid command type returned for clEnqueueSVMMemFill\n");
return TEST_FAIL;
}
}
error = clGetEventInfo(eventMemcpy, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MEMCPY)
{
log_error("Invalid command type returned for clEnqueueSVMMemcpy\n");
return TEST_FAIL;
}
for (size_t map_id = 0; map_id < ARRAY_SIZE(eventMap); map_id++) {
error = clGetEventInfo(eventMap[map_id], CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_MAP)
{
log_error("Invalid command type returned for clEnqueueSVMMap\n");
return TEST_FAIL;
}
error = clGetEventInfo(eventUnmap[map_id], CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_UNMAP)
{
log_error("Invalid command type returned for clEnqueueSVMUnmap\n");
return TEST_FAIL;
}
}
error = clGetEventInfo(eventFree, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
test_error(error, "clGetEventInfo failed");
if (commandType != CL_COMMAND_SVM_FREE)
{
log_error("Invalid command type returned for clEnqueueSVMFree\n");
return TEST_FAIL;
}
}
}
std::vector<void *> buffers(numSVMBuffers, 0);
for(size_t i = 0; i < numSVMBuffers; ++i) buffers[i] = clSVMAlloc(context, CL_MEM_READ_WRITE, elementNum, 0);
//verify if callback is triggered correctly
CallbackData data;
data.status = 0;
error = clEnqueueSVMFree(queue, buffers.size(), &buffers[0], callback_svm_free, &data, 0, 0, 0);
test_error(error, "clEnqueueSVMFree failed");
error = clFinish(queue);
test_error(error, "clFinish failed");
//wait for the callback
while(data.status.load(std::memory_order_acquire) == 0) {
usleep(1);
}
//check if number of SVM pointers returned in the callback matches with expected
if (data.num_svm_pointers != buffers.size())
{
log_error("Invalid number of SVM pointers returned in the callback, "
"expected: %zu, got: %d\n",
buffers.size(), data.num_svm_pointers);
return TEST_FAIL;
}
//check if pointers returned in callback are correct
for (size_t i = 0; i < buffers.size(); ++i)
{
if (data.svm_pointers[i] != buffers[i])
{
log_error("Invalid SVM pointer returned in the callback, idx: %zu\n",
i);
return TEST_FAIL;
}
}
return 0;
return 0;
}