diff --git a/unified-runtime/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp b/unified-runtime/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp index a7c5a7cd7ec7a..0769d11db01de 100644 --- a/unified-runtime/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp +++ b/unified-runtime/test/conformance/enqueue/urEnqueueMemBufferWriteRect.cpp @@ -87,7 +87,7 @@ TEST_P(urEnqueueMemBufferWriteRectTestWithParam, Success) { UUR_KNOWN_FAILURE_ON(uur::HIP{}); } - UUR_KNOWN_FAILURE_ON(uur::LevelZero{}, uur::LevelZeroV2{}); + UUR_KNOWN_FAILURE_ON(uur::LevelZero{}); // Unpack the parameters. const auto host_size = getParam().src_size; diff --git a/unified-runtime/test/conformance/exp_command_buffer/CMakeLists.txt b/unified-runtime/test/conformance/exp_command_buffer/CMakeLists.txt index 0613421719fdb..68f6b1b98cc63 100644 --- a/unified-runtime/test/conformance/exp_command_buffer/CMakeLists.txt +++ b/unified-runtime/test/conformance/exp_command_buffer/CMakeLists.txt @@ -11,6 +11,11 @@ add_conformance_test_with_kernels_environment(exp_command_buffer event_sync.cpp kernel_event_sync.cpp invalid.cpp + copy.cpp + read.cpp + write.cpp + rect_read.cpp + rect_write.cpp update/buffer_fill_kernel_update.cpp update/invalid_update.cpp update/kernel_handle_update.cpp diff --git a/unified-runtime/test/conformance/exp_command_buffer/copy.cpp b/unified-runtime/test/conformance/exp_command_buffer/copy.cpp new file mode 100644 index 0000000000000..026339921a0b6 --- /dev/null +++ b/unified-runtime/test/conformance/exp_command_buffer/copy.cpp @@ -0,0 +1,168 @@ +// Copyright (C) 2025 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See LICENSE.TXT +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "fixtures.h" + +struct testParametersMemcpy { + size_t size; + size_t offset_src; + size_t offset_dst; + size_t copy_size; +}; + +struct urCommandBufferMemcpyCommandsTest + : uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersMemcpy> { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersMemcpy>::SetUp()); + + size = std::get<1>(GetParam()).size; + offset_src = std::get<1>(GetParam()).offset_src; + offset_dst = std::get<1>(GetParam()).offset_dst; + copy_size = std::get<1>(GetParam()).copy_size; + assert(size <= offset_src + copy_size); + assert(size <= offset_dst + copy_size); + // Allocate USM pointers + ASSERT_SUCCESS( + urUSMDeviceAlloc(context, device, nullptr, nullptr, size, &device_ptr)); + ASSERT_NE(device_ptr, nullptr); + + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, size, + nullptr, &buffer)); + + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, size, + nullptr, &buffer_base)); + + ASSERT_NE(buffer, nullptr); + ASSERT_NE(buffer_base, nullptr); + } + + void TearDown() override { + if (device_ptr) { + EXPECT_SUCCESS(urUSMFree(context, device_ptr)); + } + + if (buffer) { + EXPECT_SUCCESS(urMemRelease(buffer)); + } + + if (buffer_base) { + EXPECT_SUCCESS(urMemRelease(buffer_base)); + } + + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersMemcpy>::TearDown()); + } + + void verifyData(const std::vector &output, + const std::vector &input) { + for (size_t i = 0; i < copy_size; ++i) { + ASSERT_EQ(output[i + offset_dst], input[i + offset_src]) + << "Result mismatch at index: " << i; + } + for (size_t i = 0; i < offset_dst; ++i) { + ASSERT_EQ(output[i], BASE_VALUE) << "Result mismatch at index: " << i; + } + for (size_t i = offset_dst + copy_size; i < size; ++i) { + ASSERT_EQ(output[i], BASE_VALUE) << "Result mismatch at index: " << i; + } + } + const uint8_t BASE_VALUE = 1; + size_t size, copy_size, offset_src, offset_dst; + + ur_exp_command_buffer_sync_point_t sync_point, sync_point2; + void *device_ptr = nullptr; + ur_mem_handle_t buffer = nullptr; + ur_mem_handle_t buffer_base = nullptr; +}; + +static std::vector test_cases{ + // copy whole buffer + {1, 0, 0, 1}, + {256, 0, 0, 256}, + {1024, 0, 0, 1024}, + // copy part of buffer + {256, 127, 127, 128}, + {1024, 256, 256, 256}, + // copy to different offset + {256, 127, 196, 25}, + {1024, 756, 256, 256}, + +}; + +template +static std::string printMemcpyTestString( + const testing::TestParamInfo &info) { + const auto device_handle = std::get<0>(info.param).device; + const auto platform_device_name = + uur::GetPlatformAndDeviceName(device_handle); + std::stringstream test_name; + test_name << platform_device_name << "__size__" + << std::get<1>(info.param).size << "__offset_src__" + << std::get<1>(info.param).offset_src << "__offset_src__" + << std::get<1>(info.param).offset_dst << "__copy_size__" + << std::get<1>(info.param).copy_size; + return test_name.str(); +} + +UUR_DEVICE_TEST_SUITE_WITH_PARAM( + urCommandBufferMemcpyCommandsTest, testing::ValuesIn(test_cases), + printMemcpyTestString); + +TEST_P(urCommandBufferMemcpyCommandsTest, Buffer) { + std::vector input(size); + std::iota(input.begin(), input.end(), 1); + + ASSERT_SUCCESS(urCommandBufferAppendMemBufferWriteExp( + cmd_buf_handle, buffer_base, 0, size, input.data(), 0, nullptr, 0, + nullptr, &sync_point, nullptr, nullptr)); + + ASSERT_SUCCESS(urCommandBufferAppendMemBufferCopyExp( + cmd_buf_handle, buffer_base, buffer, offset_src, offset_dst, copy_size, 1, + &sync_point, 0, nullptr, &sync_point2, nullptr, nullptr)); + std::vector output(size, BASE_VALUE); + ASSERT_SUCCESS(urCommandBufferAppendMemBufferReadExp( + cmd_buf_handle, buffer, 0, size, output.data(), 1, &sync_point2, 0, + nullptr, nullptr, nullptr, nullptr)); + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS(urEnqueueMemBufferWrite(queue, buffer, true, 0, size, + output.data(), 0, nullptr, nullptr)); + + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + + verifyData(output, input); +} + +TEST_P(urCommandBufferMemcpyCommandsTest, USM) { + std::vector input(size); + std::iota(input.begin(), input.end(), 1); + ASSERT_SUCCESS(urCommandBufferAppendUSMMemcpyExp( + cmd_buf_handle, ((uint8_t *)device_ptr) + offset_dst, + input.data() + offset_src, copy_size, 0, nullptr, 0, nullptr, &sync_point, + nullptr, nullptr)); + + std::vector output(size, BASE_VALUE); + ASSERT_SUCCESS(urCommandBufferAppendUSMMemcpyExp( + cmd_buf_handle, output.data(), device_ptr, size, 1, &sync_point, 0, + nullptr, nullptr, nullptr, nullptr)); + + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS(urEnqueueUSMMemcpy(queue, true, device_ptr, output.data(), + size, 0, nullptr, nullptr)); + + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + + verifyData(output, input); +} diff --git a/unified-runtime/test/conformance/exp_command_buffer/fill.cpp b/unified-runtime/test/conformance/exp_command_buffer/fill.cpp index fd2bda518da74..a07030f8b330a 100644 --- a/unified-runtime/test/conformance/exp_command_buffer/fill.cpp +++ b/unified-runtime/test/conformance/exp_command_buffer/fill.cpp @@ -53,7 +53,8 @@ struct urCommandBufferFillCommandsTest testParametersFill>::TearDown()); } - void verifyData(std::vector &output, size_t verify_size) { + void verifyData(const std::vector &output, + const size_t verify_size) { size_t pattern_index = 0; for (size_t i = 0; i < verify_size; ++i) { ASSERT_EQ(output[i], pattern[pattern_index]) diff --git a/unified-runtime/test/conformance/exp_command_buffer/fixtures.h b/unified-runtime/test/conformance/exp_command_buffer/fixtures.h index be3df5f973d2d..9c6681123cb05 100644 --- a/unified-runtime/test/conformance/exp_command_buffer/fixtures.h +++ b/unified-runtime/test/conformance/exp_command_buffer/fixtures.h @@ -45,7 +45,6 @@ static void checkCommandBufferUpdateSupport( struct urCommandBufferExpTest : uur::urContextTest { void SetUp() override { - UUR_RETURN_ON_FATAL_FAILURE(uur::urContextTest::SetUp()); UUR_RETURN_ON_FATAL_FAILURE(checkCommandBufferSupport(device)); @@ -71,7 +70,6 @@ struct urCommandBufferExpTest : uur::urContextTest { template struct urCommandBufferExpTestWithParam : urQueueTestWithParam { void SetUp() override { - UUR_RETURN_ON_FATAL_FAILURE(uur::urQueueTestWithParam::SetUp()); UUR_RETURN_ON_FATAL_FAILURE(checkCommandBufferSupport(this->device)); @@ -95,7 +93,6 @@ struct urCommandBufferExpTestWithParam : urQueueTestWithParam { struct urCommandBufferExpExecutionTest : uur::urKernelExecutionTest { void SetUp() override { - UUR_RETURN_ON_FATAL_FAILURE(uur::urKernelExecutionTest::SetUp()); UUR_RETURN_ON_FATAL_FAILURE(checkCommandBufferSupport(device)); @@ -156,7 +153,6 @@ struct urUpdatableCommandBufferExpTest : uur::urQueueTest { struct urUpdatableCommandBufferExpExecutionTest : uur::urKernelExecutionTest { void SetUp() override { UUR_KNOWN_FAILURE_ON(uur::LevelZeroV2{}); - UUR_RETURN_ON_FATAL_FAILURE(uur::urKernelExecutionTest::SetUp()); ASSERT_SUCCESS(urPlatformGetInfo(platform, UR_PLATFORM_INFO_BACKEND, diff --git a/unified-runtime/test/conformance/exp_command_buffer/read.cpp b/unified-runtime/test/conformance/exp_command_buffer/read.cpp new file mode 100644 index 0000000000000..933f3adb64433 --- /dev/null +++ b/unified-runtime/test/conformance/exp_command_buffer/read.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2025 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See LICENSE.TXT +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "fixtures.h" + +struct testParametersRead { + size_t size; + size_t offset; + size_t read_size; +}; + +struct urCommandBufferReadCommandsTest + : uur::command_buffer::urCommandBufferExpTestWithParam { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersRead>::SetUp()); + + size = std::get<1>(GetParam()).size; + offset = std::get<1>(GetParam()).offset; + read_size = std::get<1>(GetParam()).read_size; + assert(size <= offset + read_size); + // Allocate USM pointers + ASSERT_SUCCESS( + urUSMDeviceAlloc(context, device, nullptr, nullptr, size, &device_ptr)); + ASSERT_NE(device_ptr, nullptr); + + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, size, + nullptr, &buffer)); + + ASSERT_NE(buffer, nullptr); + } + + void TearDown() override { + if (device_ptr) { + EXPECT_SUCCESS(urUSMFree(context, device_ptr)); + } + + if (buffer) { + EXPECT_SUCCESS(urMemRelease(buffer)); + } + + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersRead>::TearDown()); + } + + void verifyData(const std::vector &output, + const std::vector &input) { + for (size_t i = 0; i < read_size; ++i) { + ASSERT_EQ(output[i], input[i + offset]) + << "Result mismatch at index: " << i; + } + } + + size_t size, read_size, offset; + + void *device_ptr = nullptr; + ur_mem_handle_t buffer = nullptr; +}; + +static std::vector test_cases{ + // read whole buffer + {1, 0, 1}, + {256, 0, 256}, + {1024, 0, 1024}, + // read part of buffer + {256, 127, 128}, + {1024, 256, 256}, +}; + +template +static std::string +printReadTestString(const testing::TestParamInfo &info) { + const auto device_handle = std::get<0>(info.param).device; + const auto platform_device_name = + uur::GetPlatformAndDeviceName(device_handle); + std::stringstream test_name; + test_name << platform_device_name << "__size__" + << std::get<1>(info.param).size << "__offset__" + << std::get<1>(info.param).offset << "__read_size__" + << std::get<1>(info.param).read_size; + return test_name.str(); +} + +UUR_DEVICE_TEST_SUITE_WITH_PARAM( + urCommandBufferReadCommandsTest, testing::ValuesIn(test_cases), + printReadTestString); + +TEST_P(urCommandBufferReadCommandsTest, Buffer) { + std::vector input(size); + std::iota(input.begin(), input.end(), 1); + + std::vector output(size, 1); + ASSERT_SUCCESS(urEnqueueMemBufferWrite(queue, buffer, true, 0, size, + input.data(), 0, nullptr, nullptr)); + + ASSERT_SUCCESS(urCommandBufferAppendMemBufferReadExp( + cmd_buf_handle, buffer, offset, read_size, output.data(), 0, nullptr, 0, + nullptr, nullptr, nullptr, nullptr)); + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + + verifyData(output, input); +} diff --git a/unified-runtime/test/conformance/exp_command_buffer/rect_read.cpp b/unified-runtime/test/conformance/exp_command_buffer/rect_read.cpp new file mode 100644 index 0000000000000..a0adf21ac7de2 --- /dev/null +++ b/unified-runtime/test/conformance/exp_command_buffer/rect_read.cpp @@ -0,0 +1,147 @@ +// Copyright (C) 2025 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See LICENSE.TXT +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include "../enqueue/helpers.h" +#include "fixtures.h" +#include +#include + +// Choose parameters so that we get good coverage and catch some edge cases. +static std::vector generateParameterizations() { + std::vector parameterizations; + +// Choose parameters so that we get good coverage and catch some edge cases. +#define PARAMETERIZATION(name, src_buffer_size, dst_buffer_size, src_origin, \ + dst_origin, region, src_row_pitch, src_slice_pitch, \ + dst_row_pitch, dst_slice_pitch) \ + uur::test_parameters_t \ + name{#name, src_buffer_size, dst_buffer_size, src_origin, \ + dst_origin, region, src_row_pitch, src_slice_pitch, \ + dst_row_pitch, dst_slice_pitch}; \ + parameterizations.push_back(name); \ + (void)0 + // Tests that a 16x16x1 region can be read from a 16x16x1 device buffer at + // offset {0,0,0} to a 16x16x1 host buffer at offset {0,0,0}. + PARAMETERIZATION(write_whole_buffer_2D, 256, 256, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 0, 0}), (ur_rect_region_t{16, 16, 1}), + 16, 256, 16, 256); + // Tests that a 2x2x1 region can be read from a 4x4x1 device buffer at + // offset {2,2,0} to a 8x4x1 host buffer at offset {4,2,0}. + PARAMETERIZATION(write_non_zero_offsets_2D, 16, 32, + (ur_rect_offset_t{2, 2, 0}), (ur_rect_offset_t{4, 2, 0}), + (ur_rect_region_t{2, 2, 1}), 4, 16, 8, 32); + // Tests that a 4x4x1 region can be read from a 4x4x16 device buffer at + // offset {0,0,0} to a 8x4x16 host buffer at offset {4,0,0}. + PARAMETERIZATION(write_different_buffer_sizes_2D, 256, 512, + (ur_rect_offset_t{0, 0, 0}), (ur_rect_offset_t{4, 0, 0}), + (ur_rect_region_t{4, 4, 1}), 4, 16, 8, 32); + // Tests that a 1x256x1 region can be read from a 1x256x1 device buffer at + // offset {0,0,0} to a 2x256x1 host buffer at offset {1,0,0}. + PARAMETERIZATION(write_column_2D, 256, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{1, 0, 0}), (ur_rect_region_t{1, 256, 1}), + 1, 256, 2, 512); + // Tests that a 256x1x1 region can be read from a 256x1x1 device buffer at + // offset {0,0,0} to a 256x2x1 host buffer at offset {0,1,0}. + PARAMETERIZATION(write_row_2D, 256, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 1, 0}), (ur_rect_region_t{256, 1, 1}), + 256, 256, 256, 512); + // Tests that a 8x8x8 region can be read from a 8x8x8 device buffer at + // offset {0,0,0} to a 8x8x8 host buffer at offset {0,0,0}. + PARAMETERIZATION(write_3d, 512, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 0, 0}), (ur_rect_region_t{8, 8, 8}), 8, + 64, 8, 64); + // Tests that a 4x3x2 region can be read from a 8x8x8 device buffer at + // offset {1,2,3} to a 8x8x8 host buffer at offset {4,1,3}. + PARAMETERIZATION(write_3d_with_offsets, 512, 512, (ur_rect_offset_t{1, 2, 3}), + (ur_rect_offset_t{4, 1, 3}), (ur_rect_region_t{4, 3, 2}), 8, + 64, 8, 64); + // Tests that a 4x16x2 region can be read from a 8x32x1 device buffer at + // offset {1,2,0} to a 8x32x4 host buffer at offset {4,1,3}. + PARAMETERIZATION(write_2d_3d, 256, 1024, (ur_rect_offset_t{1, 2, 0}), + (ur_rect_offset_t{4, 1, 3}), (ur_rect_region_t{4, 16, 1}), 8, + 256, 8, 256); + // Tests that a 1x4x1 region can be read from a 8x16x4 device buffer at + // offset {7,3,3} to a 2x8x1 host buffer at offset {1,3,0}. + // PARAMETERIZATION(write_3d_2d, 512, 16, (ur_rect_offset_t{7, 3, 3}), + // (ur_rect_offset_t{1, 3, 0}), (ur_rect_region_t{1, 4, 1}), 8, + // 128, 2, 16); +#undef PARAMETERIZATION + return parameterizations; +} + +struct urCommandBufferAppendMemBufferReadRectTestWithParam + : public uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t> { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t>::SetUp()); + + host_size = getParam().src_size; + buffer_size = getParam().dst_size; + host_origin = getParam().src_origin; + buffer_origin = getParam().dst_origin; + region = getParam().region; + host_row_pitch = getParam().src_row_pitch; + host_slice_pitch = getParam().src_slice_pitch; + buffer_row_pitch = getParam().dst_row_pitch; + buffer_slice_pitch = getParam().dst_slice_pitch; + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, + buffer_size, nullptr, &buffer)); + + ASSERT_NE(buffer, nullptr); + } + + void TearDown() override { + if (buffer) { + EXPECT_SUCCESS(urMemRelease(buffer)); + } + + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t>::TearDown()); + } + size_t host_size = 0, buffer_size = 0; + ur_rect_offset_t host_origin, buffer_origin; + ur_rect_region_t region; + size_t host_row_pitch, host_slice_pitch, buffer_row_pitch, buffer_slice_pitch; + ur_mem_handle_t buffer = nullptr; +}; + +UUR_DEVICE_TEST_SUITE_WITH_PARAM( + urCommandBufferAppendMemBufferReadRectTestWithParam, + testing::ValuesIn(generateParameterizations()), + uur::printRectTestString< + urCommandBufferAppendMemBufferReadRectTestWithParam>); + +TEST_P(urCommandBufferAppendMemBufferReadRectTestWithParam, Success) { + UUR_KNOWN_FAILURE_ON(uur::LevelZero{}); + + // The input will just be sequentially increasing values. + std::vector input(buffer_size, 0x0); + std::iota(std::begin(input), std::end(input), 0x0); + EXPECT_SUCCESS(urEnqueueMemBufferWrite(queue, buffer, /* isBlocking */ true, + 0, input.size(), input.data(), 0, + nullptr, nullptr)); + + // Enqueue the rectangular read. + std::vector output(host_size, 0x0); + EXPECT_SUCCESS(urCommandBufferAppendMemBufferReadRectExp( + cmd_buf_handle, buffer, buffer_origin, host_origin, region, + buffer_row_pitch, buffer_slice_pitch, host_row_pitch, host_slice_pitch, + output.data(), 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr)); + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + // Do host side equivalent. + std::vector expected(host_size, 0x0); + uur::copyRect(input, buffer_origin, host_origin, region, buffer_row_pitch, + buffer_slice_pitch, host_row_pitch, host_slice_pitch, expected); + + // Verify the results. + EXPECT_EQ(expected, output); +} diff --git a/unified-runtime/test/conformance/exp_command_buffer/rect_write.cpp b/unified-runtime/test/conformance/exp_command_buffer/rect_write.cpp new file mode 100644 index 0000000000000..7c63be305c12f --- /dev/null +++ b/unified-runtime/test/conformance/exp_command_buffer/rect_write.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2025 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See LICENSE.TXT +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include "../enqueue/helpers.h" +#include "fixtures.h" +#include +#include + +static std::vector generateParameterizations() { + std::vector parameterizations; + +// Choose parameters so that we get good coverage and catch some edge cases. +#define PARAMETERIZATION(name, src_buffer_size, dst_buffer_size, src_origin, \ + dst_origin, region, src_row_pitch, src_slice_pitch, \ + dst_row_pitch, dst_slice_pitch) \ + uur::test_parameters_t \ + name{#name, src_buffer_size, dst_buffer_size, src_origin, \ + dst_origin, region, src_row_pitch, src_slice_pitch, \ + dst_row_pitch, dst_slice_pitch}; \ + parameterizations.push_back(name); \ + (void)0 + // Tests that a 16x16x1 region can be written from a 16x16x1 host buffer at + // offset {0,0,0} to a 16x16x1 device buffer at offset {0,0,0}. + PARAMETERIZATION(write_whole_buffer_2D, 256, 256, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 0, 0}), (ur_rect_region_t{16, 16, 1}), + 16, 256, 16, 256); + // Tests that a 2x2x1 region can be written from a 4x4x1 host buffer at + // offset {2,2,0} to a 8x4x1 device buffer at offset {4,2,0}. + PARAMETERIZATION(write_non_zero_offsets_2D, 16, 32, + (ur_rect_offset_t{2, 2, 0}), (ur_rect_offset_t{4, 2, 0}), + (ur_rect_region_t{2, 2, 1}), 4, 16, 8, 32); + // Tests that a 4x4x1 region can be written from a 4x4x16 host buffer at + // offset {0,0,0} to a 8x4x16 device buffer at offset {4,0,0}. + PARAMETERIZATION(write_different_buffer_sizes_2D, 256, 512, + (ur_rect_offset_t{0, 0, 0}), (ur_rect_offset_t{4, 0, 0}), + (ur_rect_region_t{4, 4, 1}), 4, 16, 8, 32); + // Tests that a 1x256x1 region can be written from a 1x256x1 host buffer at + // offset {0,0,0} to a 2x256x1 device buffer at offset {1,0,0}. + PARAMETERIZATION(write_column_2D, 256, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{1, 0, 0}), (ur_rect_region_t{1, 256, 1}), + 1, 256, 2, 512); + // Tests that a 256x1x1 region can be written from a 256x1x1 host buffer at + // offset {0,0,0} to a 256x2x1 device buffer at offset {0,1,0}. + PARAMETERIZATION(write_row_2D, 256, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 1, 0}), (ur_rect_region_t{256, 1, 1}), + 256, 256, 256, 512); + // Tests that a 8x8x8 region can be written from a 8x8x8 host buffer at + // offset {0,0,0} to a 8x8x8 device buffer at offset {0,0,0}. + PARAMETERIZATION(write_3D, 512, 512, (ur_rect_offset_t{0, 0, 0}), + (ur_rect_offset_t{0, 0, 0}), (ur_rect_region_t{8, 8, 8}), 8, + 64, 8, 64); + // Tests that a 4x3x2 region can be written from a 8x8x8 host buffer at + // offset {1,2,3} to a 8x8x8 device buffer at offset {4,1,3}. + PARAMETERIZATION(write_3D_with_offsets, 512, 512, (ur_rect_offset_t{1, 2, 3}), + (ur_rect_offset_t{4, 1, 3}), (ur_rect_region_t{4, 3, 2}), 8, + 64, 8, 64); + // Tests that a 4x16x2 region can be written from a 8x32x1 host buffer at + // offset {1,2,0} to a 8x32x4 device buffer at offset {4,1,3}. + // PARAMETERIZATION(write_2D_3D, 256, 1024, (ur_rect_offset_t{1, 2, 0}), + // (ur_rect_offset_t{4, 1, 3}), (ur_rect_region_t{4, 16, 1}), 8, + // 256, 8, 256); + // Tests that a 1x4x1 region can be written from a 8x16x4 host buffer at + // offset {7,3,3} to a 2x8x1 device buffer at offset {1,3,0}. + // PARAMETERIZATION(write_3D_2D, 512, 16, (ur_rect_offset_t{7, 3, 3}), + // (ur_rect_offset_t{1, 3, 0}), (ur_rect_region_t{1, 4, 1}), 8, + // 128, 2, 16); +#undef PARAMETERIZATION + return parameterizations; +} + +struct urCommandBufferAppendMemBufferWriteRectTestWithParam + : public uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t> { + + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t>::SetUp()); + + host_size = getParam().src_size; + buffer_size = getParam().dst_size; + host_origin = getParam().src_origin; + buffer_origin = getParam().dst_origin; + region = getParam().region; + host_row_pitch = getParam().src_row_pitch; + host_slice_pitch = getParam().src_slice_pitch; + buffer_row_pitch = getParam().dst_row_pitch; + buffer_slice_pitch = getParam().dst_slice_pitch; + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, + buffer_size, nullptr, &buffer)); + + ASSERT_NE(buffer, nullptr); + } + + void TearDown() override { + if (buffer) { + EXPECT_SUCCESS(urMemRelease(buffer)); + } + + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + uur::test_parameters_t>::TearDown()); + } + size_t host_size = 0, buffer_size = 0; + ur_rect_offset_t host_origin, buffer_origin; + ur_rect_region_t region; + size_t host_row_pitch, host_slice_pitch, buffer_row_pitch, buffer_slice_pitch; + ur_mem_handle_t buffer = nullptr; +}; + +UUR_DEVICE_TEST_SUITE_WITH_PARAM( + urCommandBufferAppendMemBufferWriteRectTestWithParam, + testing::ValuesIn(generateParameterizations()), + uur::printRectTestString< + urCommandBufferAppendMemBufferWriteRectTestWithParam>); + +TEST_P(urCommandBufferAppendMemBufferWriteRectTestWithParam, Success) { + const auto name = getParam().name; + + // This file is based on enqueue/urEnqueueMemBufferWriteRect.cpp + // because of this, these checks are present here, + // since there were present in original code + if (name.find("write_row_2D") != std::string::npos) { + UUR_KNOWN_FAILURE_ON(uur::HIP{}); + } + + if (name.find("write_3D_2D") != std::string::npos) { + UUR_KNOWN_FAILURE_ON(uur::HIP{}); + } + + UUR_KNOWN_FAILURE_ON(uur::LevelZero{}); + + // Zero it to begin with since the write may not cover the whole buffer. + const uint8_t zero = 0x0; + ASSERT_SUCCESS(urEnqueueMemBufferFill(queue, buffer, &zero, sizeof(zero), 0, + buffer_size, 0, nullptr, nullptr)); + + // Create a host buffer of sequentially increasing values. + + std::vector input(host_size, 0x0); + std::iota(std::begin(input), std::end(input), 0x0); + EXPECT_SUCCESS(urCommandBufferAppendMemBufferWriteRectExp( + cmd_buf_handle, buffer, buffer_origin, host_origin, region, + buffer_row_pitch, buffer_slice_pitch, host_row_pitch, host_slice_pitch, + input.data(), 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr)); + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + + std::vector output(buffer_size, 0x0); + EXPECT_SUCCESS(urEnqueueMemBufferRead(queue, buffer, /* is_blocking */ true, + 0, buffer_size, output.data(), 0, + nullptr, nullptr)); + + // Do host side equivalent. + std::vector expected(buffer_size, 0x0); + uur::copyRect(input, host_origin, buffer_origin, region, host_row_pitch, + host_slice_pitch, buffer_row_pitch, buffer_slice_pitch, + expected); + + // Verify the results. + EXPECT_EQ(expected, output); +} \ No newline at end of file diff --git a/unified-runtime/test/conformance/exp_command_buffer/update/invalid_update.cpp b/unified-runtime/test/conformance/exp_command_buffer/update/invalid_update.cpp index fea62b1c57f9d..0c40188c14cc1 100644 --- a/unified-runtime/test/conformance/exp_command_buffer/update/invalid_update.cpp +++ b/unified-runtime/test/conformance/exp_command_buffer/update/invalid_update.cpp @@ -7,6 +7,7 @@ #include "../fixtures.h" #include #include +#include // Negative tests that correct error codes are thrown on invalid update usage. struct InvalidUpdateTest diff --git a/unified-runtime/test/conformance/exp_command_buffer/write.cpp b/unified-runtime/test/conformance/exp_command_buffer/write.cpp new file mode 100644 index 0000000000000..2ebd827fd9e75 --- /dev/null +++ b/unified-runtime/test/conformance/exp_command_buffer/write.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2025 Intel Corporation +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See LICENSE.TXT +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "fixtures.h" + +struct testParametersWrite { + size_t size; + size_t offset; + size_t write_size; +}; + +struct urCommandBufferWriteCommandsTest + : uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersWrite> { + void SetUp() override { + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersWrite>::SetUp()); + + size = std::get<1>(GetParam()).size; + offset = std::get<1>(GetParam()).offset; + write_size = std::get<1>(GetParam()).write_size; + assert(size <= offset + write_size); + // Allocate USM pointers + ASSERT_SUCCESS( + urUSMDeviceAlloc(context, device, nullptr, nullptr, size, &device_ptr)); + ASSERT_NE(device_ptr, nullptr); + + ASSERT_SUCCESS(urMemBufferCreate(context, UR_MEM_FLAG_READ_WRITE, size, + nullptr, &buffer)); + + ASSERT_NE(buffer, nullptr); + } + + void TearDown() override { + if (device_ptr) { + EXPECT_SUCCESS(urUSMFree(context, device_ptr)); + } + + if (buffer) { + EXPECT_SUCCESS(urMemRelease(buffer)); + } + + UUR_RETURN_ON_FATAL_FAILURE( + uur::command_buffer::urCommandBufferExpTestWithParam< + testParametersWrite>::TearDown()); + } + + void verifyData(const std::vector &output, + const std::vector &input) { + for (size_t i = 0; i < write_size; ++i) { + ASSERT_EQ(output[i + offset], input[i]) + << "Result mismatch at index: " << i; + } + for (size_t i = 0; i < offset; ++i) { + ASSERT_EQ(output[i], BASE_VALUE) << "Result mismatch at index: " << i; + } + for (size_t i = offset + write_size; i < size; ++i) { + ASSERT_EQ(output[i], BASE_VALUE) << "Result mismatch at index: " << i; + } + } + + const uint8_t BASE_VALUE = 1; + size_t size, write_size, offset; + + void *device_ptr = nullptr; + ur_mem_handle_t buffer = nullptr; +}; + +static std::vector test_cases{ + // write whole buffer + {1, 0, 1}, + {256, 0, 256}, + {1024, 0, 1024}, + // write part of buffer + {256, 127, 128}, + {1024, 256, 256}, +}; + +template +static std::string printWriteTestString( + const testing::TestParamInfo &info) { + const auto device_handle = std::get<0>(info.param).device; + const auto platform_device_name = + uur::GetPlatformAndDeviceName(device_handle); + std::stringstream test_name; + test_name << platform_device_name << "__size__" + << std::get<1>(info.param).size << "__offset__" + << std::get<1>(info.param).offset << "__write_size__" + << std::get<1>(info.param).write_size; + return test_name.str(); +} + +UUR_DEVICE_TEST_SUITE_WITH_PARAM( + urCommandBufferWriteCommandsTest, testing::ValuesIn(test_cases), + printWriteTestString); + +TEST_P(urCommandBufferWriteCommandsTest, Buffer) { + std::vector input(size); + std::iota(input.begin(), input.end(), 1); + + std::vector output(size, BASE_VALUE); + ASSERT_SUCCESS(urCommandBufferAppendMemBufferWriteExp( + cmd_buf_handle, buffer, offset, write_size, input.data(), 0, nullptr, 0, + nullptr, nullptr, nullptr, nullptr)); + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + + ASSERT_SUCCESS(urEnqueueMemBufferWrite(queue, buffer, true, 0, size, + output.data(), 0, nullptr, nullptr)); + ASSERT_SUCCESS( + urEnqueueCommandBufferExp(queue, cmd_buf_handle, 0, nullptr, nullptr)); + ASSERT_SUCCESS(urQueueFinish(queue)); + + ASSERT_SUCCESS(urEnqueueMemBufferRead(queue, buffer, true, 0, size, + output.data(), 0, nullptr, nullptr)); + verifyData(output, input); +}