diff --git a/include/ur.py b/include/ur.py index 2adc7a5a17..30e117135c 100644 --- a/include/ur.py +++ b/include/ur.py @@ -169,7 +169,8 @@ class ur_result_v(IntEnum): ERROR_INVALID_NULL_HANDLE = 48 ## [Validation] handle argument is not valid ERROR_HANDLE_OBJECT_IN_USE = 49 ## [Validation] object pointed to by handle still in-use by device ERROR_INVALID_NULL_POINTER = 50 ## [Validation] pointer argument may not be nullptr - ERROR_INVALID_SIZE = 51 ## [Validation] size argument is invalid (e.g., must not be zero) + ERROR_INVALID_SIZE = 51 ## [Validation] invalid size or dimensions (e.g., must not be zero, or is + ## out of bounds) ERROR_UNSUPPORTED_SIZE = 52 ## [Validation] size argument is not supported by the device (e.g., too ## large) ERROR_UNSUPPORTED_ALIGNMENT = 53 ## [Validation] alignment argument is not supported by the device (e.g., diff --git a/include/ur_api.h b/include/ur_api.h index 8452d5e959..bbfb380050 100644 --- a/include/ur_api.h +++ b/include/ur_api.h @@ -192,7 +192,8 @@ typedef enum ur_result_t { UR_RESULT_ERROR_INVALID_NULL_HANDLE = 48, ///< [Validation] handle argument is not valid UR_RESULT_ERROR_HANDLE_OBJECT_IN_USE = 49, ///< [Validation] object pointed to by handle still in-use by device UR_RESULT_ERROR_INVALID_NULL_POINTER = 50, ///< [Validation] pointer argument may not be nullptr - UR_RESULT_ERROR_INVALID_SIZE = 51, ///< [Validation] size argument is invalid (e.g., must not be zero) + UR_RESULT_ERROR_INVALID_SIZE = 51, ///< [Validation] invalid size or dimensions (e.g., must not be zero, or is + ///< out of bounds) UR_RESULT_ERROR_UNSUPPORTED_SIZE = 52, ///< [Validation] size argument is not supported by the device (e.g., too ///< large) UR_RESULT_ERROR_UNSUPPORTED_ALIGNMENT = 53, ///< [Validation] alignment argument is not supported by the device (e.g., @@ -1426,6 +1427,12 @@ urEnqueueUSMFill2D( /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER /// + `NULL == pMem` +/// - ::UR_RESULT_ERROR_INVALID_SIZE +/// + `pitch == 0` +/// + `width == 0` +/// + `height == 0` +/// + `pitch < width` +/// + `pitch * height` is higher than the memory allocation size /// - ::UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST /// + `phEventWaitList == NULL && numEventsInWaitList > 0` /// + `phEventWaitList != NULL && numEventsInWaitList == 0` diff --git a/scripts/core/common.yml b/scripts/core/common.yml index f9fe2d34f2..2b8ce78f54 100644 --- a/scripts/core/common.yml +++ b/scripts/core/common.yml @@ -225,7 +225,7 @@ etors: - name: ERROR_INVALID_NULL_POINTER desc: "[Validation] pointer argument may not be nullptr" - name: ERROR_INVALID_SIZE - desc: "[Validation] size argument is invalid (e.g., must not be zero)" + desc: "[Validation] invalid size or dimensions (e.g., must not be zero, or is out of bounds)" - name: ERROR_UNSUPPORTED_SIZE desc: "[Validation] size argument is not supported by the device (e.g., too large)" - name: ERROR_UNSUPPORTED_ALIGNMENT diff --git a/scripts/core/enqueue.yml b/scripts/core/enqueue.yml index d6eebfc208..4ccbafe769 100644 --- a/scripts/core/enqueue.yml +++ b/scripts/core/enqueue.yml @@ -1177,6 +1177,12 @@ params: desc: | [in,out][optional] return an event object that identifies this particular kernel execution instance. returns: + - $X_RESULT_ERROR_INVALID_SIZE: + - "`pitch == 0`" + - "`width == 0`" + - "`height == 0`" + - "`pitch < width`" + - "`pitch * height` is higher than the memory allocation size" - $X_RESULT_ERROR_INVALID_EVENT_WAIT_LIST: - "`phEventWaitList == NULL && numEventsInWaitList > 0`" - "`phEventWaitList != NULL && numEventsInWaitList == 0`" diff --git a/source/loader/layers/validation/ur_valddi.cpp b/source/loader/layers/validation/ur_valddi.cpp index f720a3c12f..06d189f41f 100644 --- a/source/loader/layers/validation/ur_valddi.cpp +++ b/source/loader/layers/validation/ur_valddi.cpp @@ -1200,6 +1200,22 @@ urEnqueueUSMMemset2D( return UR_RESULT_ERROR_INVALID_NULL_POINTER; } + if (pitch == 0) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + if (width == 0) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + if (height == 0) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + + if (pitch < width) { + return UR_RESULT_ERROR_INVALID_SIZE; + } + if (phEventWaitList == NULL && numEventsInWaitList > 0) { return UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST; } diff --git a/source/loader/ur_libapi.cpp b/source/loader/ur_libapi.cpp index b6785fc2a0..189a6b3b3a 100644 --- a/source/loader/ur_libapi.cpp +++ b/source/loader/ur_libapi.cpp @@ -1288,6 +1288,12 @@ urEnqueueUSMFill2D( /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER /// + `NULL == pMem` +/// - ::UR_RESULT_ERROR_INVALID_SIZE +/// + `pitch == 0` +/// + `width == 0` +/// + `height == 0` +/// + `pitch < width` +/// + `pitch * height` is higher than the memory allocation size /// - ::UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST /// + `phEventWaitList == NULL && numEventsInWaitList > 0` /// + `phEventWaitList != NULL && numEventsInWaitList == 0` diff --git a/source/ur_api.cpp b/source/ur_api.cpp index dc8a56945b..96c0142bf8 100644 --- a/source/ur_api.cpp +++ b/source/ur_api.cpp @@ -1177,6 +1177,12 @@ urEnqueueUSMFill2D( /// + `NULL == hQueue` /// - ::UR_RESULT_ERROR_INVALID_NULL_POINTER /// + `NULL == pMem` +/// - ::UR_RESULT_ERROR_INVALID_SIZE +/// + `pitch == 0` +/// + `width == 0` +/// + `height == 0` +/// + `pitch < width` +/// + `pitch * height` is higher than the memory allocation size /// - ::UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST /// + `phEventWaitList == NULL && numEventsInWaitList > 0` /// + `phEventWaitList != NULL && numEventsInWaitList == 0` diff --git a/test/conformance/enqueue/rect_helpers.h b/test/conformance/enqueue/helpers.h similarity index 78% rename from test/conformance/enqueue/rect_helpers.h rename to test/conformance/enqueue/helpers.h index 262ee4c5d6..77b7628ac0 100644 --- a/test/conformance/enqueue/rect_helpers.h +++ b/test/conformance/enqueue/helpers.h @@ -53,6 +53,22 @@ inline void copyRect(std::vector src, ur_rect_offset_t src_offset, ur_r } } +struct TestParameters2D { + int pitch; + int width; + int height; +}; + +template +inline std::string print2DTestString(const testing::TestParamInfo &info) { + const auto device_handle = std::get<0>(info.param); + const auto platform_device_name = uur::GetPlatformAndDeviceName(device_handle); + std::stringstream test_name; + test_name << platform_device_name << "__pitch__" << std::get<1>(info.param).pitch << "__width__" << std::get<1>(info.param).width + << "__height__" << std::get<1>(info.param).height; + return test_name.str(); +} + } // namespace uur #endif // UUR_ENQUEUE_RECT_HELPERS_H_INCLUDED diff --git a/test/conformance/enqueue/urEnqueueMemBufferCopyRect.cpp b/test/conformance/enqueue/urEnqueueMemBufferCopyRect.cpp index 567e4e710c..7157ba2ea5 100644 --- a/test/conformance/enqueue/urEnqueueMemBufferCopyRect.cpp +++ b/test/conformance/enqueue/urEnqueueMemBufferCopyRect.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2023 Intel Corporation // SPDX-License-Identifier: MIT -#include "rect_helpers.h" +#include "helpers.h" #include static std::vector generateParameterizations() { diff --git a/test/conformance/enqueue/urEnqueueMemBufferReadRect.cpp b/test/conformance/enqueue/urEnqueueMemBufferReadRect.cpp index 2b1e8706f4..0b2e6171d1 100644 --- a/test/conformance/enqueue/urEnqueueMemBufferReadRect.cpp +++ b/test/conformance/enqueue/urEnqueueMemBufferReadRect.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2023 Intel Corporation // SPDX-License-Identifier: MIT -#include "rect_helpers.h" +#include "helpers.h" #include // Choose parameters so that we get good coverage and catch some edge cases. diff --git a/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp b/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp index 2caf623552..f5c6d17e5f 100644 --- a/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp +++ b/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2023 Intel Corporation // SPDX-License-Identifier: MIT -#include "rect_helpers.h" +#include "helpers.h" #include static std::vector generateParameterizations() { diff --git a/test/conformance/enqueue/urEnqueueUSMMemcpy.cpp b/test/conformance/enqueue/urEnqueueUSMMemcpy.cpp index d43485b487..1a88c5e0ec 100644 --- a/test/conformance/enqueue/urEnqueueUSMMemcpy.cpp +++ b/test/conformance/enqueue/urEnqueueUSMMemcpy.cpp @@ -48,10 +48,15 @@ struct urEnqueueUSMMemcpyTest : uur::urQueueTest { return UR_EVENT_STATUS_COMPLETE == memset_event_status; } - bool verifyData() { - EXPECT_SUCCESS( - urEnqueueUSMMemcpy(queue, true, host_mem.data(), device_dst, allocation_size, 0, nullptr, nullptr)); - return std::all_of(host_mem.begin(), host_mem.end(), [this](uint8_t i) { return i == memset_value; }); + void verifyData() { + ASSERT_SUCCESS( + urEnqueueUSMMemcpy(queue, true, host_mem.data(), device_dst, + allocation_size, 0, nullptr, nullptr)); + bool good = std::all_of(host_mem.begin(), host_mem.end(), + [this](uint8_t i) { + return i == memset_value; + }); + ASSERT_TRUE(good); } const uint32_t num_elements = 1024; @@ -71,7 +76,7 @@ TEST_P(urEnqueueUSMMemcpyTest, Blocking) { ASSERT_SUCCESS(urEventWait(1, &memset_event)); ASSERT_TRUE(memsetHasFinished()); ASSERT_SUCCESS(urEnqueueUSMMemcpy(queue, true, device_dst, device_src, allocation_size, 0, nullptr, nullptr)); - ASSERT_TRUE(verifyData()); + ASSERT_NO_FATAL_FAILURE(verifyData()); } /** @@ -90,7 +95,7 @@ TEST_P(urEnqueueUSMMemcpyTest, BlockingWithEvent) { &event_status, nullptr)); ASSERT_EQ(event_status, UR_EVENT_STATUS_COMPLETE); EXPECT_SUCCESS(urEventRelease(memcpy_event)); - ASSERT_TRUE(verifyData()); + ASSERT_NO_FATAL_FAILURE(verifyData()); } /** @@ -105,7 +110,7 @@ TEST_P(urEnqueueUSMMemcpyTest, NonBlocking) { urEnqueueUSMMemcpy(queue, false, device_dst, device_src, allocation_size, 0, nullptr, &memcpy_event)); ASSERT_SUCCESS(urEventWait(1, &memcpy_event)); - ASSERT_TRUE(verifyData()); + ASSERT_NO_FATAL_FAILURE(verifyData()); } /** @@ -115,7 +120,7 @@ TEST_P(urEnqueueUSMMemcpyTest, WaitForDependencies) { ASSERT_SUCCESS( urEnqueueUSMMemcpy(queue, true, device_dst, device_src, sizeof(int), 1, &memset_event, nullptr)); ASSERT_TRUE(memsetHasFinished()); - ASSERT_TRUE(verifyData()); + ASSERT_NO_FATAL_FAILURE(verifyData()); } TEST_P(urEnqueueUSMMemcpyTest, InvalidNullQueueHandle) { diff --git a/test/conformance/enqueue/urEnqueueUSMMemset2D.cpp b/test/conformance/enqueue/urEnqueueUSMMemset2D.cpp index 09e5c02adc..a71639b884 100644 --- a/test/conformance/enqueue/urEnqueueUSMMemset2D.cpp +++ b/test/conformance/enqueue/urEnqueueUSMMemset2D.cpp @@ -1,2 +1,210 @@ // Copyright (C) 2023 Intel Corporation // SPDX-License-Identifier: MIT +#include "helpers.h" +#include + +struct urEnqueueUSMMemset2DTestWithParam + : uur::urQueueTestWithParam { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE(urQueueTestWithParam::SetUp()); + + pitch = std::get<1>(GetParam()).pitch; + width = std::get<1>(GetParam()).width; + height = std::get<1>(GetParam()).height; + num_elements = pitch * height; + host_mem = std::vector(num_elements); + + bool device_usm{false}; + ASSERT_SUCCESS(urDeviceGetInfo(device, UR_DEVICE_INFO_USM_DEVICE_SUPPORT, + sizeof(bool), &device_usm, nullptr)); + + if (!device_usm) { + GTEST_SKIP() << "Device USM is not supported"; + } + + ur_usm_mem_flags_t flags{}; + ASSERT_SUCCESS(urUSMDeviceAlloc(context, device, &flags, num_elements, 0, + reinterpret_cast(&ptr))); + } + + void TearDown() override { + if (ptr) { + EXPECT_SUCCESS(urUSMFree(context, ptr)); + } + + UUR_RETURN_ON_FATAL_FAILURE(urQueueTestWithParam::TearDown()); + } + + void verifyData() { + ASSERT_SUCCESS( + urEnqueueUSMMemcpy2D(queue, true, host_mem.data(), pitch, ptr, + pitch, width, height, 0, nullptr, nullptr)); + for (int w = 0; w < width; ++w) { + for (int h = 0; h < height; ++h) { + char *host_ptr = host_mem.data(); + size_t index = (pitch * h) + w; + ASSERT_TRUE((*(host_ptr + index) == memset_value)); + } + } + } + + const int memset_value = 12; + int pitch; + int width; + int height; + uint32_t num_elements; + std::vector host_mem; + int *ptr{nullptr}; +}; + +std::vector test_cases{ + /* Everything set to 1 */ + {1, 1, 1}, + /* Height == 1 && Pitch > width */ + {1024, 256, 1}, + /* Height == 1 && Pitch == width */ + {1024, 1024, 1}, + /* Height > 1 && Pitch > width */ + {1024, 256, 256}, + /* Height > 1 && Pitch == width + 1 */ + {234, 233, 23}, + /* Height == 1 && Pitch == width + 1 */ + {234, 233, 1}}; + +UUR_TEST_SUITE_P(urEnqueueUSMMemset2DTestWithParam, + testing::ValuesIn(test_cases), + uur::print2DTestString); + +TEST_P(urEnqueueUSMMemset2DTestWithParam, Success) { + + ur_event_handle_t event = nullptr; + ASSERT_SUCCESS( + urEnqueueUSMMemset2D(queue, ptr, pitch, memset_value, width, height, 0, + nullptr, &event)); + EXPECT_SUCCESS(urQueueFlush(queue)); + + ASSERT_SUCCESS(urEventWait(1, &event)); + ur_event_status_t event_status; + EXPECT_SUCCESS(urEventGetInfo(event, UR_EVENT_INFO_COMMAND_EXECUTION_STATUS, + sizeof(ur_event_status_t), &event_status, + nullptr)); + ASSERT_EQ(UR_EVENT_STATUS_COMPLETE, event_status); + EXPECT_SUCCESS(urEventRelease(event)); + + ASSERT_NO_FATAL_FAILURE(verifyData()); +} + +struct urEnqueueUSMMemset2DNegativeTest : uur::urQueueTest { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE(urQueueTest::SetUp()); + + bool device_usm{false}; + ASSERT_SUCCESS(urDeviceGetInfo(device, UR_DEVICE_INFO_USM_DEVICE_SUPPORT, + sizeof(bool), &device_usm, nullptr)); + + if (!device_usm) { + GTEST_SKIP() << "Device USM is not supported"; + } + + ur_usm_mem_flags_t flags{}; + ASSERT_SUCCESS(urUSMDeviceAlloc(context, device, &flags, num_elements, 0, + reinterpret_cast(&ptr))); + } + + void TearDown() override { + if (ptr) { + EXPECT_SUCCESS(urUSMFree(context, ptr)); + } + + UUR_RETURN_ON_FATAL_FAILURE(urQueueTest::TearDown()); + } + + const int memset_value = 12; + int default_pitch = 16; + int default_width = 16; + int default_height = 16; + uint32_t num_elements = default_pitch * default_height; + int *ptr{nullptr}; +}; + +UUR_INSTANTIATE_DEVICE_TEST_SUITE_P(urEnqueueUSMMemset2DNegativeTest); + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidNullQueueHandle) { + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(nullptr, ptr, default_pitch, memset_value, + default_width, default_height, 0, nullptr, + nullptr), + UR_RESULT_ERROR_INVALID_NULL_HANDLE); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidNullPtr) { + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, default_pitch, memset_value, + default_width, default_height, 0, nullptr, + nullptr), + UR_RESULT_ERROR_INVALID_NULL_POINTER); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidPitch) { + + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, 0, memset_value, default_width, + default_height, 0, nullptr, nullptr), + UR_RESULT_ERROR_INVALID_SIZE); + + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, default_width - 1, memset_value, + default_width, default_height, 0, nullptr, + nullptr), + UR_RESULT_ERROR_INVALID_SIZE); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidWidth) { + + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, default_pitch, memset_value, 0, + default_height, 0, nullptr, nullptr), + UR_RESULT_ERROR_INVALID_SIZE); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidHeight) { + + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, default_pitch, memset_value, + default_width, 0, 0, nullptr, nullptr), + UR_RESULT_ERROR_INVALID_SIZE); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, OutOfBounds) { + + size_t out_of_bounds = default_pitch * default_height + 1; + + /* Interpret memory as having just one row */ + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, out_of_bounds, memset_value, + default_width, 1, 0, nullptr, nullptr), + UR_RESULT_ERROR_INVALID_SIZE); + + /* Interpret memory as having just one column */ + ASSERT_EQ_RESULT( + urEnqueueUSMMemset2D(queue, nullptr, 1, memset_value, 1, out_of_bounds, + 0, nullptr, nullptr), + UR_RESULT_ERROR_INVALID_SIZE); +} + +TEST_P(urEnqueueUSMMemset2DNegativeTest, InvalidNullPtrEventWaitList) { + + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST, + urEnqueueUSMMemset2D(queue, nullptr, default_pitch, + memset_value, default_width, + default_height, 1, nullptr, nullptr)); + + ur_event_handle_t validEvent; + ASSERT_SUCCESS(urEnqueueEventsWait(queue, 0, nullptr, &validEvent)); + + ASSERT_EQ_RESULT(UR_RESULT_ERROR_INVALID_EVENT_WAIT_LIST, + urEnqueueUSMMemset2D(queue, nullptr, default_pitch, + memset_value, default_width, + default_height, 0, &validEvent, + nullptr)); +}