/* * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. * * SPDX-License-Identifier: MIT */ #include #include #include #include #include "graph_tests_common.hh" /** * @addtogroup hipGraphAddMemcpyNode hipGraphAddMemcpyNode * @{ * @ingroup GraphTest * `hipGraphAddMemcpyNode(hipGraphNode_t *pGraphNode, hipGraph_t graph, const * hipGraphNode_t *pDependencies, size_t numDependencies, const hipMemcpy3DParms * *pCopyParams)` - Creates a memcpy node and adds it to a graph */ /** * Test Description * ------------------------ * - Verify basic API behavior. A Memcpy node is created with parameters set according to the * test run, after which the graph is run and the memcpy results are verified. * The test is run for all possible memcpy directions, with both the corresponding memcpy * kind and hipMemcpyDefault, as well as half page and full page allocation sizes. * Test source * ------------------------ * - unit/graph/hipGraphAddMemcpyNode.cc * Test requirements * ------------------------ * - HIP_VERSION >= 5.2 */ HIP_TEST_CASE(Unit_hipGraphAddMemcpyNode_Positive_Basic) { CHECK_IMAGE_SUPPORT constexpr bool async = false; SECTION("Device to host") { Memcpy3DDeviceToHostShell(Memcpy3DWrapper); } SECTION("Device to host with default kind") { Memcpy3DDeviceToHostShell(Memcpy3DWrapper); } SECTION("Host to device") { Memcpy3DHostToDeviceShell(Memcpy3DWrapper); } SECTION("Host to device with default kind") { Memcpy3DHostToDeviceShell(Memcpy3DWrapper); } SECTION("Host to host") { Memcpy3DHostToHostShell(Memcpy3DWrapper); } SECTION("Host to host with default kind") { Memcpy3DHostToHostShell(Memcpy3DWrapper); } SECTION("Device to device") { SECTION("Peer access enabled") { Memcpy3DDeviceToDeviceShell(Memcpy3DWrapper); } SECTION("Peer access disabled") { Memcpy3DDeviceToDeviceShell(Memcpy3DWrapper); } } SECTION("Device to device with default kind") { SECTION("Peer access enabled") { Memcpy3DDeviceToDeviceShell(Memcpy3DWrapper); } SECTION("Peer access disabled") { Memcpy3DDeviceToDeviceShell(Memcpy3DWrapper); } } SECTION("Array from/to Host") { Memcpy3DArrayHostShell(Memcpy3DWrapper); } #if HT_NVIDIA // Disabled on AMD due to defect - EXSWHTEC-220 SECTION("Array from/to Device") { Memcpy3DArrayDeviceShell(Memcpy3DWrapper); } #endif } /** * Test Description * ------------------------ * - Verify API behaviour with invalid arguments: * -# node is nullptr * -# graph is nullptr * -# pCopyParams is nullptr * -# pDependencies is nullptr when numDependencies is zero * -# pDependencies is nullptr when numDependencies is not zero * -# A node in pDependencies originates from a different graph * -# numDependencies is invalid * -# A node is duplicated in pDependencies * -# srcArray and srcPtr.ptr are both nullptr * -# dstArray and dstPtr.ptr are both nullptr * -# srcArray and dstArray use incompatible extents * -# dst is nullptr * -# src is nullptr * -# kind is an invalid enum value * -# count is zero * -# count is larger than dst allocation size * -# count is larger than src allocation size * Test source * ------------------------ * - unit/graph/hipGraphAddMemcpyNode.cc * Test requirements * ------------------------ * - HIP_VERSION >= 5.2 */ HIP_TEST_CASE(Unit_hipGraphAddMemcpyNode_Negative_Parameters) { CHECK_IMAGE_SUPPORT using namespace std::placeholders; constexpr hipExtent extent{128 * sizeof(int), 128, 8}; constexpr auto NegativeTests = [](hipPitchedPtr dst_ptr, hipPos dst_pos, hipPitchedPtr src_ptr, hipPos src_pos, hipExtent extent, hipMemcpyKind kind) { hipGraph_t graph = nullptr; HIP_CHECK(hipGraphCreate(&graph, 0)); hipGraphNode_t node = nullptr; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, src_ptr, src_pos, extent, kind); GraphAddNodeCommonNegativeTests(std::bind(hipGraphAddMemcpyNode, _1, _2, _3, _4, ¶ms), graph); SECTION("pCopyParams == nullptr") { HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, nullptr), hipErrorInvalidValue); } SECTION("pDependencies == nullptr with numDependencies == 0") { HIP_CHECK(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms)); } SECTION("dst_ptr.ptr == nullptr") { hipPitchedPtr invalid_ptr = dst_ptr; invalid_ptr.ptr = nullptr; auto params = GetMemcpy3DParms(invalid_ptr, dst_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("src_ptr.ptr == nullptr") { hipPitchedPtr invalid_ptr = src_ptr; invalid_ptr.ptr = nullptr; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, invalid_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("dst_ptr.pitch < width") { hipPitchedPtr invalid_ptr = dst_ptr; invalid_ptr.pitch = extent.width - 1; auto params = GetMemcpy3DParms(invalid_ptr, dst_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidPitchValue); } SECTION("src_ptr.pitch < width") { hipPitchedPtr invalid_ptr = src_ptr; invalid_ptr.pitch = extent.width - 1; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, invalid_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidPitchValue); } SECTION("dst_ptr.pitch > max pitch") { int attr = 0; HIP_CHECK(hipDeviceGetAttribute(&attr, hipDeviceAttributeMaxPitch, 0)); hipPitchedPtr invalid_ptr = dst_ptr; invalid_ptr.pitch = attr; auto params = GetMemcpy3DParms(invalid_ptr, dst_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("src_ptr.pitch > max pitch") { int attr = 0; HIP_CHECK(hipDeviceGetAttribute(&attr, hipDeviceAttributeMaxPitch, 0)); hipPitchedPtr invalid_ptr = src_ptr; invalid_ptr.pitch = attr; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, invalid_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("extent.width + dst_pos.x > dst_ptr.pitch") { hipPos invalid_pos = dst_pos; invalid_pos.x = dst_ptr.pitch - extent.width + 1; auto params = GetMemcpy3DParms(dst_ptr, invalid_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("extent.width + src_pos.x > src_ptr.pitch") { hipPos invalid_pos = src_pos; invalid_pos.x = src_ptr.pitch - extent.width + 1; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, src_ptr, invalid_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("dst_pos.y out of bounds") { hipPos invalid_pos = dst_pos; invalid_pos.y = 1; auto params = GetMemcpy3DParms(dst_ptr, invalid_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("src_pos.y out of bounds") { hipPos invalid_pos = src_pos; invalid_pos.y = 1; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, src_ptr, invalid_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("dst_pos.z out of bounds") { hipPos invalid_pos = dst_pos; invalid_pos.z = 1; auto params = GetMemcpy3DParms(dst_ptr, invalid_pos, src_ptr, src_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("src_pos.z out of bounds") { hipPos invalid_pos = src_pos; invalid_pos.z = 1; auto params = GetMemcpy3DParms(dst_ptr, dst_pos, src_ptr, invalid_pos, extent, kind); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("Invalid MemcpyKind") { auto params = GetMemcpy3DParms(dst_ptr, dst_pos, src_ptr, src_pos, extent, static_cast(-1)); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidMemcpyDirection); } HIP_CHECK(hipGraphDestroy(graph)); }; SECTION("Host to Device") { LinearAllocGuard3D device_alloc(extent); LinearAllocGuard host_alloc( LinearAllocs::hipHostMalloc, device_alloc.pitch() * device_alloc.height() * device_alloc.depth()); NegativeTests(device_alloc.pitched_ptr(), make_hipPos(0, 0, 0), make_hipPitchedPtr(host_alloc.ptr(), device_alloc.pitch(), device_alloc.width(), device_alloc.height()), make_hipPos(0, 0, 0), extent, hipMemcpyHostToDevice); } SECTION("Device to Host") { LinearAllocGuard3D device_alloc(extent); LinearAllocGuard host_alloc( LinearAllocs::hipHostMalloc, device_alloc.pitch() * device_alloc.height() * device_alloc.depth()); NegativeTests(make_hipPitchedPtr(host_alloc.ptr(), device_alloc.pitch(), device_alloc.width(), device_alloc.height()), make_hipPos(0, 0, 0), device_alloc.pitched_ptr(), make_hipPos(0, 0, 0), extent, hipMemcpyDeviceToHost); } SECTION("Host to Host") { LinearAllocGuard src_alloc(LinearAllocs::hipHostMalloc, extent.width * extent.height * extent.depth); LinearAllocGuard dst_alloc(LinearAllocs::hipHostMalloc, extent.width * extent.height * extent.depth); NegativeTests(make_hipPitchedPtr(dst_alloc.ptr(), extent.width, extent.width, extent.height), make_hipPos(0, 0, 0), make_hipPitchedPtr(src_alloc.ptr(), extent.width, extent.width, extent.height), make_hipPos(0, 0, 0), extent, hipMemcpyHostToHost); } SECTION("Device to Device") { LinearAllocGuard3D src_alloc(extent); LinearAllocGuard3D dst_alloc(extent); NegativeTests(dst_alloc.pitched_ptr(), make_hipPos(0, 0, 0), src_alloc.pitched_ptr(), make_hipPos(0, 0, 0), extent, hipMemcpyDeviceToDevice); } SECTION("Array parameter combinations") { constexpr size_t width = 10; constexpr size_t height = 10; constexpr size_t depth = 10; const hipExtent array_extent = make_hipExtent(width, height, depth); constexpr size_t host_size = width * height * depth * sizeof(int); ArrayAllocGuard src_array(array_extent); ArrayAllocGuard dst_array(array_extent); LinearAllocGuard host_alloc(LinearAllocs::malloc, host_size); hipGraph_t graph = nullptr; HIP_CHECK(hipGraphCreate(&graph, 0)); hipGraphNode_t node = nullptr; SECTION("srcArray and srcPtr.ptr are nullptr") { hipMemcpy3DParms params = {}; params.dstArray = dst_array.ptr(); params.extent = array_extent; params.kind = hipMemcpyHostToDevice; HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("dstArray and dstPtr.ptr are nullptr") { hipMemcpy3DParms params = {}; params.srcPtr = make_hipPitchedPtr(host_alloc.ptr(), width * sizeof(int), width, height); params.extent = array_extent; params.kind = hipMemcpyHostToDevice; HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } SECTION("srcArray and dstArray use different extents") { const hipExtent mismatched_extent = make_hipExtent(width + 1, height + 1, depth + 1); ArrayAllocGuard mismatched_dst_array(mismatched_extent); auto params = GetMemcpy3DParms(dst_array.ptr(), make_hipPos(0, 0, 0), src_array.ptr(), make_hipPos(0, 0, 0), array_extent, hipMemcpyDeviceToDevice); params.dstArray = mismatched_dst_array.ptr(); HIP_CHECK_ERROR(hipGraphAddMemcpyNode(&node, graph, nullptr, 0, ¶ms), hipErrorInvalidValue); } HIP_CHECK(hipGraphDestroy(graph)); } } /** * End doxygen group GraphTest. * @} */