From a31589412f740df74c364b48bd4ccabce44e540b Mon Sep 17 00:00:00 2001 From: Michael Rizkalla Date: Tue, 14 Oct 2025 16:48:20 +0100 Subject: [PATCH] Implement negative tests for cl_command_queue functions (#2505) This change adds negative tests to `cl_command_queue`-related APIs: - clCreateCommandQueue - clCreateCommandQueueWithProperties - clSetDefaultDeviceCommandQueue - clRetainCommandQueue - clReleaseCommandQueue - clGetCommandQueueInfo - clSetCommandQueueProperty Signed-off-by: Michael Rizkalla Co-authored-by: Chetankumar Mistry Co-authored-by: Ahmed Hesham --- test_conformance/api/negative_queue.cpp | 455 ++++++++++++++++++++---- 1 file changed, 390 insertions(+), 65 deletions(-) diff --git a/test_conformance/api/negative_queue.cpp b/test_conformance/api/negative_queue.cpp index c25b571d..7da68b32 100644 --- a/test_conformance/api/negative_queue.cpp +++ b/test_conformance/api/negative_queue.cpp @@ -16,92 +16,184 @@ #include "testBase.h" #include "harness/typeWrappers.h" +#include + REGISTER_TEST(negative_create_command_queue) { - cl_command_queue_properties device_props = 0; - cl_int error = clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, - sizeof(device_props), &device_props, NULL); - test_error(error, "clGetDeviceInfo for CL_DEVICE_QUEUE_PROPERTIES failed"); + cl_int err = 0; + clCreateCommandQueue(nullptr, device, 0, &err); + test_failure_error_ret( + err, CL_INVALID_CONTEXT, + "clCreateCommandQueue should return CL_INVALID_CONTEXT when: \"context " + "is not a valid context\" using a nullptr", + TEST_FAIL); - // CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE is the only optional property to - // clCreateCommandQueue, CL_QUEUE_PROFILING_ENABLE is mandatory. - const bool out_of_order_device_support = - device_props & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE; - if (out_of_order_device_support) + clCreateCommandQueue(context, nullptr, 0, &err); + test_failure_error_ret( + err, CL_INVALID_DEVICE, + "clCreateCommandQueue should return CL_INVALID_DEVICE when: \"device " + "is not a valid device\" using a nullptr", + TEST_FAIL); + + cl_device_id different_device = GetOpposingDevice(device); + if (different_device && device != different_device) { - // Early return as we can't check correct error is returned for - // unsupported property. - return TEST_PASS; + clCreateCommandQueue(context, different_device, 0, &err); + test_failure_error_ret( + err, CL_INVALID_DEVICE, + "clCreateCommandQueue should return CL_INVALID_DEVICE when: " + "\"device is not associated with context\"", + TEST_FAIL); } - // Try create a command queue with out-of-order property and check return - // code - cl_int test_error = CL_SUCCESS; - clCommandQueueWrapper test_queue = clCreateCommandQueue( - context, device, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, &test_error); - + cl_queue_properties invalid_property{ static_cast( + -1) }; + clCreateCommandQueue(context, device, invalid_property, &err); test_failure_error_ret( - test_error, CL_INVALID_QUEUE_PROPERTIES, - "clCreateCommandQueue should return CL_INVALID_QUEUE_PROPERTIES if " - "values specified in properties are valid but are not supported by " - "the " - "device.", + err, CL_INVALID_VALUE, + "clCreateCommandQueue should return CL_INVALID_VALUE when: \"values " + "specified in properties are not valid\"", TEST_FAIL); + + cl_command_queue_properties device_queue_properties = 0; + err = clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, + sizeof(device_queue_properties), + &device_queue_properties, nullptr); + test_error(err, "clGetDeviceInfo"); + cl_command_queue_properties valid_properties[] = { + CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, CL_QUEUE_PROFILING_ENABLE + }; + cl_queue_properties property{ 0 }; + bool missing_property = false; + // Iterate through all possible properties to find one which isn't supported + for (auto prop : valid_properties) + { + if ((device_queue_properties & prop) == 0) + { + missing_property = true; + property = prop; + break; + } + } + // This test can only run when a device does not support a property + if (missing_property) + { + clCreateCommandQueue(context, device, property, &err); + test_failure_error_ret( + err, CL_INVALID_QUEUE_PROPERTIES, + "clCreateCommandQueue should return CL_INVALID_QUEUE_PROPERTIES " + "when: \"values specified in properties are valid but are not " + "supported by the device\"", + TEST_FAIL); + } + return TEST_PASS; } REGISTER_TEST_VERSION(negative_create_command_queue_with_properties, Version(2, 0)) { - cl_command_queue_properties device_props = 0; - cl_int error = clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, - sizeof(device_props), &device_props, NULL); - test_error(error, "clGetDeviceInfo for CL_DEVICE_QUEUE_PROPERTIES failed"); + cl_int err = 0; + clCreateCommandQueueWithProperties(nullptr, device, nullptr, &err); + test_failure_error_ret( + err, CL_INVALID_CONTEXT, + "clCreateCommandQueueWithProperties should return CL_INVALID_CONTEXT " + "when: \"context is not a valid context\" using a nullptr", + TEST_FAIL); - cl_command_queue_properties device_on_host_props = 0; - error = clGetDeviceInfo(device, CL_DEVICE_QUEUE_ON_HOST_PROPERTIES, - sizeof(device_on_host_props), &device_on_host_props, - NULL); - test_error(error, - "clGetDeviceInfo for CL_DEVICE_QUEUE_ON_HOST_PROPERTIES failed"); + clCreateCommandQueueWithProperties(context, nullptr, nullptr, &err); + test_failure_error_ret( + err, CL_INVALID_DEVICE, + "clCreateCommandQueueWithProperties should return CL_INVALID_DEVICE " + "when: \"device is not a valid device\" using a nullptr", + TEST_FAIL); - if (device_on_host_props != device_props) + cl_device_id different_device = GetOpposingDevice(device); + if (different_device && device != different_device) { - log_error( - "ERROR: CL_DEVICE_QUEUE_PROPERTIES and " - "CL_DEVICE_QUEUE_ON_HOST_PROPERTIES properties should match\n"); - return TEST_FAIL; + clCreateCommandQueueWithProperties(context, different_device, nullptr, + &err); + test_failure_error_ret( + err, CL_INVALID_DEVICE, + "clCreateCommandQueueWithProperties should return " + "CL_INVALID_DEVICE when: \"device is not associated with context\"", + TEST_FAIL); } - // CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE is the only optional host-queue - // property to clCreateCommandQueueWithProperties, - // CL_QUEUE_PROFILING_ENABLE is mandatory. - const bool out_of_order_device_support = - device_props & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE; - if (out_of_order_device_support) - { - // Early return as we can't check correct error is returned for - // unsupported property. - return TEST_PASS; - } + cl_queue_properties invalid_property{ static_cast( + -1) }; - // Try create a command queue with out-of-order property and check return - // code - cl_command_queue_properties queue_prop_def[] = { - CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, 0 + // Depending on the OpenCL Version, there can be up to 2 properties which + // each take values, and the list should be terminated with a 0 + cl_queue_properties properties[] = { invalid_property, invalid_property, 0, + 0, 0 }; + clCreateCommandQueueWithProperties(context, device, properties, &err); + test_failure_error_ret( + err, CL_INVALID_VALUE, + "clCreateCommandQueueWithProperties should return CL_INVALID_VALUE " + "when: \"values specified in properties are not valid\"", + TEST_FAIL); + + cl_command_queue_properties device_queue_properties = 0; + err = clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, + sizeof(device_queue_properties), + &device_queue_properties, nullptr); + test_error(err, "clGetDeviceInfo"); + cl_command_queue_properties valid_properties[] = { + CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, CL_QUEUE_PROFILING_ENABLE }; - - cl_int test_error = CL_SUCCESS; - clCommandQueueWrapper test_queue = clCreateCommandQueueWithProperties( - context, device, queue_prop_def, &test_error); - - test_failure_error_ret(test_error, CL_INVALID_QUEUE_PROPERTIES, - "clCreateCommandQueueWithProperties should " - "return CL_INVALID_QUEUE_PROPERTIES if " - "values specified in properties are valid but " - "are not supported by the " - "device.", - TEST_FAIL); + properties[0] = CL_QUEUE_PROPERTIES; + bool missing_property = false; + // Iterate through all possible properties to find one which isn't supported + for (auto property : valid_properties) + { + if ((device_queue_properties & property) == 0) + { + missing_property = true; + properties[1] = property; + break; + } + } + if (missing_property) + { + clCreateCommandQueueWithProperties(context, device, properties, &err); + test_failure_error_ret( + err, CL_INVALID_QUEUE_PROPERTIES, + "clCreateCommandQueueWithProperties should return " + "CL_INVALID_QUEUE_PROPERTIES when: \"values specified in " + "properties are valid but are not supported by the device\"", + TEST_FAIL); + } + else if (get_device_cl_version(device) >= Version(2, 0)) + { + cl_uint max_size = -1; + err = clGetDeviceInfo(device, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, + sizeof(max_size), &max_size, nullptr); + test_error(err, "clGetDeviceInfo"); + if (max_size > 0 && max_size < CL_UINT_MAX) + { + properties[0] = CL_QUEUE_PROPERTIES; + properties[1] = + CL_QUEUE_ON_DEVICE | CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE; + properties[2] = CL_QUEUE_SIZE; + properties[3] = max_size + 1; + clCreateCommandQueueWithProperties(context, device, properties, + &err); + if (err != CL_INVALID_VALUE && err != CL_INVALID_QUEUE_PROPERTIES) + { + log_error("ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clCreateCommandQueueWithProperties should return " + "CL_INVALID_VALUE or CL_INVALID_QUEUE_PROPERTIES " + "when: \"values specified in properties are not " + "valid\" using a queue size greather than " + "CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE", + IGetErrorString(err), + "CL_INVALID_VALUE or CL_INVALID_QUEUE_PROPERTIES", + __FILE__, __LINE__); + return TEST_FAIL; + } + } + } return TEST_PASS; } @@ -166,3 +258,236 @@ REGISTER_TEST(negative_create_command_queue_with_properties_khr) TEST_FAIL); return TEST_PASS; } + +REGISTER_TEST_VERSION(negative_set_default_device_command_queue, Version(2, 1)) +{ + cl_int err = 0; + if (get_device_cl_version(device) >= Version(3, 0)) + { + cl_device_device_enqueue_capabilities device_capabilities = 0; + cl_int err = clGetDeviceInfo( + device, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, + sizeof(device_capabilities), &device_capabilities, nullptr); + test_error(err, "clGetDeviceInfo"); + if (((device_capabilities & CL_DEVICE_QUEUE_REPLACEABLE_DEFAULT) == 0) + && ((device_capabilities & CL_DEVICE_QUEUE_SUPPORTED) == 1)) + { + const cl_queue_properties properties[] = { + CL_QUEUE_PROPERTIES, + CL_QUEUE_ON_DEVICE_DEFAULT | CL_QUEUE_ON_DEVICE + | CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, + 0 + }; + clCommandQueueWrapper cmd_queue = + clCreateCommandQueueWithProperties(context, device, properties, + &err); + test_error(err, "clCreateCommandQueueWithProperties"); + err = clSetDefaultDeviceCommandQueue(context, device, cmd_queue); + test_failure_error_ret( + err, CL_INVALID_OPERATION, + "clSetDefaultDeviceCommandQueue should return " + "CL_INVALID_OPERATION when \"device does not support a " + "replaceable default on-device queue\"", + TEST_FAIL); + } + } + + err = clSetDefaultDeviceCommandQueue(nullptr, device, queue); + if (err != CL_INVALID_OPERATION && err != CL_INVALID_CONTEXT) + { + log_error("ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clSetDefaultDeviceCommandQueue should return " + "CL_INVALID_OPERATION or CL_INVALID_CONTEXT when: \"context " + "is not a valid context\" using a nullptr", + IGetErrorString(err), + "CL_INVALID_OPERATION or CL_INVALID_CONTEXT", __FILE__, + __LINE__); + return TEST_FAIL; + } + + err = clSetDefaultDeviceCommandQueue(context, nullptr, queue); + if (err != CL_INVALID_OPERATION && err != CL_INVALID_DEVICE) + { + log_error("ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clSetDefaultDeviceCommandQueue should return " + "CL_INVALID_OPERATION or CL_INVALID_DEVICE when: \"device " + "is not a valid device\" using a nullptr", + IGetErrorString(err), + "CL_INVALID_OPERATION or CL_INVALID_DEVICE", __FILE__, + __LINE__); + return TEST_FAIL; + } + + cl_device_id different_device = GetOpposingDevice(device); + if (different_device && device != different_device) + { + err = clSetDefaultDeviceCommandQueue(context, different_device, queue); + if (err != CL_INVALID_OPERATION && err != CL_INVALID_DEVICE) + { + log_error("ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clSetDefaultDeviceCommandQueue should return " + "CL_INVALID_OPERATION or CL_INVALID_DEVICE when: " + "\"device is not associated with context\"", + IGetErrorString(err), + "CL_INVALID_OPERATION or CL_INVALID_DEVICE", __FILE__, + __LINE__); + return TEST_FAIL; + } + } + err = clSetDefaultDeviceCommandQueue(context, device, nullptr); + if (err != CL_INVALID_OPERATION && err != CL_INVALID_COMMAND_QUEUE) + { + log_error( + "ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clSetDefaultDeviceCommandQueue should return CL_INVALID_OPERATION " + "or CL_INVALID_COMMAND_QUEUE when: \"command_queue is not a valid " + "command-queue for device\" using a nullptr", + IGetErrorString(err), + "CL_INVALID_OPERATION or CL_INVALID_COMMAND_QUEUE", __FILE__, + __LINE__); + return TEST_FAIL; + } + + { + constexpr cl_queue_properties props[] = { + CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, 0 + }; + clCommandQueueWrapper not_on_device_queue = + clCreateCommandQueueWithProperties(context, device, props, &err); + test_error_fail(err, "clCreateCommandQueueWithProperties failed"); + err = clSetDefaultDeviceCommandQueue(context, device, + not_on_device_queue); + if (err != CL_INVALID_OPERATION && err != CL_INVALID_COMMAND_QUEUE) + { + log_error("ERROR: %s! (Got %s, expected (%s) from %s:%d)\n", + "clSetDefaultDeviceCommandQueue should return " + "CL_INVALID_OPERATION or CL_INVALID_COMMAND_QUEUE when: " + "\"command_queue is not a valid command-queue for " + "device\" using a command queue that is not on device", + IGetErrorString(err), + "CL_INVALID_OPERATION or CL_INVALID_COMMAND_QUEUE", + __FILE__, __LINE__); + } + } + + return TEST_PASS; +} + +REGISTER_TEST(negative_retain_command_queue) +{ + cl_int err = clRetainCommandQueue(nullptr); + test_failure_error_ret( + err, CL_INVALID_COMMAND_QUEUE, + "clRetainCommandQueue should return CL_INVALID_COMMAND_QUEUE when: " + "\"command_queue is not a valid command-queue\" using a nullptr", + TEST_FAIL); + + return TEST_PASS; +} + +REGISTER_TEST(negative_release_command_queue) +{ + cl_int err = clReleaseCommandQueue(nullptr); + test_failure_error_ret( + err, CL_INVALID_COMMAND_QUEUE, + "clReleaseCommandQueue should return CL_INVALID_COMMAND_QUEUE when: " + "\"command_queue is not a valid command-queue\" using a nullptr", + TEST_FAIL); + + return TEST_PASS; +} + +static bool device_supports_on_device_queue(cl_device_id deviceID) +{ + cl_command_queue_properties device_queue_properties = 0; + if (get_device_cl_version(deviceID) >= Version(2, 0)) + { + cl_int err = clGetDeviceInfo( + deviceID, CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, + sizeof(device_queue_properties), &device_queue_properties, nullptr); + test_error(err, "clGetDeviceInfo"); + return (device_queue_properties + & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE); + } + return false; +} + +REGISTER_TEST(negative_get_command_queue_info) +{ + cl_int err = + clGetCommandQueueInfo(nullptr, CL_QUEUE_CONTEXT, 0, nullptr, nullptr); + test_failure_error_ret( + err, CL_INVALID_COMMAND_QUEUE, + "clGetCommandQueueInfo should return CL_INVALID_COMMAND_QUEUE when: " + "\"command_queue is not a valid command-queue\" using a nullptr", + TEST_FAIL); + + if (device_supports_on_device_queue(device)) + { + const cl_queue_properties properties[] = { + CL_QUEUE_PROPERTIES, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, 0 + }; + cl_int err = CL_INVALID_VALUE; + clCommandQueueWrapper cmd_queue = clCreateCommandQueueWithProperties( + context, device, properties, &err); + test_error(err, "clCreateCommandQueueWithProperties"); + cl_uint queue_size = -1; + err = clGetCommandQueueInfo(cmd_queue, CL_QUEUE_SIZE, + sizeof(queue_size), &queue_size, nullptr); + test_failure_error_ret(err, CL_INVALID_COMMAND_QUEUE, + "clGetCommandQueueInfo should return " + "CL_INVALID_COMMAND_QUEUE when: \"command_queue " + "is not a valid command-queue for param_name\"", + TEST_FAIL); + } + + constexpr cl_command_queue_info invalid_param = -1; + err = clGetCommandQueueInfo(queue, invalid_param, 0, nullptr, nullptr); + test_failure_error_ret( + err, CL_INVALID_VALUE, + "clGetCommandQueueInfo should return CL_INVALID_VALUE when: " + "\"param_name is not one of the supported values\"", + TEST_FAIL); + + + cl_uint ref_count = -1; + err = clGetCommandQueueInfo(queue, CL_QUEUE_REFERENCE_COUNT, 0, &ref_count, + nullptr); + test_failure_error_ret( + err, CL_INVALID_VALUE, + "clGetCommandQueueInfo should return CL_INVALID_VALUE when: \"size in " + "bytes specified by param_value_size is < size of return type and " + "param_value is not a NULL value\"", + TEST_FAIL); + + return TEST_PASS; +} + +REGISTER_TEST_VERSION(negative_set_command_queue_property, Version(1, 0)) +{ + auto version = get_device_cl_version(device); + if (version >= Version(1, 1)) + { + // Implementations are allowed to return an error for + // non-OpenCL 1.0 devices. In which case, skip the test. + return TEST_SKIPPED_ITSELF; + } + + cl_queue_properties property{ CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE }; + cl_int err = clSetCommandQueueProperty(nullptr, property, CL_TRUE, nullptr); + test_failure_error_ret( + err, CL_INVALID_COMMAND_QUEUE, + "clSetCommandQueueProperty should return CL_INVALID_COMMAND_QUEUE " + "when: \"command_queue is not a valid command-queue\" using a nullptr", + TEST_FAIL); + + property = -1; + err = clSetCommandQueueProperty(queue, property, CL_TRUE, nullptr); + test_failure_error_ret( + err, CL_INVALID_VALUE, + "clSetCommandQueueProperty should return CL_INVALID_VALUE when: " + "\"values specified in properties are not valid\"", + TEST_FAIL); + + return TEST_PASS; +}