From 33285facbebf54e7357d93c08842a8db155279c3 Mon Sep 17 00:00:00 2001 From: Marcin Hajder Date: Fri, 3 Mar 2023 09:20:46 +0100 Subject: [PATCH] Command buffer event sync (#1606) * Added initial commit for event sync test cases (issue #1369, p.3.3) * Added test cases for return event scenarios with and without out-of-order, work in progress (#1369, p.3.3) * Added support for return event test cases for both regular and out-of-order command queue (#1369, p.3.3) * Added user event test cases, cosmetic corrections (#1369, p.3.3) * Added correction for windows build (#1369, p.3.3) * Corrected proper testing of test fail/skip conditions (#1369, p.3.3) * Added corrections related to PR review (#1369, p.3.3) * Added correction related to change of order Skip/SetUp (issue #1369, event sync) * Added clang format correction for previous commit * Reordered initialization of attributes. --- .../cl_khr_command_buffer/CMakeLists.txt | 1 + .../basic_command_buffer.cpp | 59 +- .../command_buffer_event_sync.cpp | 1040 +++++++++++++++++ .../extensions/cl_khr_command_buffer/main.cpp | 62 +- .../extensions/cl_khr_command_buffer/procs.h | 34 +- 5 files changed, 1115 insertions(+), 81 deletions(-) create mode 100644 test_conformance/extensions/cl_khr_command_buffer/command_buffer_event_sync.cpp diff --git a/test_conformance/extensions/cl_khr_command_buffer/CMakeLists.txt b/test_conformance/extensions/cl_khr_command_buffer/CMakeLists.txt index 097a197c..5a4f82d5 100644 --- a/test_conformance/extensions/cl_khr_command_buffer/CMakeLists.txt +++ b/test_conformance/extensions/cl_khr_command_buffer/CMakeLists.txt @@ -3,6 +3,7 @@ set(MODULE_NAME CL_KHR_COMMAND_BUFFER) set(${MODULE_NAME}_SOURCES main.cpp basic_command_buffer.cpp + command_buffer_event_sync.cpp command_buffer_out_of_order.cpp command_buffer_profiling.cpp command_buffer_queue_substitution.cpp diff --git a/test_conformance/extensions/cl_khr_command_buffer/basic_command_buffer.cpp b/test_conformance/extensions/cl_khr_command_buffer/basic_command_buffer.cpp index 4a892bb3..43734da0 100644 --- a/test_conformance/extensions/cl_khr_command_buffer/basic_command_buffer.cpp +++ b/test_conformance/extensions/cl_khr_command_buffer/basic_command_buffer.cpp @@ -53,7 +53,6 @@ bool BasicCommandBufferTest::Skip() "CL_DEVICE_COMMAND_BUFFER_REQUIRED_QUEUE_PROPERTIES_KHR"); cl_command_queue_properties queue_properties; - error = clGetCommandQueueInfo(queue, CL_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, NULL); @@ -145,6 +144,11 @@ cl_int BasicCommandBufferTest::SetUp(int elements) { return error; } + + if (elements <= 0) + { + return CL_INVALID_VALUE; + } num_elements = static_cast(elements); error = SetUpKernel(); @@ -270,53 +274,6 @@ struct MixedCommandsTest : public BasicCommandBufferTest } }; -// Test enqueueing a command-buffer blocked on a user-event -struct UserEventTest : public BasicCommandBufferTest -{ - using BasicCommandBufferTest::BasicCommandBufferTest; - - cl_int Run() override - { - cl_int error = clCommandNDRangeKernelKHR( - command_buffer, nullptr, nullptr, kernel, 1, nullptr, &num_elements, - nullptr, 0, nullptr, nullptr, nullptr); - test_error(error, "clCommandNDRangeKernelKHR failed"); - - error = clFinalizeCommandBufferKHR(command_buffer); - test_error(error, "clFinalizeCommandBufferKHR failed"); - - clEventWrapper user_event = clCreateUserEvent(context, &error); - test_error(error, "clCreateUserEvent failed"); - - const cl_int pattern = 42; - error = clEnqueueFillBuffer(queue, in_mem, &pattern, sizeof(cl_int), 0, - data_size(), 0, nullptr, nullptr); - test_error(error, "clEnqueueFillBuffer failed"); - - error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer, 1, - &user_event, nullptr); - test_error(error, "clEnqueueCommandBufferKHR failed"); - - std::vector output_data(num_elements); - error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), - output_data.data(), 0, nullptr, nullptr); - test_error(error, "clEnqueueReadBuffer failed"); - - error = clSetUserEventStatus(user_event, CL_COMPLETE); - test_error(error, "clSetUserEventStatus failed"); - - error = clFinish(queue); - test_error(error, "clFinish failed"); - - for (size_t i = 0; i < num_elements; i++) - { - CHECK_VERIFICATION_ERROR(pattern, output_data[i], i); - } - - return CL_SUCCESS; - } -}; - // Test flushing the command-queue between command-buffer enqueues struct ExplicitFlushTest : public BasicCommandBufferTest { @@ -472,9 +429,3 @@ int test_explicit_flush(cl_device_id device, cl_context context, return MakeAndRunTest(device, context, queue, num_elements); } - -int test_user_events(cl_device_id device, cl_context context, - cl_command_queue queue, int num_elements) -{ - return MakeAndRunTest(device, context, queue, num_elements); -} diff --git a/test_conformance/extensions/cl_khr_command_buffer/command_buffer_event_sync.cpp b/test_conformance/extensions/cl_khr_command_buffer/command_buffer_event_sync.cpp new file mode 100644 index 00000000..be8530b2 --- /dev/null +++ b/test_conformance/extensions/cl_khr_command_buffer/command_buffer_event_sync.cpp @@ -0,0 +1,1040 @@ +// +// Copyright (c) 2022 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 "basic_command_buffer.h" +#include "procs.h" + +#include + +//-------------------------------------------------------------------------- +enum class EventMode +{ + RET_REGULAR_WAIT_FOR_COMBUF = 0, + RET_COMBUF_WAIT_FOR_COMBUF, + RET_COMBUF_WAIT_FOR_SEC_COMBUF, + RET_EVENT_CALLBACK, + RET_CLWAITFOREVENTS_SINGLE, + RET_CLWAITFOREVENTS, + RET_COMBUF_WAIT_FOR_REGULAR, + RET_WAIT_FOR_SEC_QUEUE_EVENT, + USER_EVENT_WAIT, + USER_EVENTS_WAIT, + USER_EVENT_CALLBACK +}; + +//-------------------------------------------------------------------------- +void CL_CALLBACK combuf_event_callback_function(cl_event event, + cl_int commandStatus, + void *userData) +{ + bool *pdata = static_cast(userData); + log_info("\tEvent callback of clEnqueueCommandBufferKHR triggered\n"); + *pdata = true; +} + +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// event sync test cases for cl_khr_command_buffer which handles: +// -test that an event returned by a command-buffer enqueue can be waited on by +// regular commands +// -test that an event returned by a command-buffer enqueue can +// be waited on an enqueue of the same command-buffer +// -tests that a command buffer enqueue can wait on the enqueue of a different +// command buffer +// -test clSetEventCallback works correctly on an event returned by +// clEnqueueCommandBufferKHR +// -test clWaitForEvents on a single event returned from a +// clEnqueueCommandBufferKHR +// -test clWaitForEvents on multiple events returned from different +// clEnqueueCommandBufferKHR calls + + +// +// +// -test clSetEventCallback works correctly on an user defined event waited by +// clEnqueueCommandBufferKHR +// +// + +template +struct CommandBufferEventSync : public BasicCommandBufferTest +{ + CommandBufferEventSync(cl_device_id device, cl_context context, + cl_command_queue queue) + : BasicCommandBufferTest(device, context, queue), + command_buffer_sec(this), kernel_sec(nullptr), in_mem_sec(nullptr), + out_mem_sec(nullptr), off_mem_sec(nullptr), test_event(nullptr) + { + simultaneous_use_requested = + (event_mode == EventMode::RET_COMBUF_WAIT_FOR_COMBUF) ? true + : false; + } + + //-------------------------------------------------------------------------- + cl_int SetUpKernel() override + { + cl_int error = BasicCommandBufferTest::SetUpKernel(); + test_error(error, "BasicCommandBufferTest::SetUpKernel failed"); + + // due to possible out-of-order command queue copy the kernel for below + // case scenarios + if (event_mode == EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF + || event_mode == EventMode::RET_CLWAITFOREVENTS) + { + kernel_sec = clCreateKernel(program, "copy", &error); + test_error(error, "Failed to create copy kernel"); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int SetUpKernelArgs() override + { + // due to possible out-of-order command queue it is necessary to create + // separate set of kernel args for below cases + if (event_mode == EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF + || event_mode == EventMode::RET_CLWAITFOREVENTS) + { + // setup arguments for secondary kernel + std::swap(kernel, kernel_sec); + + cl_int error = BasicCommandBufferTest::SetUpKernelArgs(); + test_error(error, "BasicCommandBufferTest::SetUpKernel failed"); + + // swap arguments for base class setup + in_mem_sec = in_mem; + out_mem_sec = out_mem; + off_mem_sec = off_mem; + std::swap(kernel, kernel_sec); + } + + cl_int error = BasicCommandBufferTest::SetUpKernelArgs(); + test_error(error, "BasicCommandBufferTest::SetUpKernel failed"); + + if (out_of_order_requested && out_of_order_support) + { + queue = clCreateCommandQueue(context, device, + CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, + &error); + test_error(error, "Unable to create command queue to test with"); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int SetUp(int elements) override + { + cl_int error = BasicCommandBufferTest::SetUp(elements); + test_error(error, "BasicCommandBufferTest::SetUp failed"); + + if (event_mode == EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF + || event_mode == EventMode::RET_CLWAITFOREVENTS) + { + command_buffer_sec = + clCreateCommandBufferKHR(1, &queue, nullptr, &error); + test_error(error, "clCreateCommandBufferKHR failed"); + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + bool Skip() override + { + if (BasicCommandBufferTest::Skip()) return true; + + if (simultaneous_use_requested && !simultaneous_use_support) + return true; + + if (out_of_order_requested && !out_of_order_support) return true; + + return false; + } + + //-------------------------------------------------------------------------- + cl_int Run() override + { + cl_int error = CL_SUCCESS; + + // record command buffer + error = RecordCommandBuffer(command_buffer, kernel); + test_error(error, "RecordCommandBuffer failed"); + + switch (event_mode) + { + case EventMode::RET_REGULAR_WAIT_FOR_COMBUF: + error = RunRegularWaitForCombuf(); + test_error(error, "RunRegularWaitForCombuf failed"); + break; + case EventMode::RET_COMBUF_WAIT_FOR_COMBUF: + error = RunCombufWaitForCombuf(); + test_error(error, "RunCombufWaitForCombuf failed"); + break; + case EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF: + error = RunCombufWaitForSecCombuf(); + test_error(error, "RunCombufWaitForSecCombuf failed"); + break; + case EventMode::RET_EVENT_CALLBACK: + error = RunReturnEventCallback(); + test_error(error, "RunReturnEventCallback failed"); + break; + case EventMode::RET_CLWAITFOREVENTS_SINGLE: + error = RunWaitForEvent(); + test_error(error, "RunWaitForEvent failed"); + break; + case EventMode::RET_CLWAITFOREVENTS: + error = RunWaitForEvents(); + test_error(error, "RunWaitForEvents failed"); + break; + case EventMode::RET_COMBUF_WAIT_FOR_REGULAR: + error = RunCombufWaitForRegular(); + test_error(error, "RunCombufWaitForRegular failed"); + break; + case EventMode::RET_WAIT_FOR_SEC_QUEUE_EVENT: + error = RunCombufWaitForSecQueueCombuf(); + test_error(error, "RunCombufWaitForSecQueueCombuf failed"); + break; + case EventMode::USER_EVENT_WAIT: + error = RunUserEventWait(); + test_error(error, "RunUserEventWait failed"); + break; + case EventMode::USER_EVENTS_WAIT: + error = RunUserEventsWait(); + test_error(error, "RunUserEventsWait failed"); + break; + case EventMode::USER_EVENT_CALLBACK: + error = RunUserEventCallback(); + test_error(error, "RunUserEventCallback failed"); + break; + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RecordCommandBuffer(clCommandBufferWrapper &combuf, + clKernelWrapper &kern) + { + cl_int error = clCommandNDRangeKernelKHR( + combuf, nullptr, nullptr, kern, 1, nullptr, &num_elements, nullptr, + 0, nullptr, nullptr, nullptr); + test_error(error, "clCommandNDRangeKernelKHR failed"); + + error = clFinalizeCommandBufferKHR(combuf); + test_error(error, "clFinalizeCommandBufferKHR failed"); + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + void InitInOrderEvents(std::vector &event_ptrs) + { + if (out_of_order_requested) + { + in_order_events.resize(event_ptrs.size()); + for (size_t i = 0; i < in_order_events.size(); i++) + { + event_ptrs[i] = &in_order_events[i]; + } + } + } + + //-------------------------------------------------------------------------- + cl_int RunRegularWaitForCombuf() + { + std::vector output_data(num_elements); + + // if out-of-order queue requested it is necessary to secure proper + // order of commands + std::vector event_ptrs = { nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = + clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), 0, + data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR( + 0, nullptr, command_buffer, wait_count, event_ptrs[0], &test_event); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = + clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), 1, &test_event, nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunCombufWaitForCombuf() + { + std::vector output_data(num_elements); + + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = + clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), 0, + data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR( + 0, nullptr, command_buffer, wait_count, event_ptrs[0], &test_event); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer, 1, + &test_event, event_ptrs[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[1], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunCombufWaitForSecCombuf() + { + std::vector output_data(num_elements); + + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + // record other command buffer + cl_int error = RecordCommandBuffer(command_buffer_sec, kernel_sec); + test_error(error, "RecordCommandBuffer failed"); + + error = + clEnqueueFillBuffer(queue, in_mem_sec, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer_sec, + wait_count, event_ptrs[0], &test_event); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clEnqueueFillBuffer(queue, in_mem, &pattern_sec, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[1]); + test_error(error, "clEnqueueFillBuffer failed"); + + cl_event wait_list[] = { test_event, + event_ptrs[1] != nullptr ? *event_ptrs[1] + : nullptr }; + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer, + 1 + wait_count, wait_list, event_ptrs[2]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[2], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_sec, output_data[i], i); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunReturnEventCallback() + { + std::vector output_data(num_elements); + + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = + clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), 0, + data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR( + 0, nullptr, command_buffer, wait_count, event_ptrs[0], &test_event); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + bool confirmation = false; + error = + clSetEventCallback(test_event, CL_COMPLETE, + combuf_event_callback_function, &confirmation); + test_error(error, "clSetEventCallback failed"); + + error = clWaitForEvents(1, &test_event); + test_error(error, "clWaitForEvents failed"); + + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), 0, nullptr, nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result + if (!confirmation) + { + log_error("combuf_event_callback_function invocation failure\n"); + return TEST_FAIL; + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunWaitForEvent() + { + std::vector output_data(num_elements); + + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = + clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), 0, + data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR( + 0, nullptr, command_buffer, wait_count, event_ptrs[0], &test_event); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clWaitForEvents(1, &test_event); + test_error(error, "clWaitForEvents failed"); + + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), 0, nullptr, nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunWaitForEvents() + { + std::vector output_data(num_elements); + clEventWrapper test_events[2]; + + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + // record other command buffer + cl_int error = RecordCommandBuffer(command_buffer_sec, kernel_sec); + test_error(error, "RecordCommandBuffer failed"); + + error = + clEnqueueFillBuffer(queue, in_mem_sec, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer_sec, + wait_count, event_ptrs[0], + &test_events[0]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + error = clEnqueueFillBuffer(queue, in_mem, &pattern_sec, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[1]); + test_error(error, "clEnqueueFillBuffer failed"); + + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer, wait_count, + event_ptrs[1], &test_events[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + cl_event wait_list[] = { test_events[0], test_events[1] }; + error = clWaitForEvents(2, wait_list); + test_error(error, "clWaitForEvents failed"); + + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), 0, nullptr, nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_sec, output_data[i], i); + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunCombufWaitForRegular() + { + // if out-of-order queue requested it is necessary to secure proper + // order of commands + std::vector event_ptrs = { nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = + clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), 0, + data_size(), 0, nullptr, &test_event); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer, 1, + &test_event, event_ptrs[0]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + std::vector output_data(num_elements); + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[0], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunCombufWaitForSecQueueCombuf() + { + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = CL_SUCCESS; + + // create secondary command queue and command buffer + clCommandQueueWrapper queue_sec = + clCreateCommandQueue(context, device, 0, &error); + test_error(error, "Unable to create command queue to test with"); + + command_buffer_sec = + clCreateCommandBufferKHR(1, &queue_sec, nullptr, &error); + test_error(error, "clCreateCommandBufferKHR failed"); + + // record secondary command buffer + error = RecordCommandBuffer(command_buffer_sec, kernel); + test_error(error, "RecordCommandBuffer failed"); + + // process secondary queue + error = + clEnqueueFillBuffer(queue_sec, in_mem, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, nullptr); + test_error(error, "clEnqueueFillBuffer failed"); + + error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer_sec, 0, + nullptr, &test_event); + test_error(error, + "clEnqueueCommandBufferKHR in secondary queue failed"); + + // process primary queue + error = clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + cl_event wait_list[] = { test_event, + event_ptrs[0] != nullptr ? *event_ptrs[0] + : nullptr }; + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer, + 1 + wait_count, wait_list, event_ptrs[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + std::vector output_data(num_elements); + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[1], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + error = clFinish(queue_sec); + test_error(error, "clFinish failed"); + + // verify the result - result buffer must contain initial pattern + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + return CL_SUCCESS; + } + + + //-------------------------------------------------------------------------- + cl_int RunUserEventWait() + { + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = CL_SUCCESS; + clEventWrapper user_event = clCreateUserEvent(context, &error); + test_error(error, "clCreateUserEvent failed"); + + const cl_int pattern = 42; + error = clEnqueueFillBuffer(queue, in_mem, &pattern, sizeof(cl_int), 0, + data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + cl_event wait_list[] = { user_event, + event_ptrs[0] != nullptr ? *event_ptrs[0] + : nullptr }; + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer, + wait_count + 1, wait_list, event_ptrs[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + std::vector output_data(num_elements); + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[1], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clSetUserEventStatus(user_event, CL_COMPLETE); + test_error(error, "clSetUserEventStatus failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern, output_data[i], i); + } + + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunUserEventsWait() + { + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = CL_SUCCESS; + std::vector user_events(user_event_num); + + for (size_t i = 0; i < user_event_num; i++) + { + user_events[i] = clCreateUserEvent(context, &error); + test_error(error, "clCreateUserEvent failed"); + } + + error = clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + std::vector wait_list(user_event_num + wait_count); + for (size_t i = 0; i < user_event_num; i++) + { + wait_list[i] = user_events[i]; + } + if (out_of_order_requested) wait_list[user_event_num] = *event_ptrs[0]; + + error = clEnqueueCommandBufferKHR(0, nullptr, command_buffer, + user_event_num + wait_count, + &wait_list.front(), event_ptrs[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + std::vector output_data(num_elements); + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[1], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + for (size_t i = 0; i < user_event_num; i++) + { + error = clSetUserEventStatus(user_events[i], CL_COMPLETE); + test_error(error, "clSetUserEventStatus failed"); + } + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + for (size_t i = 0; i < num_elements; i++) + { + CHECK_VERIFICATION_ERROR(pattern_pri, output_data[i], i); + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + cl_int RunUserEventCallback() + { + // if out-of-order queue requested it is necessary to secure proper + // order of all commands + std::vector event_ptrs = { nullptr, nullptr }; + InitInOrderEvents(event_ptrs); + + cl_int error = CL_SUCCESS; + clEventWrapper user_event = clCreateUserEvent(context, &error); + test_error(error, "clCreateUserEvent failed"); + + error = clEnqueueFillBuffer(queue, in_mem, &pattern_pri, sizeof(cl_int), + 0, data_size(), 0, nullptr, event_ptrs[0]); + test_error(error, "clEnqueueFillBuffer failed"); + + cl_event wait_list[] = { user_event, + event_ptrs[0] != nullptr ? *event_ptrs[0] + : nullptr }; + error = + clEnqueueCommandBufferKHR(0, nullptr, command_buffer, + wait_count + 1, wait_list, event_ptrs[1]); + test_error(error, "clEnqueueCommandBufferKHR failed"); + + bool confirmation = false; + error = + clSetEventCallback(user_event, CL_COMPLETE, + combuf_event_callback_function, &confirmation); + test_error(error, "clSetEventCallback failed"); + + error = clSetUserEventStatus(user_event, CL_COMPLETE); + test_error(error, "clSetUserEventStatus failed"); + + std::vector output_data(num_elements); + error = clEnqueueReadBuffer(queue, out_mem, CL_FALSE, 0, data_size(), + output_data.data(), wait_count, + event_ptrs[1], nullptr); + test_error(error, "clEnqueueReadBuffer failed"); + + error = clFinish(queue); + test_error(error, "clFinish failed"); + + // verify the result + if (!confirmation) + { + log_error("combuf_event_callback_function invocation failure\n"); + return TEST_FAIL; + } + return CL_SUCCESS; + } + + //-------------------------------------------------------------------------- + + clCommandBufferWrapper command_buffer_sec; + clKernelWrapper kernel_sec; + clMemWrapper in_mem_sec, out_mem_sec, off_mem_sec; + clEventWrapper test_event; + + std::vector in_order_events; + + const cl_int pattern_pri = 0xA; + const cl_int pattern_sec = 0xB; + const cl_int wait_count = out_of_order_requested ? 1 : 0; + + const cl_int user_event_num = 3; +}; + +} // anonymous namespace + +// helper macros +#define IN_ORDER_MSG(name) #name " test with in-order command queue" +#define OUT_OF_ORDER_MSG(name) #name " test with out-of-order command queue" +#define test_status_val(code, msg) \ + { \ + if (code == TEST_FAIL) \ + { \ + print_failure_error(code, TEST_PASS, msg " failed\n"); \ + return TEST_FAIL; \ + } \ + else if (code == TEST_SKIP) \ + { \ + log_info(msg " skipped\n"); \ + } \ + } + +//-------------------------------------------------------------------------- +// return-events test cases for regular queue +int test_regular_wait_for_command_buffer(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + int status = TEST_PASS; + // The approach here is that test scenario which involves out-of-order + // command queue may be skipped without breaking in-order queue test. + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + OUT_OF_ORDER_MSG(EventMode::RET_REGULAR_WAIT_FOR_COMBUF)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_REGULAR_WAIT_FOR_COMBUF)); + + return status; +} + +int test_command_buffer_wait_for_command_buffer(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + OUT_OF_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_COMBUF)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_COMBUF)); + + return status; +} + +int test_command_buffer_wait_for_sec_command_buffer(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest>(device, context, + queue, num_elements); + test_status_val( + status, OUT_OF_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF)); + + // in-order command queue test + status = MakeAndRunTest>(device, context, + queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_SEC_COMBUF)); + + return status; +} + +int test_return_event_callback(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, OUT_OF_ORDER_MSG(EventMode::RET_EVENT_CALLBACK)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, IN_ORDER_MSG(EventMode::RET_EVENT_CALLBACK)); + + return status; +} + +int test_clwaitforevents_single(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + OUT_OF_ORDER_MSG(EventMode::RET_CLWAITFOREVENTS_SINGLE)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_CLWAITFOREVENTS_SINGLE)); + + return status; +} + +int test_clwaitforevents(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, OUT_OF_ORDER_MSG(EventMode::RET_CLWAITFOREVENTS)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, IN_ORDER_MSG(EventMode::RET_CLWAITFOREVENTS)); + + return status; +} + +int test_command_buffer_wait_for_regular(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + OUT_OF_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_REGULAR)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_COMBUF_WAIT_FOR_REGULAR)); + + return status; +} + +int test_wait_for_sec_queue_event(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + OUT_OF_ORDER_MSG(EventMode::RET_WAIT_FOR_SEC_QUEUE_EVENT)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, + IN_ORDER_MSG(EventMode::RET_WAIT_FOR_SEC_QUEUE_EVENT)); + + return status; +} + +//-------------------------------------------------------------------------- +// user-events test cases + +int test_user_event_wait(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, OUT_OF_ORDER_MSG(EventMode::USER_EVENT_WAIT)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, IN_ORDER_MSG(EventMode::USER_EVENT_WAIT)); + + return status; +} + +int test_user_events_wait(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, OUT_OF_ORDER_MSG(EventMode::USER_EVENTS_WAIT)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, IN_ORDER_MSG(EventMode::USER_EVENTS_WAIT)); + + return status; +} + +int test_user_event_callback(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + int status = TEST_PASS; + // out-of-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, OUT_OF_ORDER_MSG(EventMode::USER_EVENT_CALLBACK)); + + // in-order command queue test + status = MakeAndRunTest< + CommandBufferEventSync>( + device, context, queue, num_elements); + test_status_val(status, IN_ORDER_MSG(EventMode::USER_EVENT_CALLBACK)); + + return status; +} diff --git a/test_conformance/extensions/cl_khr_command_buffer/main.cpp b/test_conformance/extensions/cl_khr_command_buffer/main.cpp index d1bb896e..909a1025 100644 --- a/test_conformance/extensions/cl_khr_command_buffer/main.cpp +++ b/test_conformance/extensions/cl_khr_command_buffer/main.cpp @@ -15,31 +15,43 @@ #include "procs.h" #include "harness/testHarness.h" -test_definition test_list[] = { ADD_TEST(single_ndrange), - ADD_TEST(interleaved_enqueue), - ADD_TEST(mixed_commands), - ADD_TEST(explicit_flush), - ADD_TEST(user_events), - ADD_TEST(out_of_order), - ADD_TEST(simultaneous_out_of_order), - ADD_TEST(basic_profiling), - ADD_TEST(simultaneous_profiling), - ADD_TEST(queue_substitution), - ADD_TEST(properties_queue_substitution), - ADD_TEST(simultaneous_queue_substitution), - ADD_TEST(fill_image), - ADD_TEST(fill_buffer), - ADD_TEST(copy_image), - ADD_TEST(copy_buffer), - ADD_TEST(copy_buffer_to_image), - ADD_TEST(copy_image_to_buffer), - ADD_TEST(copy_buffer_rect), - ADD_TEST(barrier_wait_list), - ADD_TEST(event_info_command_type), - ADD_TEST(event_info_command_queue), - ADD_TEST(event_info_execution_status), - ADD_TEST(event_info_context), - ADD_TEST(event_info_reference_count) }; +test_definition test_list[] = { + ADD_TEST(single_ndrange), + ADD_TEST(interleaved_enqueue), + ADD_TEST(mixed_commands), + ADD_TEST(explicit_flush), + ADD_TEST(out_of_order), + ADD_TEST(simultaneous_out_of_order), + ADD_TEST(basic_profiling), + ADD_TEST(simultaneous_profiling), + ADD_TEST(regular_wait_for_command_buffer), + ADD_TEST(command_buffer_wait_for_command_buffer), + ADD_TEST(command_buffer_wait_for_sec_command_buffer), + ADD_TEST(return_event_callback), + ADD_TEST(clwaitforevents_single), + ADD_TEST(clwaitforevents), + ADD_TEST(command_buffer_wait_for_regular), + ADD_TEST(wait_for_sec_queue_event), + ADD_TEST(user_event_wait), + ADD_TEST(user_events_wait), + ADD_TEST(user_event_callback), + ADD_TEST(queue_substitution), + ADD_TEST(properties_queue_substitution), + ADD_TEST(simultaneous_queue_substitution), + ADD_TEST(fill_image), + ADD_TEST(fill_buffer), + ADD_TEST(copy_image), + ADD_TEST(copy_buffer), + ADD_TEST(copy_buffer_to_image), + ADD_TEST(copy_image_to_buffer), + ADD_TEST(copy_buffer_rect), + ADD_TEST(barrier_wait_list), + ADD_TEST(event_info_command_type), + ADD_TEST(event_info_command_queue), + ADD_TEST(event_info_execution_status), + ADD_TEST(event_info_context), + ADD_TEST(event_info_reference_count) +}; int main(int argc, const char *argv[]) { diff --git a/test_conformance/extensions/cl_khr_command_buffer/procs.h b/test_conformance/extensions/cl_khr_command_buffer/procs.h index f43bdb59..24e3faae 100644 --- a/test_conformance/extensions/cl_khr_command_buffer/procs.h +++ b/test_conformance/extensions/cl_khr_command_buffer/procs.h @@ -27,10 +27,40 @@ extern int test_mixed_commands(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements); extern int test_explicit_flush(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements); -extern int test_user_events(cl_device_id device, cl_context context, - cl_command_queue queue, int num_elements); extern int test_out_of_order(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements); +extern int test_regular_wait_for_command_buffer(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_command_buffer_wait_for_command_buffer(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_command_buffer_wait_for_sec_command_buffer( + cl_device_id device, cl_context context, cl_command_queue queue, + int num_elements); +extern int test_return_event_callback(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements); +extern int test_clwaitforevents_single(cl_device_id device, cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_clwaitforevents(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements); +extern int test_command_buffer_wait_for_regular(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_wait_for_sec_queue_event(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_user_event_wait(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements); +extern int test_user_events_wait(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements); +extern int test_user_event_callback(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements); extern int test_simultaneous_out_of_order(cl_device_id device, cl_context context, cl_command_queue queue,