From 7fa9ec997e4be676b909c7f474e11a7aec18cc82 Mon Sep 17 00:00:00 2001 From: Marcin Hajder Date: Tue, 18 Jun 2024 09:07:05 +0200 Subject: [PATCH 1/2] Added new test to verify negative results of clGetSemaphoreInfoKHR --- .../cl_khr_semaphore/CMakeLists.txt | 2 + .../extensions/cl_khr_semaphore/main.cpp | 3 + .../extensions/cl_khr_semaphore/procs.h | 6 + .../cl_khr_semaphore/semaphore_base.h | 202 ++++++++++++++++++ .../test_semaphores_negative_getinfo.cpp | 131 ++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 test_conformance/extensions/cl_khr_semaphore/semaphore_base.h create mode 100644 test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp diff --git a/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt b/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt index 824784a135..042eb91b30 100644 --- a/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt +++ b/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt @@ -3,6 +3,8 @@ set(MODULE_NAME CL_KHR_SEMAPHORE) set(${MODULE_NAME}_SOURCES main.cpp test_semaphores.cpp + test_semaphores_negative_getinfo.cpp + semaphore_base.h ) include(../../CMakeCommon.txt) diff --git a/test_conformance/extensions/cl_khr_semaphore/main.cpp b/test_conformance/extensions/cl_khr_semaphore/main.cpp index 0ae7206a0d..040343eaa1 100644 --- a/test_conformance/extensions/cl_khr_semaphore/main.cpp +++ b/test_conformance/extensions/cl_khr_semaphore/main.cpp @@ -35,6 +35,9 @@ test_definition test_list[] = { ADD_TEST_VERSION(semaphores_multi_wait, Version(1, 2)), ADD_TEST_VERSION(semaphores_queries, Version(1, 2)), ADD_TEST_VERSION(semaphores_import_export_fd, Version(1, 2)), + ADD_TEST_VERSION(semaphores_negative_get_info_invalid_semaphore, + Version(1, 2)), + ADD_TEST_VERSION(semaphores_negative_get_info_invalid_value, Version(1, 2)), }; const int test_num = ARRAY_SIZE(test_list); diff --git a/test_conformance/extensions/cl_khr_semaphore/procs.h b/test_conformance/extensions/cl_khr_semaphore/procs.h index f7c1aaa301..0688eee3a3 100644 --- a/test_conformance/extensions/cl_khr_semaphore/procs.h +++ b/test_conformance/extensions/cl_khr_semaphore/procs.h @@ -45,3 +45,9 @@ extern int test_semaphores_import_export_fd(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements); +extern int test_semaphores_negative_get_info_invalid_semaphore( + cl_device_id device, cl_context context, cl_command_queue queue, + int num_elements); +extern int test_semaphores_negative_get_info_invalid_value( + cl_device_id device, cl_context context, cl_command_queue queue, + int num_elements); diff --git a/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h b/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h new file mode 100644 index 0000000000..e50f33aedd --- /dev/null +++ b/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h @@ -0,0 +1,202 @@ +// +// Copyright (c) 2024 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CL_KHR_SEMAPHORE_BASE_H +#define CL_KHR_SEMAPHORE_BASE_H + +#include +#include "harness/deviceInfo.h" +#include "harness/testHarness.h" + +#include "harness/typeWrappers.h" + +struct SemaphoreBase +{ + SemaphoreBase(cl_device_id device): device(device) {} + + cl_int init_extension_functions() + { + cl_platform_id platform; + cl_int error = + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), + &platform, nullptr); + test_error(error, "clGetDeviceInfo for CL_DEVICE_PLATFORM failed"); + + // If it is supported get the addresses of all the APIs here. + // clang-format off +#define GET_EXTENSION_ADDRESS(FUNC) \ + FUNC = reinterpret_cast( \ + clGetExtensionFunctionAddressForPlatform(platform, #FUNC)); \ + if (FUNC == nullptr) \ + { \ + log_error("ERROR: clGetExtensionFunctionAddressForPlatform failed" \ + " with " #FUNC "\n"); \ + return TEST_FAIL; \ + } + // clang-format on + + GET_EXTENSION_ADDRESS(clCreateSemaphoreWithPropertiesKHR); + GET_EXTENSION_ADDRESS(clEnqueueSignalSemaphoresKHR); + GET_EXTENSION_ADDRESS(clEnqueueWaitSemaphoresKHR); + GET_EXTENSION_ADDRESS(clReleaseSemaphoreKHR); + GET_EXTENSION_ADDRESS(clGetSemaphoreInfoKHR); + GET_EXTENSION_ADDRESS(clRetainSemaphoreKHR); + GET_EXTENSION_ADDRESS(clGetSemaphoreHandleForTypeKHR); + +#undef GET_EXTENSION_ADDRESS + return CL_SUCCESS; + } + + clCreateSemaphoreWithPropertiesKHR_fn clCreateSemaphoreWithPropertiesKHR = + nullptr; + clEnqueueSignalSemaphoresKHR_fn clEnqueueSignalSemaphoresKHR = nullptr; + clEnqueueWaitSemaphoresKHR_fn clEnqueueWaitSemaphoresKHR = nullptr; + clReleaseSemaphoreKHR_fn clReleaseSemaphoreKHR = nullptr; + clGetSemaphoreInfoKHR_fn clGetSemaphoreInfoKHR = nullptr; + clRetainSemaphoreKHR_fn clRetainSemaphoreKHR = nullptr; + clGetSemaphoreHandleForTypeKHR_fn clGetSemaphoreHandleForTypeKHR = nullptr; + + cl_device_id device = nullptr; +}; + +// Wrapper class based off generic typeWrappers.h wrappers. However, because +// the release/retain functions are queried at runtime from the platform, +// rather than known at compile time we cannot link the instantiated template. +// Instead, pass an instance of `SemaphoreTestBase` on wrapper construction +// to access the release/retain functions. +class clSemaphoreWrapper { + cl_semaphore_khr object = nullptr; + + void retain() + { + if (!object) return; + + auto err = base->clRetainSemaphoreKHR(object); + if (err != CL_SUCCESS) + { + print_error(err, "clRetainCommandBufferKHR() failed"); + std::abort(); + } + } + + void release() + { + if (!object) return; + + auto err = base->clReleaseSemaphoreKHR(object); + if (err != CL_SUCCESS) + { + print_error(err, "clReleaseCommandBufferKHR() failed"); + std::abort(); + } + } + + // Used to access release/retain functions + SemaphoreBase *base; + +public: + // We always want to have base available to dereference + clSemaphoreWrapper() = delete; + + clSemaphoreWrapper(SemaphoreBase *base): base(base) {} + + // On assignment, assume the object has a refcount of one. + clSemaphoreWrapper &operator=(cl_semaphore_khr rhs) + { + reset(rhs); + return *this; + } + + // Copy semantics, increase retain count. + clSemaphoreWrapper(clSemaphoreWrapper const &w) { *this = w; } + clSemaphoreWrapper &operator=(clSemaphoreWrapper const &w) + { + reset(w.object); + retain(); + return *this; + } + + // Move semantics, directly take ownership. + clSemaphoreWrapper(clSemaphoreWrapper &&w) { *this = std::move(w); } + clSemaphoreWrapper &operator=(clSemaphoreWrapper &&w) + { + reset(w.object); + w.object = nullptr; + return *this; + } + + ~clSemaphoreWrapper() { reset(); } + + // Release the existing object, if any, and own the new one, if any. + void reset(cl_semaphore_khr new_object = nullptr) + { + release(); + object = new_object; + } + + operator cl_semaphore_khr() const { return object; } + operator const cl_semaphore_khr *() { return &object; } +}; + +struct SemaphoreTestBase : public SemaphoreBase +{ + SemaphoreTestBase(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreBase(device), context(context), semaphore(this) + { + cl_int error = init_extension_functions(); + if (error != CL_SUCCESS) + throw std::runtime_error("init_extension_functions failed\n"); + + error = clRetainCommandQueue(queue); + if (error != CL_SUCCESS) + throw std::runtime_error("clRetainCommandQueue failed\n"); + this->queue = queue; + } + + virtual cl_int Run() = 0; + +protected: + cl_context context = nullptr; + clCommandQueueWrapper queue = nullptr; + clSemaphoreWrapper semaphore = nullptr; +}; + +template +int MakeAndRunTest(cl_device_id device, cl_context context, + cl_command_queue queue) +{ + if (!is_extension_available(device, "cl_khr_semaphore")) + { + log_info( + "Device does not support 'cl_khr_semaphore'. Skipping the test.\n"); + return TEST_SKIPPED_ITSELF; + } + + cl_int status = TEST_PASS; + try + { + auto test_fixture = T(device, context, queue); + status = test_fixture.Run(); + } catch (const std::runtime_error &e) + { + log_error("%s", e.what()); + return TEST_FAIL; + } + + return status; +} + +#endif // CL_KHR_SEMAPHORE_BASE_H diff --git a/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp new file mode 100644 index 0000000000..f40c9ccffa --- /dev/null +++ b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp @@ -0,0 +1,131 @@ +// +// Copyright (c) 2024 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "semaphore_base.h" + +#include "harness/errorHelpers.h" + +namespace { + +// sema_object is not a valid semaphore. + +struct GetInfoInvalidSemaphore : public SemaphoreTestBase +{ + GetInfoInvalidSemaphore(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreTestBase(device, context, queue) + {} + + cl_int Run() override + { + // Wait semaphore + cl_semaphore_type_khr type = 0; + size_t ret_size = 0; + cl_int err = clGetSemaphoreInfoKHR(nullptr, CL_SEMAPHORE_TYPE_KHR, + sizeof(cl_semaphore_type_khr), &type, + &ret_size); + test_failure_error(err, CL_INVALID_SEMAPHORE_KHR, + "Unexpected clGetSemaphoreInfoKHR return"); + + return CL_SUCCESS; + } +}; + +// 1) param_name is not one of the attribute defined in the Semaphore Queries +// table + +// 2) param_value_size is less than the size of Return Type of the corresponding +// param_name attribute as defined in the Semaphore Queries table. + +struct GetInfoInvalidValue : public SemaphoreTestBase +{ + GetInfoInvalidValue(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreTestBase(device, context, queue) + {} + + cl_int Run() override + { + // Create semaphore + cl_semaphore_properties_khr sema_props[] = { + static_cast(CL_SEMAPHORE_TYPE_KHR), + static_cast( + CL_SEMAPHORE_TYPE_BINARY_KHR), + static_cast( + CL_SEMAPHORE_DEVICE_HANDLE_LIST_KHR), + (cl_semaphore_properties_khr)device, + CL_SEMAPHORE_DEVICE_HANDLE_LIST_END_KHR, + 0 + }; + + cl_int err = CL_SUCCESS; + semaphore = + clCreateSemaphoreWithPropertiesKHR(context, sema_props, &err); + test_error(err, "Could not create semaphore"); + + // (1) + cl_semaphore_info_khr param_name = ~0; + err = clGetSemaphoreInfoKHR(semaphore, param_name, 0, nullptr, nullptr); + test_failure_error(err, CL_INVALID_VALUE, + "Unexpected clGetSemaphoreInfoKHR return"); + + // (2) + size_t size = 0; + err = clGetSemaphoreInfoKHR(semaphore, CL_SEMAPHORE_PROPERTIES_KHR, 0, + nullptr, &size); + test_error(err, "Could not query semaphore"); + + // make sure that first test provides too small param size + if (size != sizeof(sema_props) + && size <= sizeof(cl_semaphore_properties_khr)) + test_fail("Error: expected size %d, returned %d", + sizeof(sema_props), size); + + // first test with non-zero property size but not enough + cl_semaphore_properties_khr ret_props = 0; + err = clGetSemaphoreInfoKHR(semaphore, CL_SEMAPHORE_PROPERTIES_KHR, + sizeof(ret_props), &ret_props, nullptr); + test_failure_error(err, CL_INVALID_VALUE, + "Unexpected clGetSemaphoreInfoKHR return"); + + // second test with zero property size + cl_semaphore_type_khr type = 0; + err = clGetSemaphoreInfoKHR(semaphore, CL_SEMAPHORE_TYPE_KHR, 0, &type, + nullptr); + test_failure_error(err, CL_INVALID_VALUE, + "Unexpected clGetSemaphoreInfoKHR return"); + + return CL_SUCCESS; + } +}; + +} + +int test_semaphores_negative_get_info_invalid_semaphore(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + return MakeAndRunTest(device, context, queue); +} + +int test_semaphores_negative_get_info_invalid_value(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + return MakeAndRunTest(device, context, queue); +} From 1dbe7eab368b2734410bd9dbf7cb3061d3c14a9b Mon Sep 17 00:00:00 2001 From: Marcin Hajder Date: Thu, 4 Jul 2024 20:06:41 +0200 Subject: [PATCH 2/2] Correction related to code review --- .../cl_khr_semaphore/test_semaphores_negative_getinfo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp index f40c9ccffa..0cf8bb0faf 100644 --- a/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp +++ b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_getinfo.cpp @@ -89,8 +89,7 @@ struct GetInfoInvalidValue : public SemaphoreTestBase test_error(err, "Could not query semaphore"); // make sure that first test provides too small param size - if (size != sizeof(sema_props) - && size <= sizeof(cl_semaphore_properties_khr)) + if (size != sizeof(sema_props)) test_fail("Error: expected size %d, returned %d", sizeof(sema_props), size);