Merge 'develop' into 'amd-staging'

Change-Id: I2dce94151b89065a31619491e88d433d6133273a
Этот коммит содержится в:
Jenkins
2023-01-23 12:10:08 +00:00
родитель d50fb11890 315b14fe4e
Коммит 4a36acb7f0
61 изменённых файлов: 8521 добавлений и 3424 удалений
+5 -1
Просмотреть файл
@@ -83,7 +83,11 @@ def hipBuildTest(String backendLabel) {
sh """#!/usr/bin/env bash
set -x
cd build
ctest
if [[ $backendLabel =~ amd ]]; then
ctest
else
ctest -E 'Unit_hipMemcpyHtoD_Positive_Synchronization_Behavior|Unit_hipMemcpy_Positive_Synchronization_Behavior|Unit_hipFreeNegativeHost'
fi
"""
}
}
+8
Просмотреть файл
@@ -6,6 +6,9 @@ set(CMAKE_CXX_COMPILER_WORKS 1)
project(hiptests)
#forcing exe per file.
set(STANDALONE_TESTS 1)
message(STATUS "STANDALONE_TESTS : ${STANDALONE_TESTS}")
# Check if platform and compiler are set
if(HIP_PLATFORM STREQUAL "amd")
@@ -125,7 +128,12 @@ set(CATCH_BUILD_DIR catch_tests)
file(COPY ./hipTestMain/config DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CATCH_BUILD_DIR}/hipTestMain)
file(COPY ./external/Catch2/cmake/Catch2/CatchAddTests.cmake
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CATCH_BUILD_DIR}/script)
file(COPY ./external/Catch2/cmake/Catch2/catch_include.cmake
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CATCH_BUILD_DIR}/script)
set(ADD_SCRIPT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${CATCH_BUILD_DIR}/script/CatchAddTests.cmake)
set(CATCH_INCLUDE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${CATCH_BUILD_DIR}/script/catch_include.cmake)
if (WIN32)
configure_file(catchProp_in_rc.in ${CMAKE_CURRENT_BINARY_DIR}/catchProp.rc @ONLY)
+219 -53
Просмотреть файл
@@ -118,8 +118,10 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
# TARGET_LIST TEST_SET
function(catch_discover_tests_compile_time_detection TARGET TEST_SET)
cmake_parse_arguments(
""
""
@@ -140,28 +142,46 @@ function(catch_discover_tests TARGET)
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SET}_tests-${args_hash}.cmake")
foreach(EXE_NAME ${TARGET})
add_custom_command(
TARGET ${EXE_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${EXE_NAME}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${EXE_NAME}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "TEST_REPORTER=${_REPORTER}"
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
endforeach()
file(RELATIVE_PATH ctestincludepath ${CMAKE_CURRENT_BINARY_DIR} ${ctest_include_file})
file(RELATIVE_PATH ctestfilepath ${CMAKE_CURRENT_BINARY_DIR} ${ctest_tests_file})
file(RELATIVE_PATH _workdir ${CMAKE_CURRENT_BINARY_DIR} ${_WORKING_DIRECTORY})
file(RELATIVE_PATH _CATCH_ADD_TEST_SCRIPT ${CMAKE_CURRENT_BINARY_DIR} ${ADD_SCRIPT_PATH})
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctestfilepath}\")\n"
" include(\"${ctestfilepath}\")\n"
"else()\n"
" message(WARNING \"Test ${TARGET} not built yet.\")\n"
"endif()\n"
)
set(EXEC_NAME ${TARGET})
if(WIN32)
set(EXEC_NAME ${EXEC_NAME}.exe)
endif()
# uses catch_include.cmake.in file to generate the *_include.cmake file
# *_include.cmake is used to generate the *_test.cmake during execution of ctest cmd
configure_file(${CATCH2_INCLUDE} ${TARGET}_include-${args_hash}.cmake @ONLY)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctestincludepath}"
@@ -184,17 +204,61 @@ endfunction()
###############################################################################
#------------------------------------------------------------------------------
# current staging
function(catch_discover_tests TARGET_LIST TEST_SET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SET}_tests-${args_hash}.cmake")
file(RELATIVE_PATH ctestincludepath ${CMAKE_CURRENT_BINARY_DIR} ${ctest_include_file})
file(RELATIVE_PATH ctestfilepath ${CMAKE_CURRENT_BINARY_DIR} ${ctest_tests_file})
file(RELATIVE_PATH _CATCH_ADD_TEST_SCRIPT ${CMAKE_CURRENT_BINARY_DIR} ${ADD_SCRIPT_PATH})
file(RELATIVE_PATH CATCH_INCLUDE_PATH ${CMAKE_CURRENT_BINARY_DIR} ${CATCH_INCLUDE_PATH})
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
file(WRITE ${ctest_include_file} "set(exc_names ${TARGET_LIST})\n")
file(APPEND ${ctest_include_file} "set(TARGET ${TEST_SET})\n")
file(APPEND ${ctest_include_file} "set(_TEST_LIST ${TEST_SET}_TESTS)\n")
file(APPEND ${ctest_include_file} "set(ctestfilepath ${ctestfilepath})\n")
file(APPEND ${ctest_include_file} "set(_CATCH_ADD_TEST_SCRIPT ${_CATCH_ADD_TEST_SCRIPT})\n")
file(APPEND ${ctest_include_file} "set(crosscompiling_emulator ${crosscompiling_emulator})\n")
file(APPEND ${ctest_include_file} "set(_PROPERTIES ${_PROPERTIES})\n")
file(APPEND ${ctest_include_file} "include(${CATCH_INCLUDE_PATH})\n")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctestincludepath}"
)
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
)
###############################################################################
# function to be called by all tests
function(hip_add_exe_to_target)
function(hip_add_exe_to_target_compile_time_detection)
set(options)
# NAME EventTest, TEST_SRC src, TEST_TARGET_NAME build_tests
set(args NAME TEST_TARGET_NAME PLATFORM COMPILE_OPTIONS)
set(list_args TEST_SRC LINKER_LIBS PROPERTY)
set(list_args TEST_SRC LINKER_LIBS COMMON_SHARED_SRC PROPERTY)
cmake_parse_arguments(
PARSE_ARGV 0
"" # variable prefix
@@ -202,48 +266,150 @@ function(hip_add_exe_to_target)
"${args}"
"${list_args}"
)
# Create shared lib of all tests
if(NOT RTC_TESTING)
add_executable(${_NAME} EXCLUDE_FROM_ALL ${_TEST_SRC} $<TARGET_OBJECTS:Main_Object> $<TARGET_OBJECTS:KERNELS>)
else ()
add_executable(${_NAME} EXCLUDE_FROM_ALL ${_TEST_SRC} $<TARGET_OBJECTS:Main_Object>)
if(HIP_PLATFORM STREQUAL "amd")
target_link_libraries(${_NAME} hiprtc)
foreach(SRC_NAME ${TEST_SRC})
if(NOT STANDALONE_TESTS EQUAL "1")
set(_EXE_NAME ${_NAME})
# take the entire source set for building the executable
set(SRC_NAME ${TEST_SRC})
else()
target_link_libraries(${_NAME} nvrtc)
# strip extension of src and use exe name as src name
get_filename_component(_EXE_NAME ${SRC_NAME} NAME_WLE)
endif()
endif()
catch_discover_tests(${_NAME} PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST")
if(UNIX)
set(_LINKER_LIBS ${_LINKER_LIBS} stdc++fs)
set(_LINKER_LIBS ${_LINKER_LIBS} -ldl)
else()
# res files are built resource files using rc files.
# use llvm-rc exe to build the res files
# Thes are used to populate the properties of the built executables
if(EXISTS "${PROP_RC}/catchProp.res")
set(_LINKER_LIBS ${_LINKER_LIBS} "${PROP_RC}/catchProp.res")
if(NOT RTC_TESTING)
add_executable(${_EXE_NAME} EXCLUDE_FROM_ALL ${SRC_NAME} ${COMMON_SHARED_SRC} $<TARGET_OBJECTS:Main_Object> $<TARGET_OBJECTS:KERNELS>)
else ()
add_executable(${_EXE_NAME} EXCLUDE_FROM_ALL ${SRC_NAME} ${COMMON_SHARED_SRC} $<TARGET_OBJECTS:Main_Object>)
if(HIP_PLATFORM STREQUAL "amd")
target_link_libraries(${_EXE_NAME} hiprtc)
else()
target_link_libraries(${_EXE_NAME} nvrtc)
endif()
endif()
endif()
if(DEFINED _LINKER_LIBS)
target_link_libraries(${_NAME} ${_LINKER_LIBS})
endif()
# Add dependency on build_tests to build it on this custom target
add_dependencies(${_TEST_TARGET_NAME} ${_NAME})
if (DEFINED _PROPERTY)
set_property(TARGET ${_NAME} PROPERTY ${_PROPERTY})
endif()
if(UNIX)
set(_LINKER_LIBS ${_LINKER_LIBS} stdc++fs)
set(_LINKER_LIBS ${_LINKER_LIBS} -ldl)
else()
# res files are built resource files using rc files.
# use llvm-rc exe to build the res files
# Thes are used to populate the properties of the built executables
if(EXISTS "${PROP_RC}/catchProp.res")
set(_LINKER_LIBS ${_LINKER_LIBS} "${PROP_RC}/catchProp.res")
endif()
#set(_LINKER_LIBS ${_LINKER_LIBS} -noAutoResponse)
endif()
if (DEFINED _COMPILE_OPTIONS)
target_compile_options(${_NAME} PUBLIC ${_COMPILE_OPTIONS})
endif()
if(DEFINED _LINKER_LIBS)
target_link_libraries(${_EXE_NAME} ${_LINKER_LIBS})
endif()
foreach(arg IN LISTS _UNPARSED_ARGUMENTS)
message(WARNING "Unparsed arguments: ${arg}")
# Add dependency on build_tests to build it on this custom target
add_dependencies(${_TEST_TARGET_NAME} ${_EXE_NAME})
# add_dependencies(${_TEST_TARGET_NAME} ${_EXE_NAME})
if (DEFINED _PROPERTY)
set_property(TARGET ${_EXE_NAME} PROPERTY ${_PROPERTY})
endif()
if (DEFINED _COMPILE_OPTIONS)
target_compile_options(${_EXE_NAME} PUBLIC ${_COMPILE_OPTIONS})
endif()
foreach(arg IN LISTS _UNPARSED_ARGUMENTS)
message(WARNING "Unparsed arguments: ${arg}")
endforeach()
get_property(crosscompiling_emulator
TARGET ${_EXE_NAME}
PROPERTY CROSSCOMPILING_EMULATOR
)
set(_EXE_NAME_LIST ${_EXE_NAME_LIST} ${_EXE_NAME})
if(NOT STANDALONE_TESTS EQUAL "1")
break()
endif()
endforeach()
catch_discover_tests("${_EXE_NAME_LIST}" "${_NAME}" PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST")
endfunction()
###############################################################################
# current staging
# function to be called by all tests
function(hip_add_exe_to_target)
set(options)
set(args NAME TEST_TARGET_NAME PLATFORM COMPILE_OPTIONS)
set(list_args TEST_SRC LINKER_LIBS COMMON_SHARED_SRC PROPERTY)
cmake_parse_arguments(
PARSE_ARGV 0
"" # variable prefix
"${options}"
"${args}"
"${list_args}"
)
foreach(SRC_NAME ${TEST_SRC})
if(NOT STANDALONE_TESTS EQUAL "1")
set(_EXE_NAME ${_NAME})
set(SRC_NAME ${TEST_SRC})
else()
# strip extension of src and use exe name as src name
get_filename_component(_EXE_NAME ${SRC_NAME} NAME_WLE)
endif()
# Create shared lib of all tests
if(NOT RTC_TESTING)
add_executable(${_EXE_NAME} EXCLUDE_FROM_ALL ${SRC_NAME} ${COMMON_SHARED_SRC} $<TARGET_OBJECTS:Main_Object> $<TARGET_OBJECTS:KERNELS>)
else ()
add_executable(${_EXE_NAME} EXCLUDE_FROM_ALL ${SRC_NAME} ${COMMON_SHARED_SRC} $<TARGET_OBJECTS:Main_Object>)
if(HIP_PLATFORM STREQUAL "amd")
target_link_libraries(${_EXE_NAME} hiprtc)
else()
target_link_libraries(${_EXE_NAME} nvrtc)
endif()
endif()
if (DEFINED _PROPERTY)
set_property(TARGET ${_EXE_NAME} PROPERTY ${_PROPERTY})
endif()
if(UNIX)
set(_LINKER_LIBS ${_LINKER_LIBS} stdc++fs)
set(_LINKER_LIBS ${_LINKER_LIBS} -ldl)
set(_LINKER_LIBS ${_LINKER_LIBS} pthread)
set(_LINKER_LIBS ${_LINKER_LIBS} rt)
else()
# res files are built resource files using rc files.
# use llvm-rc exe to build the res files
# Thes are used to populate the properties of the built executables
if(EXISTS "${PROP_RC}/catchProp.res")
set(_LINKER_LIBS ${_LINKER_LIBS} "${PROP_RC}/catchProp.res")
endif()
endif()
if(DEFINED _LINKER_LIBS)
target_link_libraries(${_EXE_NAME} ${_LINKER_LIBS})
endif()
# Add dependency on build_tests to build it on this custom target
add_dependencies(${_TEST_TARGET_NAME} ${_EXE_NAME})
if (DEFINED _COMPILE_OPTIONS)
target_compile_options(${_EXE_NAME} PUBLIC ${_COMPILE_OPTIONS})
endif()
foreach(arg IN LISTS _UNPARSED_ARGUMENTS)
message(WARNING "Unparsed arguments: ${arg}")
endforeach()
get_property(crosscompiling_emulator
TARGET ${_EXE_NAME}
PROPERTY CROSSCOMPILING_EMULATOR
)
set(_EXE_NAME_LIST ${_EXE_NAME_LIST} ${_EXE_NAME})
if(NOT STANDALONE_TESTS EQUAL "1")
break()
endif()
endforeach()
catch_discover_tests("${_EXE_NAME_LIST}" "${_NAME}" PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST")
endfunction()
+1 -1
Просмотреть файл
@@ -135,4 +135,4 @@ endforeach()
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")
file(APPEND "${CTEST_FILE}" "${script}")
+41
Просмотреть файл
@@ -0,0 +1,41 @@
# when ctest is ran, each submodule includes this file to generate the <submodule>_tests.cmake file.
# <submodule>_tests.cmake contains the add_test macro which runs the individual test.
get_filename_component(_cmake_path cmake ABSOLUTE)
foreach(EXEC_NAME ${exc_names})
if(WIN32)
set(EXEC_NAME ${EXEC_NAME}.exe)
endif()
if(EXISTS "${EXEC_NAME}")
execute_process(
COMMAND "${_cmake_path}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=${EXEC_NAME}"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_workdir}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "TEST_REPORTER=${_REPORTER}"
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
-D "CTEST_FILE=${ctestfilepath}"
-P "${_CATCH_ADD_TEST_SCRIPT}"
OUTPUT_VARIABLE output
RESULT_VARIABLE result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
else()
message("executable not found : ${EXEC_NAME}" )
endif()
endforeach()
if(EXISTS "${ctestfilepath}")
# include the generated ctest file for execution
include(${ctestfilepath})
endif()
-34
Просмотреть файл
@@ -1,34 +0,0 @@
# File @ctestincludepath@ is generated by cmake.
# For changes please modify hip/tests/catch/external/Catch2/cmake/Catch2/catch_include.cmake.in
get_filename_component(_cmake_path cmake ABSOLUTE)
if(EXISTS "@EXEC_NAME@")
execute_process(
COMMAND "${_cmake_path}"
-D "TEST_TARGET=@TARGET@"
-D "TEST_EXECUTABLE=@EXEC_NAME@"
-D "TEST_EXECUTOR=@crosscompiling_emulator@"
-D "TEST_WORKING_DIR=@_workdir@"
-D "TEST_SPEC=@_TEST_SPEC@"
-D "TEST_EXTRA_ARGS=@_EXTRA_ARGS@"
-D "TEST_PROPERTIES=@_PROPERTIES@"
-D "TEST_PREFIX=@_TEST_PREFIX@"
-D "TEST_SUFFIX=@_TEST_SUFFIX@"
-D "TEST_LIST=@_TEST_LIST@"
-D "TEST_REPORTER=@_REPORTER@"
-D "TEST_OUTPUT_DIR=@_OUTPUT_DIR@"
-D "TEST_OUTPUT_PREFIX=@_OUTPUT_PREFIX@"
-D "TEST_OUTPUT_SUFFIX=@_OUTPUT_SUFFIX@"
-D "CTEST_FILE=@ctestfilepath@"
-P "@_CATCH_ADD_TEST_SCRIPT@"
OUTPUT_VARIABLE output
RESULT_VARIABLE result
WORKING_DIRECTORY "@TEST_WORKING_DIR@"
)
# include the generated ctest file for execution
include(@ctestfilepath@)
else()
message(STATUS "executable not built : @EXEC_NAME@" )
endif()
+2 -1
Просмотреть файл
@@ -7,7 +7,8 @@
"Unit_hipInit_Negative",
"Unit_BuiltinAtomicsRTC_fmaxCoherentGlobalMem",
"Unit_BuiltinAtomicsRTC__fminCoherentGlobalMem",
"Unit_BuiltInAtomicAdd_CoherentGlobalMemWithRtc"
"Unit_BuiltInAtomicAdd_CoherentGlobalMemWithRtc",
"Unit_hipMemGetAddressRange_Negative"
]
}
+9 -1
Просмотреть файл
@@ -17,6 +17,14 @@
"Unit_hipDeviceReset_Positive_Threaded",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ClonedGrph",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ChldNode"
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ChldNode",
"Unit_hipMemGetAddressRange_Negative",
"Unit_hipMemRangeGetAttribute_Positive_AccessedBy_Basic",
"Unit_hipMemRangeGetAttribute_Positive_AccessedBy_Partial_Range",
"Unit_hipMemRangeGetAttributes_Negative_Parameters",
"Unit_hipStreamAttachMemAsync_Positive_Basic",
"Unit_hipStreamAttachMemAsync_Positive_AttachGlobal",
"Unit_hipStreamAttachMemAsync_Negative_Parameters",
"Unit_hipMemGetAddressRange_Positive"
]
}
+2 -1
Просмотреть файл
@@ -92,6 +92,7 @@
"Unit_hipDeviceGetPCIBusId_Negative_PartialFill",
"Unit_hipInit_Negative",
"Unit_hipGraphAddEventRecordNode_Functional_ElapsedTime",
"Unit_hipStreamBeginCapture_captureComplexGraph"
"Unit_hipStreamBeginCapture_captureComplexGraph",
"Unit_hipMemGetAddressRange_Negative"
]
}
+3 -1
Просмотреть файл
@@ -96,6 +96,8 @@
"Unit_hipGraphAddEventRecordNode_Functional_WithoutFlags",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ClonedGrph",
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ChldNode"
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep_ChldNode",
"Unit_hipMemGetAddressRange_Negative",
"Unit_hipMemGetAddressRange_Positive"
]
}
+316
Просмотреть файл
@@ -0,0 +1,316 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <functional>
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#include <utils.hh>
#include <resource_guards.hh>
static inline unsigned int GenerateLinearAllocationFlagCombinations(
const LinearAllocs allocation_type) {
switch (allocation_type) {
case LinearAllocs::hipHostMalloc:
return GENERATE(hipHostMallocDefault, hipHostMallocPortable, hipHostMallocMapped,
hipHostMallocWriteCombined);
case LinearAllocs::mallocAndRegister:
case LinearAllocs::hipMallocManaged:
case LinearAllocs::malloc:
case LinearAllocs::hipMalloc:
return 0u;
default:
assert("Invalid LinearAllocs enumerator");
throw std::invalid_argument("Invalid LinearAllocs enumerator");
}
}
template <bool should_synchronize, typename F>
void MemcpyDeviceToHostShell(F memcpy_func, const hipStream_t kernel_stream = nullptr) {
using LA = LinearAllocs;
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
const auto host_allocation_type = GENERATE(LA::malloc, LA::hipHostMalloc);
const auto host_allocation_flags = GenerateLinearAllocationFlagCombinations(host_allocation_type);
LinearAllocGuard<int> host_allocation(host_allocation_type, allocation_size,
host_allocation_flags);
LinearAllocGuard<int> device_allocation(LA::hipMalloc, allocation_size);
const auto element_count = allocation_size / sizeof(*device_allocation.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int expected_value = 42;
VectorSet<<<block_count, thread_count, 0, kernel_stream>>>(device_allocation.ptr(),
expected_value, element_count);
HIP_CHECK(hipGetLastError());
HIP_CHECK(memcpy_func(host_allocation.host_ptr(), device_allocation.ptr(), allocation_size));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
ArrayFindIfNot(host_allocation.host_ptr(), expected_value, element_count);
}
template <bool should_synchronize, typename F>
void MemcpyHostToDeviceShell(F memcpy_func, const hipStream_t kernel_stream = nullptr) {
using LA = LinearAllocs;
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
const auto host_allocation_type = GENERATE(LA::malloc, LA::hipHostMalloc);
const auto host_allocation_flags = GenerateLinearAllocationFlagCombinations(host_allocation_type);
LinearAllocGuard<int> src_host_allocation(host_allocation_type, allocation_size,
host_allocation_flags);
LinearAllocGuard<int> dst_host_allocation(LA::hipHostMalloc, allocation_size);
LinearAllocGuard<int> device_allocation(LA::hipMalloc, allocation_size);
const auto element_count = allocation_size / sizeof(*device_allocation.ptr());
constexpr int fill_value = 42;
std::fill_n(src_host_allocation.host_ptr(), element_count, fill_value);
std::fill_n(dst_host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(memcpy_func(device_allocation.ptr(), src_host_allocation.host_ptr(), allocation_size));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
HIP_CHECK(hipMemcpy(dst_host_allocation.host_ptr(), device_allocation.ptr(), allocation_size,
hipMemcpyDeviceToHost));
ArrayFindIfNot(dst_host_allocation.host_ptr(), fill_value, element_count);
}
template <bool should_synchronize, typename F>
void MemcpyHostToHostShell(F memcpy_func, const hipStream_t kernel_stream = nullptr) {
using LA = LinearAllocs;
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
const auto src_allocation_type = GENERATE(LA::malloc, LA::hipHostMalloc);
const auto dst_allocation_type = GENERATE(LA::malloc, LA::hipHostMalloc);
const auto src_allocation_flags = GenerateLinearAllocationFlagCombinations(src_allocation_type);
const auto dst_allocation_flags = GenerateLinearAllocationFlagCombinations(dst_allocation_type);
LinearAllocGuard<int> src_allocation(src_allocation_type, allocation_size, src_allocation_flags);
LinearAllocGuard<int> dst_allocation(dst_allocation_type, allocation_size, dst_allocation_flags);
const auto element_count = allocation_size / sizeof(*src_allocation.host_ptr());
constexpr auto expected_value = 42;
std::fill_n(src_allocation.host_ptr(), element_count, expected_value);
HIP_CHECK(memcpy_func(dst_allocation.host_ptr(), src_allocation.host_ptr(), allocation_size));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
ArrayFindIfNot(dst_allocation.host_ptr(), expected_value, element_count);
}
template <bool should_synchronize, bool enable_peer_access, typename F>
void MemcpyDeviceToDeviceShell(F memcpy_func, const hipStream_t kernel_stream = nullptr) {
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
const auto device_count = HipTest::getDeviceCount();
const auto src_device = GENERATE_COPY(range(0, device_count));
const auto dst_device = GENERATE_COPY(range(0, device_count));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
HIP_CHECK(hipSetDevice(src_device));
if constexpr (enable_peer_access) {
if (src_device == dst_device) {
return;
}
int can_access_peer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (!can_access_peer) {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
REQUIRE(can_access_peer);
}
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
}
LinearAllocGuard<int> src_allocation(LinearAllocs::hipMalloc, allocation_size);
LinearAllocGuard<int> result(LinearAllocs::hipHostMalloc, allocation_size, hipHostMallocPortable);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_allocation(LinearAllocs::hipMalloc, allocation_size);
const auto element_count = allocation_size / sizeof(*src_allocation.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int expected_value = 42;
HIP_CHECK(hipSetDevice(src_device));
VectorSet<<<block_count, thread_count, 0, kernel_stream>>>(src_allocation.ptr(), expected_value,
element_count);
HIP_CHECK(hipGetLastError());
HIP_CHECK(memcpy_func(dst_allocation.ptr(), src_allocation.ptr(), allocation_size));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
HIP_CHECK(
hipMemcpy(result.host_ptr(), dst_allocation.ptr(), allocation_size, hipMemcpyDeviceToHost));
if constexpr (enable_peer_access) {
// If we've gotten this far, EnablePeerAccess must have succeeded, so we only need to check this
// condition
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
}
ArrayFindIfNot(result.host_ptr(), expected_value, element_count);
}
template <bool should_synchronize, typename F> void MemcpyWithDirectionCommonTests(F memcpy_func) {
using namespace std::placeholders;
SECTION("Device to host") {
MemcpyDeviceToHostShell<should_synchronize>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDeviceToHost));
}
SECTION("Device to host with default kind") {
MemcpyDeviceToHostShell<should_synchronize>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDefault));
}
SECTION("Host to device") {
MemcpyHostToDeviceShell<should_synchronize>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyHostToDevice));
}
SECTION("Host to device with default kind") {
MemcpyHostToDeviceShell<should_synchronize>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDefault));
}
SECTION("Host to host") {
MemcpyHostToHostShell<should_synchronize>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyHostToHost));
}
SECTION("Host to host with default kind") {
MemcpyHostToHostShell<should_synchronize>(std::bind(memcpy_func, _1, _2, _3, hipMemcpyDefault));
}
SECTION("Device to device") {
SECTION("Peer access enabled") {
MemcpyDeviceToDeviceShell<should_synchronize, true>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDeviceToDevice));
}
SECTION("Peer access disabled") {
MemcpyDeviceToDeviceShell<should_synchronize, false>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDeviceToDevice));
}
}
SECTION("Device to device with default kind") {
SECTION("Peer access enabled") {
MemcpyDeviceToDeviceShell<should_synchronize, true>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDefault));
}
SECTION("Peer access disabled") {
MemcpyDeviceToDeviceShell<should_synchronize, false>(
std::bind(memcpy_func, _1, _2, _3, hipMemcpyDefault));
}
}
}
// Synchronization behavior checks
template <typename F>
void MemcpySyncBehaviorCheck(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream) {
LaunchDelayKernel(std::chrono::milliseconds{100}, kernel_stream);
HIP_CHECK(memcpy_func());
if (should_sync) {
HIP_CHECK(hipStreamQuery(kernel_stream));
} else {
HIP_CHECK_ERROR(hipStreamQuery(kernel_stream), hipErrorNotReady);
}
}
template <typename F>
void MemcpyHtoDSyncBehavior(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
using LA = LinearAllocs;
const auto host_alloc_type = GENERATE(LA::malloc, LA::hipHostMalloc);
LinearAllocGuard<int> host_alloc(host_alloc_type, kPageSize);
LinearAllocGuard<int> device_alloc(LA::hipMalloc, kPageSize);
MemcpySyncBehaviorCheck(std::bind(memcpy_func, device_alloc.ptr(), host_alloc.ptr(), kPageSize),
should_sync, kernel_stream);
}
template <typename F>
void MemcpyDtoHPageableSyncBehavior(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
LinearAllocGuard<int> host_alloc(LinearAllocs::malloc, kPageSize);
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
MemcpySyncBehaviorCheck(std::bind(memcpy_func, host_alloc.ptr(), device_alloc.ptr(), kPageSize),
should_sync, kernel_stream);
}
template <typename F>
void MemcpyDtoHPinnedSyncBehavior(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, kPageSize);
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
MemcpySyncBehaviorCheck(std::bind(memcpy_func, host_alloc.ptr(), device_alloc.ptr(), kPageSize),
should_sync, kernel_stream);
}
template <typename F>
void MemcpyDtoDSyncBehavior(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
MemcpySyncBehaviorCheck(std::bind(memcpy_func, dst_alloc.ptr(), src_alloc.ptr(), kPageSize),
should_sync, kernel_stream);
}
template <typename F>
void MemcpyHtoHSyncBehavior(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
using LA = LinearAllocs;
const auto src_alloc_type = GENERATE(LA::malloc, LA::hipHostMalloc);
const auto dst_alloc_type = GENERATE(LA::malloc, LA::hipHostMalloc);
LinearAllocGuard<int> src_alloc(src_alloc_type, kPageSize);
LinearAllocGuard<int> dst_alloc(dst_alloc_type, kPageSize);
MemcpySyncBehaviorCheck(std::bind(memcpy_func, dst_alloc.ptr(), src_alloc.ptr(), kPageSize),
should_sync, kernel_stream);
}
// Common negative tests
template <typename F> void MemcpyCommonNegativeTests(F f, void* dst, void* src, size_t count) {
SECTION("dst == nullptr") { HIP_CHECK_ERROR(f(nullptr, src, count), hipErrorInvalidValue); }
SECTION("src == nullptr") { HIP_CHECK_ERROR(f(dst, nullptr, count), hipErrorInvalidValue); }
}
template <typename F>
void MemcpyWithDirectionCommonNegativeTests(F f, void* dst, void* src, size_t count,
hipMemcpyKind kind) {
using namespace std::placeholders;
MemcpyCommonNegativeTests(std::bind(f, _1, _2, _3, kind), dst, src, count);
// Disabled on AMD due to defect - EXSWHTEC-128
#if HT_NVIDIA
SECTION("Invalid MemcpyKind") {
HIP_CHECK_ERROR(f(dst, src, count, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
+55 -2
Просмотреть файл
@@ -196,11 +196,11 @@ template <typename T> class DrvArrayAllocGuard {
const hipExtent extent_;
};
enum class Streams { nullstream, perThread, created };
enum class Streams { nullstream, perThread, created, withFlags, withPriority };
class StreamGuard {
public:
StreamGuard(const Streams stream_type) : stream_type_{stream_type} {
StreamGuard(const Streams stream_type, unsigned int flags = hipStreamDefault, int priority = 0) : stream_type_{stream_type}, flags_{flags}, priority_{priority} {
switch (stream_type_) {
case Streams::nullstream:
stream_ = nullptr;
@@ -210,6 +210,11 @@ class StreamGuard {
break;
case Streams::created:
HIP_CHECK(hipStreamCreate(&stream_));
break;
case Streams::withFlags:
HIP_CHECK(hipStreamCreateWithFlags(&stream_, flags_));
case Streams::withPriority:
HIP_CHECK(hipStreamCreateWithPriority(&stream_, flags_, priority_));
}
}
@@ -226,5 +231,53 @@ class StreamGuard {
private:
const Streams stream_type_;
unsigned int flags_;
int priority_;
hipStream_t stream_;
};
class EventsGuard {
public:
EventsGuard(size_t N) : events_(N) {
for (auto &e : events_) HIP_CHECK(hipEventCreate(&e));
}
EventsGuard(const EventsGuard&) = delete;
EventsGuard(EventsGuard&&) = delete;
~EventsGuard() {
for (auto &e : events_) static_cast<void>(hipEventDestroy(e));
}
hipEvent_t& operator[](int index) { return events_[index]; }
operator hipEvent_t() const { return events_.at(0); }
std::vector<hipEvent_t>& event_list() { return events_; }
private:
std::vector<hipEvent_t> events_;
};
class StreamsGuard {
public:
StreamsGuard(size_t N) : streams_(N) {
for (auto &s : streams_) HIP_CHECK(hipStreamCreate(&s));
}
StreamsGuard(const StreamsGuard&) = delete;
StreamsGuard(StreamsGuard&&) = delete;
~StreamsGuard() {
for (auto &s : streams_) static_cast<void>(hipStreamDestroy(s));
}
hipStream_t& operator[](int index) { return streams_[index]; }
operator hipStream_t() const { return streams_.at(0); }
std::vector<hipStream_t>& stream_list() { return streams_; }
private:
std::vector<hipStream_t> streams_;
};
+5 -7
Просмотреть файл
@@ -1,5 +1,5 @@
# Common Tests
set(LINUX_TEST_SRC
set(TEST_SRC
childMalloc.cc
hipDeviceComputeCapabilityMproc.cc
hipDeviceGetPCIBusIdMproc.cc
@@ -12,10 +12,9 @@ set(LINUX_TEST_SRC
hipMallocConcurrencyMproc.cc
hipMemCoherencyTstMProc.cc
hipIpcEventHandle.cc
hipIpcMemAccessTest.cc
deviceAllocationMproc.cc
hipNoGpuTsts.cc
hipMemGetInfo.cc
hipMemGetInfoMProc.cc
)
add_custom_target(dummy_kernel.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${CMAKE_CURRENT_SOURCE_DIR}/dummy_kernel.cpp -o ${CMAKE_CURRENT_BINARY_DIR}/../multiproc/dummy_kernel.code -I${CMAKE_CURRENT_SOURCE_DIR}/../../../../include/ -I${CMAKE_CURRENT_SOURCE_DIR}/../../include)
@@ -23,14 +22,13 @@ add_custom_target(dummy_kernel.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${CMAK
# the last argument linker libraries is required for this test but optional to the function
if(HIP_PLATFORM MATCHES "nvidia")
hip_add_exe_to_target(NAME MultiProc
TEST_SRC ${LINUX_TEST_SRC}
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests
LINKER_LIBS nvrtc)
elseif(HIP_PLATFORM MATCHES "amd")
hip_add_exe_to_target(NAME MultiProc
TEST_SRC ${LINUX_TEST_SRC}
TEST_TARGET_NAME build_tests
LINKER_LIBS ${CMAKE_DL_LIBS})
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests)
endif()
add_dependencies(build_tests dummy_kernel.code)
Просмотреть файл
+1 -1
Просмотреть файл
@@ -4,7 +4,7 @@ set(TEST_SRC
hipMemcpyMThreadMSize.cc
hipMallocManagedStress.cc
hipMemPrftchAsyncStressTst.cc
hipHostMalloc.cc
hipHostMallocStress.cc
)
hip_add_exe_to_target(NAME memory
Просмотреть файл
+4 -2
Просмотреть файл
@@ -34,6 +34,8 @@ add_subdirectory(multiThread)
add_subdirectory(compiler)
add_subdirectory(errorHandling)
add_subdirectory(cooperativeGrps)
#if(HIP_PLATFORM STREQUAL "amd")
if(HIP_PLATFORM STREQUAL "amd")
#add_subdirectory(clock)
#endif()
# Vulkan interop APIs currently undefined for Nvidia
add_subdirectory(vulkan_interop)
endif()
+3 -3
Просмотреть файл
@@ -41,12 +41,12 @@ set_source_files_properties(hipGetDeviceCount.cc PROPERTIES COMPILE_FLAGS -std=c
set_source_files_properties(hipDeviceGetP2PAttribute.cc PROPERTIES COMPILE_FLAGS -std=c++17)
add_executable(getDeviceCount EXCLUDE_FROM_ALL getDeviceCount_exe.cc)
add_executable(hipDeviceGetP2PAttribute EXCLUDE_FROM_ALL hipDeviceGetP2PAttribute_exe.cc)
add_executable(hipDeviceGetP2PAttribute_exe EXCLUDE_FROM_ALL hipDeviceGetP2PAttribute_exe.cc)
hip_add_exe_to_target(NAME DeviceTest
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests
COMPILE_OPTIONS -std=c++14)
add_dependencies(DeviceTest getDeviceCount)
add_dependencies(DeviceTest hipDeviceGetP2PAttribute)
add_dependencies(build_tests getDeviceCount)
add_dependencies(build_tests hipDeviceGetP2PAttribute_exe)
+11 -11
Просмотреть файл
@@ -122,20 +122,20 @@ TEST_CASE("Unit_hipDeviceGetP2PAttribute_Negative") {
/* https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#env-vars */
SECTION("Hidden devices using environment variables") {
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("0") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("1") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("0,1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("-1,0") == hipErrorNoDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("0,-1") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("0,1,-1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("0,-1,1") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("0") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("1") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("0,1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("-1,0") == hipErrorNoDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("0,-1") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("0,1,-1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("0,-1,1") == hipErrorInvalidDevice);
if (deviceCount > 2) {
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("2,1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("2") == hipErrorInvalidDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("2,1") == hipSuccess);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("2") == hipErrorInvalidDevice);
} else {
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute").run("2,1") == hipErrorNoDevice);
REQUIRE(hip::SpawnProc("hipDeviceGetP2PAttribute_exe").run("2,1") == hipErrorNoDevice);
}
}
#endif
-1
Просмотреть файл
@@ -59,7 +59,6 @@ set(TEST_SRC
hipGraphEventWaitNodeGetEvent.cc
hipGraphExecMemcpyNodeSetParams.cc
hipStreamBeginCapture.cc
hipGraphAddMemcpyNode1D.cc
hipStreamIsCapturing.cc
hipStreamGetCaptureInfo.cc
hipStreamEndCapture.cc
+37 -9
Просмотреть файл
@@ -18,14 +18,17 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
set(COMMON_SHARED_SRC DriverContext.cc)
# Common Tests - Test independent of all platforms
if(HIP_PLATFORM MATCHES "amd")
set(TEST_SRC
DriverContext.cc
memset.cc
malloc.cc
hipMemcpy2DToArray.cc
hipMemcpy2DToArray_old.cc
hipMemcpy2DToArrayAsync.cc
hipMemcpy2DToArrayAsync_old.cc
hipMemcpy3D.cc
hipMemcpy3DAsync.cc
hipMemcpyParam2D.cc
@@ -33,14 +36,17 @@ set(TEST_SRC
hipMemcpy2D.cc
hipMemcpy2DAsync.cc
hipMemcpy2DFromArray.cc
hipMemcpy2DFromArray_old.cc
hipMemcpy2DFromArrayAsync.cc
hipMemcpy2DFromArrayAsync_old.cc
hipMemcpyAtoH.cc
hipMemcpyAtoH_old.cc
hipMemcpyHtoA.cc
hipMemcpyHtoA_old.cc
hipMemcpyAllApiNegative.cc
hipMemcpy_MultiThread.cc
hipHostRegister.cc
hipHostUnregister.cc
hipMallocPitch.cc
hipMemPtrGetInfo.cc
hipPointerGetAttributes.cc
hipHostGetFlags.cc
@@ -60,23 +66,29 @@ set(TEST_SRC
hipMemCoherencyTst.cc
hipMallocManaged.cc
hipMemRangeGetAttribute.cc
hipMemRangeGetAttribute_old.cc
hipMemcpyFromSymbol.cc
hipPtrGetAttribute.cc
hipMemPoolApi.cc
hipMemcpyPeer.cc
hipMemcpyPeer_old.cc
hipMemcpyPeerAsync.cc
hipMemcpyPeerAsync_old.cc
hipMemcpyWithStream_old.cc
hipMemcpyWithStream.cc
hipMemcpyWithStreamMultiThread.cc
hipMemsetAsyncAndKernel.cc
hipMemset2DAsyncMultiThreadAndKernel.cc
hipMallocManaged.cc
hipMallocConcurrency.cc
hipMemcpyDtoD.cc
hipMemcpyDtoDAsync.cc
hipHostMalloc.cc
hipMemcpy.cc
hipMemcpy_old.cc
hipMemcpy_derivatives.cc
hipMemcpyAsync.cc
hipMemsetFunctional.cc
hipMalloc.cc
hipExtMallocWithFlags.cc
hipMallocPitch.cc
hipMallocArray.cc
hipMalloc3D.cc
@@ -98,14 +110,18 @@ set(TEST_SRC
hipMemsetAsync.cc
hipMemAdvise.cc
hipMemRangeGetAttributes.cc
hipStreamAttachMemAsync.cc
hipMemRangeGetAttributes_old.cc
hipMemGetAddressRange.cc
)
else()
set(TEST_SRC
DriverContext.cc
memset.cc
malloc.cc
hipMemcpy2DToArray.cc
hipMemcpy2DToArray_old.cc
hipMemcpy2DToArrayAsync.cc
hipMemcpy2DToArrayAsync_old.cc
hipMemcpy3D.cc
hipMemcpy3DAsync.cc
hipMemcpyParam2D.cc
@@ -113,14 +129,17 @@ set(TEST_SRC
hipMemcpy2D.cc
hipMemcpy2DAsync.cc
hipMemcpy2DFromArray.cc
hipMemcpy2DFromArray_old.cc
hipMemcpy2DFromArrayAsync.cc
hipMemcpy2DFromArrayAsync_old.cc
hipMemcpyAtoH.cc
hipMemcpyAtoH_old.cc
hipMemcpyHtoA.cc
hipMemcpyHtoA_old.cc
hipMemcpyAllApiNegative.cc
hipMemcpy_MultiThread.cc
hipHostRegister.cc
hipHostUnregister.cc
hipMallocPitch.cc
hipHostGetFlags.cc
hipHostGetDevicePointer.cc
hipMallocManaged_MultiScenario.cc
@@ -137,23 +156,28 @@ set(TEST_SRC
hipMemAdviseMmap.cc
hipMallocManaged.cc
hipMemRangeGetAttribute.cc
hipMemRangeGetAttribute_old.cc
hipMemcpyFromSymbol.cc
hipPtrGetAttribute.cc
hipMemPoolApi.cc
hipMemcpyPeer.cc
hipMemcpyPeer_old.cc
hipMemcpyPeerAsync.cc
hipMemcpyPeerAsync_old.cc
hipMemcpyWithStream_old.cc
hipMemcpyWithStream.cc
hipMemcpyWithStreamMultiThread.cc
hipMemsetAsyncAndKernel.cc
hipMemset2DAsyncMultiThreadAndKernel.cc
hipMallocManaged.cc
hipMallocConcurrency.cc
hipMemcpyDtoD.cc
hipMemcpyDtoDAsync.cc
hipHostMalloc.cc
hipMemcpy.cc
hipMemcpy_old.cc
hipMemcpy_derivatives.cc
hipMemcpyAsync.cc
hipMemsetFunctional.cc
hipMalloc.cc
hipMallocPitch.cc
hipMallocArray.cc
hipMalloc3D.cc
@@ -172,7 +196,10 @@ set(TEST_SRC
hipMemsetAsync.cc
hipMemAdvise.cc
hipMemRangeGetAttributes.cc
hipMemRangeGetAttributes_old.cc
hipGetSymbolSizeAddress.cc
hipStreamAttachMemAsync.cc
hipMemGetAddressRange.cc
)
endif()
@@ -186,4 +213,5 @@ endif()
hip_add_exe_to_target(NAME MemoryTest
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests)
TEST_TARGET_NAME build_tests
COMMON_SHARED_SRC ${COMMON_SHARED_SRC})
+442
Просмотреть файл
@@ -0,0 +1,442 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <functional>
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#include <utils.hh>
#include <resource_guards.hh>
#include "hipArrayCommon.hh"
/* Array -> Host */
template <bool should_synchronize, typename T, typename F>
void MemcpyAtoHShell(F memcpy_func, size_t width, const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t allocation_size = width * sizeof(T);
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, 0, 0), flag);
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 42;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_allocation.ptr(), 0, 0, host_allocation.host_ptr(),
sizeof(T) * width, sizeof(T) * width, 1, hipMemcpyHostToDevice));
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(memcpy_func(host_allocation.host_ptr(), array_allocation.ptr()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
template <bool should_synchronize, typename T, typename F>
void Memcpy2DHostFromAShell(F memcpy_func, size_t width, size_t height,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t allocation_size = width * height * sizeof(T);
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, height, 0), flag);
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 42;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_allocation.ptr(), 0, 0, host_allocation.host_ptr(),
sizeof(T) * width, sizeof(T) * width, height,
hipMemcpyHostToDevice));
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(memcpy_func(host_allocation.host_ptr(), sizeof(T) * width, array_allocation.ptr()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
/* Array -> Device */
template <bool should_synchronize, bool enable_peer_access, typename T, typename F>
void Memcpy2DDeviceFromAShell(F memcpy_func, size_t width, size_t height,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t allocation_size = width * height * sizeof(T);
const auto device_count = HipTest::getDeviceCount();
const auto src_device = GENERATE_COPY(range(0, device_count));
const auto dst_device = GENERATE_COPY(range(0, device_count));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
HIP_CHECK(hipSetDevice(src_device));
if constexpr (enable_peer_access) {
if (src_device == dst_device) {
return;
}
int can_access_peer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (!can_access_peer) {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
REQUIRE(can_access_peer);
}
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
}
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, height, 0), flag);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard2D<T> device_allocation(width, height);
HIP_CHECK(hipSetDevice(src_device));
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 42;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_allocation.ptr(), 0, 0, host_allocation.host_ptr(),
sizeof(T) * width, sizeof(T) * width, height,
hipMemcpyHostToDevice));
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(
memcpy_func(device_allocation.ptr(), device_allocation.pitch(), array_allocation.ptr()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
HIP_CHECK(hipMemcpy2D(host_allocation.host_ptr(), sizeof(T) * width, device_allocation.ptr(),
device_allocation.pitch(), sizeof(T) * width, height,
hipMemcpyDeviceToHost));
if constexpr (enable_peer_access) {
// If we've gotten this far, EnablePeerAccess must have succeeded, so we only need to check this
// condition
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
}
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
/* Host -> Array */
template <bool should_synchronize, typename T, typename F>
void MemcpyHtoAShell(F memcpy_func, size_t width, const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t allocation_size = width * sizeof(T);
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, 0, 0), flag);
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 41;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(memcpy_func(array_allocation.ptr(), host_allocation.host_ptr()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(hipMemcpy2DFromArray(host_allocation.host_ptr(), sizeof(T) * width,
array_allocation.ptr(), 0, 0, sizeof(T) * width, 1,
hipMemcpyDeviceToHost));
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
template <bool should_synchronize, typename T, typename F>
void Memcpy2DHosttoAShell(F memcpy_func, size_t width, size_t height,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
;
size_t allocation_size = width * height * sizeof(T);
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, height, 0), flag);
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 41;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(memcpy_func(array_allocation.ptr(), host_allocation.host_ptr(), sizeof(T) * width));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(hipMemcpy2DFromArray(host_allocation.host_ptr(), sizeof(T) * width,
array_allocation.ptr(), 0, 0, sizeof(T) * width, height,
hipMemcpyDeviceToHost));
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
/* Device -> Array */
template <bool should_synchronize, bool enable_peer_access, typename T, typename F>
void Memcpy2DDevicetoAShell(F memcpy_func, size_t width, size_t height,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t allocation_size = width * height * sizeof(T);
const auto device_count = HipTest::getDeviceCount();
const auto src_device = GENERATE_COPY(range(0, device_count));
const auto dst_device = GENERATE_COPY(range(0, device_count));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
HIP_CHECK(hipSetDevice(src_device));
if constexpr (enable_peer_access) {
if (src_device == dst_device) {
return;
}
int can_access_peer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (!can_access_peer) {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
REQUIRE(can_access_peer);
}
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
}
LinearAllocGuard<T> host_allocation(LinearAllocs::hipHostMalloc, allocation_size);
LinearAllocGuard2D<T> device_allocation(width, height);
HIP_CHECK(hipSetDevice(dst_device));
ArrayAllocGuard<T> array_allocation(make_hipExtent(width, height, 0), flag);
HIP_CHECK(hipSetDevice(src_device));
const auto element_count = allocation_size / sizeof(T);
constexpr int fill_value = 41;
std::fill_n(host_allocation.host_ptr(), element_count, fill_value);
HIP_CHECK(hipMemcpy2D(device_allocation.ptr(), device_allocation.pitch(),
host_allocation.host_ptr(), sizeof(T) * width, sizeof(T) * width, height,
hipMemcpyHostToDevice));
HIP_CHECK(
memcpy_func(array_allocation.ptr(), device_allocation.ptr(), device_allocation.pitch()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(kernel_stream));
}
std::fill_n(host_allocation.host_ptr(), element_count, 0);
HIP_CHECK(hipMemcpy2DFromArray(host_allocation.host_ptr(), sizeof(T) * width,
array_allocation.ptr(), 0, 0, sizeof(T) * width, height,
hipMemcpyDeviceToHost));
if constexpr (enable_peer_access) {
// If we've gotten this far, EnablePeerAccess must have succeeded, so we only need to check this
// condition
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
}
ArrayFindIfNot(host_allocation.host_ptr(), fill_value, element_count);
}
// Synchronization behavior checks
template <typename F>
void MemcpyArraySyncBehaviorCheck(F memcpy_func, const bool should_sync,
const hipStream_t kernel_stream) {
LaunchDelayKernel(std::chrono::milliseconds{100}, kernel_stream);
HIP_CHECK(memcpy_func());
if (should_sync) {
HIP_CHECK(hipStreamQuery(kernel_stream));
} else {
HIP_CHECK_ERROR(hipStreamQuery(kernel_stream), hipErrorNotReady);
}
}
/* Host -> Array Sync check */
template <typename F>
void MemcpyHtoASyncBehavior(F memcpy_func, size_t width, size_t height, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t num_h = (height == 0) ? 1 : height;
size_t allocation_size = width * num_h * sizeof(int);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<int> array_allocation(make_hipExtent(width, height, 0), flag);
MemcpyArraySyncBehaviorCheck(std::bind(memcpy_func, array_allocation.ptr(), host_alloc.ptr()),
should_sync, kernel_stream);
}
/* Array -> Host sync check */
template <typename F>
void MemcpyAtoHPageableSyncBehavior(F memcpy_func, size_t width, size_t height,
const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t num_h = (height == 0) ? 1 : height;
size_t allocation_size = width * num_h * sizeof(int);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<int> array_allocation(make_hipExtent(width, height, 0), flag);
MemcpyArraySyncBehaviorCheck(std::bind(memcpy_func, host_alloc.ptr(), array_allocation.ptr()),
should_sync, kernel_stream);
}
template <typename F>
void MemcpyAtoHPinnedSyncBehavior(F memcpy_func, size_t width, size_t height,
const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
size_t num_h = (height == 0) ? 1 : height;
size_t allocation_size = width * num_h * sizeof(int);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
ArrayAllocGuard<int> array_allocation(make_hipExtent(width, height, 0), flag);
MemcpyArraySyncBehaviorCheck(std::bind(memcpy_func, host_alloc.ptr(), array_allocation.ptr()),
should_sync, kernel_stream);
}
/* Device -> Array sync check */
template <typename F>
void MemcpyDtoASyncBehavior(F memcpy_func, size_t width, size_t height, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_allocation(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_allocation(width, height);
MemcpyArraySyncBehaviorCheck(std::bind(memcpy_func, array_allocation.ptr(),
device_allocation.ptr(), device_allocation.pitch()),
should_sync, kernel_stream);
}
/* Array -> Device sync check */
template <typename F>
void MemcpyAtoDSyncBehavior(F memcpy_func, size_t width, size_t height, const bool should_sync,
const hipStream_t kernel_stream = nullptr) {
const unsigned int flag = hipArrayDefault;
LinearAllocGuard2D<int> device_allocation(width, height);
ArrayAllocGuard<int> array_allocation(make_hipExtent(width, height, 0), flag);
MemcpyArraySyncBehaviorCheck(std::bind(memcpy_func, device_allocation.ptr(),
device_allocation.pitch(), array_allocation.ptr()),
should_sync, kernel_stream);
}
/* Array -> Host/Device zero copy */
template <bool should_synchronize, typename F>
void Memcpy2DFromArrayZeroWidthHeight(F memcpy_func, size_t width, size_t height,
const hipStream_t stream = nullptr) {
const unsigned int flag = hipArrayDefault;
const auto element_count = width * height;
SECTION("Device to Host") {
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, width * height * sizeof(int));
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height,
hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(memcpy_func(host_alloc.host_ptr(), sizeof(int) * width, array_alloc.ptr()));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(stream));
}
ArrayFindIfNot(host_alloc.host_ptr(), fill_value, element_count);
}
SECTION("Device to Device") {
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, width * height * sizeof(int));
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height,
hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2D(device_alloc.ptr(), device_alloc.pitch(), host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height, hipMemcpyHostToDevice));
HIP_CHECK(memcpy_func(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr()));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(stream));
}
HIP_CHECK(hipMemcpy2D(host_alloc.host_ptr(), sizeof(int) * width, device_alloc.ptr(),
device_alloc.pitch(), sizeof(int) * width, height,
hipMemcpyDeviceToHost));
ArrayFindIfNot(host_alloc.host_ptr(), fill_value, element_count);
}
}
/* Host/Device -> Array zero copy */
template <bool should_synchronize, typename F>
void Memcpy2DToArrayZeroWidthHeight(F memcpy_func, size_t width, size_t height,
const hipStream_t stream = nullptr) {
const unsigned int flag = hipArrayDefault;
const auto element_count = width * height;
SECTION("Host to Device") {
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, width * height * sizeof(int));
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height,
hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(memcpy_func(array_alloc.ptr(), host_alloc.host_ptr(), sizeof(int) * width));
if (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(stream));
}
HIP_CHECK(hipMemcpy2DFromArray(host_alloc.host_ptr(), sizeof(int) * width, array_alloc.ptr(), 0,
0, sizeof(int) * width, height, hipMemcpyDeviceToHost));
ArrayFindIfNot(host_alloc.host_ptr(), 42, element_count);
}
SECTION("Device to Device") {
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, width * height * sizeof(int));
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height,
hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width * height, fill_value);
HIP_CHECK(hipMemcpy2D(device_alloc.ptr(), device_alloc.pitch(), host_alloc.host_ptr(),
sizeof(int) * width, sizeof(int) * width, height, hipMemcpyHostToDevice));
HIP_CHECK(memcpy_func(array_alloc.ptr(), device_alloc.ptr(), device_alloc.pitch()));
if constexpr (should_synchronize) {
HIP_CHECK(hipStreamSynchronize(stream));
}
HIP_CHECK(hipMemcpy2DFromArray(host_alloc.host_ptr(), sizeof(int) * width, array_alloc.ptr(), 0,
0, sizeof(int) * width, height, hipMemcpyDeviceToHost));
ArrayFindIfNot(host_alloc.host_ptr(), 42, element_count);
}
}
+134
Просмотреть файл
@@ -0,0 +1,134 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#include <utils.hh>
TEST_CASE("Unit_hipExtMallocWithFlags_Positive_Basic") {
void* ptr = nullptr;
SECTION("hipDeviceMallocDefault") {
const auto alloc_size =
GENERATE_COPY(10, kPageSize / 2, kPageSize, kPageSize * 3 / 2, kPageSize * 2);
HIP_CHECK(hipExtMallocWithFlags(&ptr, alloc_size, hipDeviceMallocDefault));
CHECK(ptr != nullptr);
CHECK(reinterpret_cast<intptr_t>(ptr) % 256 == 0);
HIP_CHECK(hipFree(ptr));
}
SECTION("hipDeviceMallocFinegrained") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeFineGrainSupport)) {
HipTest::HIP_SKIP_TEST("Device does not support fine-grained memory allocations");
return;
}
const auto alloc_size =
GENERATE_COPY(10, kPageSize / 2, kPageSize, kPageSize * 3 / 2, kPageSize * 2);
HIP_CHECK(hipExtMallocWithFlags(&ptr, alloc_size, hipDeviceMallocFinegrained));
CHECK(ptr != nullptr);
CHECK(reinterpret_cast<intptr_t>(ptr) % 256 == 0);
HIP_CHECK(hipFree(ptr));
}
SECTION("hipMallocSignalMemory") {
HIP_CHECK(hipExtMallocWithFlags(&ptr, 8, hipMallocSignalMemory));
CHECK(ptr != nullptr);
HIP_CHECK(hipFree(ptr));
}
}
TEST_CASE("Unit_hipExtMallocWithFlags_Positive_Zero_Size") {
void* ptr = reinterpret_cast<void*>(0x1);
const auto flag = GENERATE(hipDeviceMallocDefault, hipDeviceMallocFinegrained);
HIP_CHECK(hipExtMallocWithFlags(&ptr, 0, flag));
REQUIRE(ptr == nullptr);
}
TEST_CASE("Unit_hipExtMallocWithFlags_Positive_Alignment") {
void *ptr1 = nullptr, *ptr2 = nullptr;
const auto flag = GENERATE(hipDeviceMallocDefault, hipDeviceMallocFinegrained);
if (flag == hipDeviceMallocFinegrained &&
!DeviceAttributesSupport(0, hipDeviceAttributeFineGrainSupport)) {
HipTest::HIP_SKIP_TEST("Device does not support fine-grained memory allocations");
return;
}
HIP_CHECK(hipExtMallocWithFlags(&ptr1, 1, flag));
HIP_CHECK(hipExtMallocWithFlags(&ptr2, 10, flag));
CHECK(reinterpret_cast<intptr_t>(ptr1) % 256 == 0);
CHECK(reinterpret_cast<intptr_t>(ptr2) % 256 == 0);
HIP_CHECK(hipFree(ptr1));
HIP_CHECK(hipFree(ptr2));
}
TEST_CASE("Unit_hipExtMallocWithFlags_Negative_Parameters") {
SECTION("Invalid flags") {
void* ptr = nullptr;
HIP_CHECK_ERROR(
hipExtMallocWithFlags(&ptr, 4096, hipDeviceMallocDefault | hipMallocSignalMemory),
hipErrorInvalidValue);
}
SECTION("hipDeviceMallocDefault") {
SECTION("ptr == nullptr") {
HIP_CHECK_ERROR(hipExtMallocWithFlags(nullptr, 4096, hipDeviceMallocDefault),
hipErrorInvalidValue);
}
SECTION("size == max size_t") {
void* ptr;
HIP_CHECK_ERROR(
hipExtMallocWithFlags(&ptr, std::numeric_limits<size_t>::max(), hipDeviceMallocDefault),
hipErrorOutOfMemory);
}
}
SECTION("hipDeviceMallocFinegrained") {
SECTION("ptr == nullptr") {
HIP_CHECK_ERROR(hipExtMallocWithFlags(nullptr, 4096, hipDeviceMallocFinegrained),
hipErrorInvalidValue);
}
SECTION("size == max size_t") {
void* ptr;
HIP_CHECK_ERROR(hipExtMallocWithFlags(&ptr, std::numeric_limits<size_t>::max(),
hipDeviceMallocFinegrained),
hipErrorOutOfMemory);
}
}
SECTION("hipMallocSignalMemory") {
SECTION("ptr == nullptr") {
HIP_CHECK_ERROR(hipExtMallocWithFlags(nullptr, 4096, hipMallocSignalMemory),
hipErrorInvalidValue);
}
SECTION("size == 0") {
void* ptr;
HIP_CHECK_ERROR(hipExtMallocWithFlags(&ptr, 0, hipMallocSignalMemory), hipErrorInvalidValue);
}
SECTION("size != 8") {
void* ptr;
HIP_CHECK_ERROR(hipExtMallocWithFlags(&ptr, 16, hipMallocSignalMemory), hipErrorInvalidValue);
}
}
}
+59
Просмотреть файл
@@ -0,0 +1,59 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
TEST_CASE("Unit_hipMalloc_Positive_Basic") {
constexpr size_t page_size = 4096;
void* ptr = nullptr;
const auto alloc_size =
GENERATE_COPY(10, page_size / 2, page_size, page_size * 3 / 2, page_size * 2);
HIP_CHECK(hipMalloc(&ptr, alloc_size));
CHECK(ptr != nullptr);
CHECK(reinterpret_cast<intptr_t>(ptr) % 256 == 0);
HIP_CHECK(hipFree(ptr));
}
TEST_CASE("Unit_hipMalloc_Positive_Zero_Size") {
void* ptr = reinterpret_cast<void*>(0x1);
HIP_CHECK(hipMalloc(&ptr, 0));
REQUIRE(ptr == nullptr);
}
TEST_CASE("Unit_hipMalloc_Positive_Alignment") {
void *ptr1 = nullptr, *ptr2 = nullptr;
HIP_CHECK(hipMalloc(&ptr1, 1));
HIP_CHECK(hipMalloc(&ptr2, 10));
CHECK(reinterpret_cast<intptr_t>(ptr1) % 256 == 0);
CHECK(reinterpret_cast<intptr_t>(ptr2) % 256 == 0);
HIP_CHECK(hipFree(ptr1));
HIP_CHECK(hipFree(ptr2));
}
TEST_CASE("Unit_hipMalloc_Negative_Parameters") {
SECTION("ptr == nullptr") { HIP_CHECK_ERROR(hipMalloc(nullptr, 4096), hipErrorInvalidValue); }
SECTION("size == max size_t") {
void* ptr;
HIP_CHECK_ERROR(hipMalloc(&ptr, std::numeric_limits<size_t>::max()), hipErrorOutOfMemory);
}
}
+88
Просмотреть файл
@@ -0,0 +1,88 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Testcase Scenarios :
Unit_hipMemGetAddressRange_Positive - Test hipMemGetAddressRange api for various memory allocation
types and offsets Unit_hipMemGetAddressRange_Negative - Test unsuccessful execution of
hipMemGetAddressRange api when parameters are invalid
*/
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#include <utils.hh>
#include <resource_guards.hh>
TEST_CASE("Unit_hipMemGetAddressRange_Positive") {
hipDeviceptr_t base_ptr;
size_t mem_size = 0;
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
const int offset = GENERATE(0, 20, 40, 60, 80);
SECTION("Host address range") {
using LA = LinearAllocs;
LinearAllocGuard<int> host_alloc(LA::hipHostMalloc, allocation_size);
HIP_CHECK(hipMemGetAddressRange(&base_ptr, &mem_size,
reinterpret_cast<hipDeviceptr_t>(host_alloc.ptr() + offset)));
REQUIRE(reinterpret_cast<hipDeviceptr_t>(host_alloc.ptr()) == base_ptr);
REQUIRE(mem_size == allocation_size);
}
SECTION("Device address range") {
using LA = LinearAllocs;
const auto device_allocation_type = GENERATE(LA::hipMalloc, LA::hipMallocManaged);
LinearAllocGuard<int> device_alloc(device_allocation_type, allocation_size);
HIP_CHECK(hipMemGetAddressRange(&base_ptr, &mem_size,
reinterpret_cast<hipDeviceptr_t>(device_alloc.ptr() + offset)));
REQUIRE(reinterpret_cast<hipDeviceptr_t>(device_alloc.ptr()) == base_ptr);
REQUIRE(mem_size == allocation_size);
}
SECTION("Pitch address range") {
size_t width = 32;
size_t height = 32;
LinearAllocGuard2D<int> device_alloc(width, height);
HIP_CHECK(hipMemGetAddressRange(&base_ptr, &mem_size,
reinterpret_cast<hipDeviceptr_t>(device_alloc.ptr() + offset)));
REQUIRE(reinterpret_cast<hipDeviceptr_t>(device_alloc.ptr()) == base_ptr);
REQUIRE(mem_size == (device_alloc.pitch() * height));
}
}
TEST_CASE("Unit_hipMemGetAddressRange_Negative") {
hipDeviceptr_t base_ptr;
size_t mem_size = 0;
const auto allocation_size = kPageSize / 2;
const int offset = kPageSize;
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
hipDeviceptr_t dummy_ptr = NULL;
SECTION("Device pointer is invalid") {
HIP_CHECK_ERROR(hipMemGetAddressRange(&base_ptr, &mem_size, dummy_ptr), hipErrorNotFound);
}
SECTION("Offset is greater than allocated size") {
HIP_CHECK_ERROR(
hipMemGetAddressRange(&base_ptr, &mem_size,
reinterpret_cast<hipDeviceptr_t>(host_alloc.ptr() + offset)),
hipErrorNotFound);
}
}
+130 -88
Просмотреть файл
@@ -1,13 +1,15 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -17,9 +19,27 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <vector>
#include <hip_test_common.hh>
// Kernel function
__global__ void MemPrftchAsyncKernel(int* C_d, const int* A_d, size_t N) {
#include <hip/hip_runtime_api.h>
#include <utils.hh>
#include <resource_guards.hh>
std::vector<int> GetDevicesWithPrefetchSupport() {
const auto device_count = HipTest::getDeviceCount();
std::vector<int> supported_devices;
supported_devices.reserve(device_count + 1);
for (int i = 0; i < device_count; ++i) {
if (DeviceAttributesSupport(i, hipDeviceAttributeManagedMemory,
hipDeviceAttributeConcurrentManagedAccess)) {
supported_devices.push_back(i);
}
}
return supported_devices;
}
__global__ void MemPrefetchAsyncKernel(int* C_d, const int* A_d, size_t N) {
size_t offset = (blockIdx.x * blockDim.x + threadIdx.x);
size_t stride = blockDim.x * gridDim.x;
for (size_t i = offset; i < N; i += stride) {
@@ -27,98 +47,120 @@ __global__ void MemPrftchAsyncKernel(int* C_d, const int* A_d, size_t N) {
}
}
TEST_CASE("Unit_hipMemPrefetchAsync_Basic") {
const auto supported_devices = GetDevicesWithPrefetchSupport();
if (supported_devices.empty()) {
HipTest::HIP_SKIP_TEST("Test need at least one device with managed memory support");
}
static int HmmAttrPrint() {
int managed = 0;
INFO("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
INFO("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
INFO("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
INFO("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
INFO("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
LinearAllocGuard<int> alloc1(LinearAllocs::hipMallocManaged, kPageSize);
const auto count = kPageSize / sizeof(*alloc1.ptr());
constexpr auto fill_value = 42;
std::fill_n(alloc1.ptr(), count, fill_value);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
INFO("hipDeviceAttributeManagedMemory: " << managed);
return managed;
for (const auto device : supported_devices) {
HIP_CHECK(hipSetDevice(device));
LinearAllocGuard<int> alloc2(LinearAllocs::hipMallocManaged, kPageSize);
StreamGuard sg(Streams::created);
HIP_CHECK(hipMemPrefetchAsync(alloc1.ptr(), kPageSize, device, sg.stream()));
MemPrefetchAsyncKernel<<<count / 1024 + 1, 1024, 0, sg.stream()>>>(alloc2.ptr(), alloc1.ptr(),
count);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(sg.stream()));
ArrayFindIfNot(alloc1.ptr(), fill_value, count);
ArrayFindIfNot(alloc2.ptr(), fill_value * fill_value, count);
}
HIP_CHECK(hipMemPrefetchAsync(alloc1.ptr(), kPageSize, hipCpuDeviceId));
HIP_CHECK(hipStreamSynchronize(nullptr));
ArrayFindIfNot(alloc1.ptr(), fill_value, count);
}
/*
Test Description: This test prefetches the memory to each of the available
devices and launch kernel followed by result verification
At the end the memory is prefetched to Host and kernel is launched followed
by result verification.
*/
TEST_CASE("Unit_hipMemPrefetchAsync_Sync_Behavior") {
const auto supported_devices = GetDevicesWithPrefetchSupport();
if (supported_devices.empty()) {
HipTest::HIP_SKIP_TEST("Test need at least one device with managed memory support");
}
const auto device = supported_devices.front();
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
TEST_CASE("Unit_hipMemPrefetchAsync") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
bool IfTestPassed = true;
int A_CONST = 123, MEM_SIZE = (8192 * sizeof(int));
int *devPtr1 = NULL, *devPtr2 = NULL, NumDevs = 0, flag = 0;
hipStream_t strm;
HIP_CHECK(hipMallocManaged(&devPtr1, MEM_SIZE));
HIP_CHECK(hipMallocManaged(&devPtr2, MEM_SIZE));
HIP_CHECK(hipGetDeviceCount(&NumDevs));
// Initializing the memory
for (uint32_t k = 0; k < (MEM_SIZE/sizeof(int)); ++k) {
devPtr1[k] = A_CONST;
devPtr2[k] = 0;
}
StreamGuard sg(stream_type);
LinearAllocGuard<void> alloc(LinearAllocs::hipMallocManaged, kPageSize);
LaunchDelayKernel(std::chrono::milliseconds{100}, sg.stream());
HIP_CHECK(hipMemPrefetchAsync(alloc.ptr(), kPageSize, device, sg.stream()));
HIP_CHECK_ERROR(hipStreamQuery(sg.stream()), hipErrorNotReady);
HIP_CHECK(hipStreamSynchronize(sg.stream()));
}
TEST_CASE("Unit_hipMemPrefetchAsync_Rounding_Behavior") {
auto supported_devices = GetDevicesWithPrefetchSupport();
if (supported_devices.empty()) {
HipTest::HIP_SKIP_TEST("Test need at least one device with managed memory support");
}
const auto device = supported_devices.front();
LinearAllocGuard<uint8_t> alloc(LinearAllocs::hipMallocManaged, 3 * kPageSize);
REQUIRE_FALSE(reinterpret_cast<intptr_t>(alloc.ptr()) % kPageSize);
const auto [offset, width] =
GENERATE_COPY(std::make_pair(kPageSize / 4, kPageSize / 2), // Withing page
std::make_pair(kPageSize / 2, kPageSize), // Across page border
std::make_pair(kPageSize / 2, kPageSize * 2)); // Across two page borders
HIP_CHECK(hipMemPrefetchAsync(alloc.ptr() + offset, width, device));
HIP_CHECK(hipStreamSynchronize(nullptr));
constexpr auto RoundDown = [](const intptr_t a, const intptr_t n) { return a - a % n; };
constexpr auto RoundUp = [RoundDown](const intptr_t a, const intptr_t n) {
return RoundDown(a + n - 1, n);
};
const auto base = alloc.ptr();
const auto rounded_up = RoundUp(offset + width, kPageSize);
unsigned int attribute = 0;
HIP_CHECK(hipMemRangeGetAttribute(&attribute, sizeof(attribute),
hipMemRangeAttributeLastPrefetchLocation,
reinterpret_cast<void*>(base), rounded_up));
REQUIRE(device == static_cast<int>(attribute));
HIP_CHECK(hipMemRangeGetAttribute(&attribute, sizeof(attribute),
hipMemRangeAttributeLastPrefetchLocation, alloc.ptr(),
3 * kPageSize));
REQUIRE((rounded_up == 3 * kPageSize ? device : hipInvalidDeviceId) == static_cast<int>(attribute));
}
for (int i = 0; i < NumDevs; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(devPtr1, MEM_SIZE, i, strm));
HIP_CHECK(hipStreamSynchronize(strm));
MemPrftchAsyncKernel<<<32, (MEM_SIZE/sizeof(int)/32)>>>(devPtr2, devPtr1,
MEM_SIZE/sizeof(int));
for (uint32_t m = 0; m < (MEM_SIZE/sizeof(int)); ++m) {
if (devPtr1[m] != (A_CONST * A_CONST)) {
flag = 1;
}
}
HIP_CHECK(hipStreamDestroy(strm));
if (!flag) {
INFO("Test failed for device: " << i);
IfTestPassed = false;
flag = 0;
}
}
// The memory will be prefetched from last gpu in the system to the host
// memory and kernel is launched followed by result verification.
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(devPtr1, MEM_SIZE, hipCpuDeviceId, strm));
HIP_CHECK(hipStreamSynchronize(strm));
MemPrftchAsyncKernel<<<32, (MEM_SIZE/sizeof(int)/32)>>>(devPtr2, devPtr1,
MEM_SIZE/sizeof(int));
for (uint32_t m = 0; m < (MEM_SIZE/sizeof(int)); ++m) {
if (devPtr1[m] != (A_CONST * A_CONST)) {
flag = 1;
}
}
HIP_CHECK(hipStreamDestroy(strm));
if (!flag) {
INFO("Failed to prefetch the memory to System space.\n");
IfTestPassed = false;
flag = 0;
}
TEST_CASE("Unit_hipMemPrefetchAsync_Negative_Parameters") {
auto supported_devices = GetDevicesWithPrefetchSupport();
if (supported_devices.empty()) {
HipTest::HIP_SKIP_TEST("Test need at least one device with managed memory support");
}
supported_devices.push_back(hipCpuDeviceId);
const auto device = GENERATE_COPY(from_range(supported_devices));
HIP_CHECK(hipFree(devPtr1));
HIP_CHECK(hipFree(devPtr2));
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
LinearAllocGuard<void> alloc(LinearAllocs::hipMallocManaged, kPageSize);
SECTION("dev_ptr == nullptr") {
HIP_CHECK_ERROR(hipMemPrefetchAsync(nullptr, kPageSize, device), hipErrorInvalidValue);
}
#if HT_NVIDIA
SECTION("dev_ptr points to non-managed memory") {
LinearAllocGuard<void> alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK_ERROR(hipMemPrefetchAsync(alloc.ptr(), kPageSize, device), hipErrorInvalidValue);
}
#endif
SECTION("count == 0") {
HIP_CHECK_ERROR(hipMemPrefetchAsync(alloc.ptr(), 0, device), hipErrorInvalidValue);
}
SECTION("count larger than allocation size") {
HIP_CHECK_ERROR(hipMemPrefetchAsync(alloc.ptr(), kPageSize + 1, device), hipErrorInvalidValue);
}
SECTION("Invalid device") {
HIP_CHECK_ERROR(hipMemPrefetchAsync(alloc.ptr(), kPageSize, hipInvalidDeviceId),
hipErrorInvalidDevice);
}
SECTION("Invalid stream") {
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipStreamDestroy(stream));
HIP_CHECK_ERROR(hipMemPrefetchAsync(alloc.ptr(), kPageSize, device, stream),
hipErrorContextIsDestroyed);
}
}
+322 -371
Просмотреть файл
@@ -1,408 +1,359 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description:
Scenario-1: The following function tests the count parameter(last param) to
hipMemRangeGetAttribute api by passing possible extreme values.
Curently the only way to test if count param working properly is to verify
the first parameter of hipMemRangeGetAttribute() api has value 1 stored
Scenario-2: This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part
Scenario-3: Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).
Scenario-4: The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash
Scenario-5: The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute
Scenario-6: The following Test Case does negative tests on hipMemRangeGetAttribute()*/
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <stdlib.h>
#ifdef __linux__
#include <unistd.h>
#include <sys/sysinfo.h>
#endif
#include <resource_guards.hh>
#include <utils.hh>
static bool CheckError(hipError_t err, int LineNo) {
if (err == hipSuccess) {
WARN("Error expected but received hipSuccess at line no.:"
<< LineNo);
return false;
} else {
return true;
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_ReadMostly_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeReadMostly,
allocation.ptr(), kPageSize));
REQUIRE(data == 0);
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeReadMostly,
allocation.ptr(), kPageSize));
REQUIRE(data == 1);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_ReadMostly_Partial_Range") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, 2 * kPageSize);
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetReadMostly, 0));
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeReadMostly,
allocation.ptr(), 2 * kPageSize));
REQUIRE(data == 0);
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeReadMostly,
allocation.ptr(), kPageSize));
REQUIRE(data == 1);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_PreferredLocation_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributePreferredLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == hipInvalidDeviceId);
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetPreferredLocation, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributePreferredLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == 0);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_PreferredLocation_CPU") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
HIP_CHECK(
hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetPreferredLocation, hipCpuDeviceId));
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributePreferredLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == hipCpuDeviceId);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_PreferredLocation_Partial_Range") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, 2 * kPageSize);
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetPreferredLocation, 0));
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributePreferredLocation,
allocation.ptr(), 2 * kPageSize));
REQUIRE(data == hipInvalidDeviceId);
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributePreferredLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == 0);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_LastPrefetchLocation_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeLastPrefetchLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == hipInvalidDeviceId);
HIP_CHECK(hipMemPrefetchAsync(allocation.ptr(), kPageSize, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeLastPrefetchLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == 0);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_LastPrefetchLocation_CPU") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
HIP_CHECK(hipMemPrefetchAsync(allocation.ptr(), kPageSize, hipCpuDeviceId));
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeLastPrefetchLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == hipCpuDeviceId);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_LastPrefetchLocation_Partial_Range") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, 2 * kPageSize);
HIP_CHECK(hipMemPrefetchAsync(allocation.ptr(), kPageSize, 0));
int32_t data;
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeLastPrefetchLocation,
allocation.ptr(), 2 * kPageSize));
REQUIRE(data == hipInvalidDeviceId);
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(data), hipMemRangeAttributeLastPrefetchLocation,
allocation.ptr(), kPageSize));
REQUIRE(data == 0);
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_AccessedBy_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
std::array<int32_t, 4> data;
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), kPageSize));
for (auto device : data) {
REQUIRE(device == hipInvalidDeviceId);
}
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, hipCpuDeviceId));
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), kPageSize));
// Use std::find since there is no guaranteed order in which devices will be returned
REQUIRE(std::find(cbegin(data), cend(data), hipCpuDeviceId) != cend(data));
REQUIRE(std::find(cbegin(data), cend(data), 0) != cend(data));
// All the unused slots should be at the end
for (auto it = cbegin(data) + 2; it != cend(data); ++it) {
REQUIRE(*it == hipInvalidDeviceId);
}
}
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_AccessedBy_Partial_Range") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
static int HmmAttrPrint() {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, 2 * kPageSize);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
return managed;
}
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, hipCpuDeviceId));
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, 0));
// The following function tests the count parameter(last param) to
// hipMemRangeGetAttribute api by passing possible extreme values.
// Curently the only way to test if count param working properly is to verify
// the first parameter of hipMemRangeGetAttribute() api has value 1 stored
TEST_CASE("Unit_hipMemRangeGetAttribute_TstCountParam") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999, FLG_READMOSTLY_ENBLD = 1;
bool IfTestPassed = true;
int data = RND_NUM, *devPtr = nullptr;
size_t TotGpuMem, TotGpuFreeMem;
HIP_CHECK(hipMemGetInfo(&TotGpuFreeMem, &TotGpuMem));
std::array<int32_t, 4> data;
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), 2 * kPageSize));
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(reinterpret_cast<void*>(&data),
sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, TotGpuFreeMem, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, TotGpuFreeMem, hipMemAdviseSetReadMostly,
0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, TotGpuFreeMem));
for (auto device : data) {
REQUIRE(device == hipInvalidDeviceId);
}
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, (TotGpuFreeMem - 1),
hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, (TotGpuFreeMem - 1),
hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, (TotGpuFreeMem - 1)));
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), kPageSize));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
// Use std::find since there is no guaranteed order in which devices will be returned
REQUIRE(std::find(cbegin(data), cend(data), hipCpuDeviceId) != cend(data));
REQUIRE(std::find(cbegin(data), cend(data), 0) != cend(data));
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
// All the unused slots should be at the end
for (auto it = cbegin(data) + 2; it != cend(data); ++it) {
REQUIRE(*it == hipInvalidDeviceId);
}
}
/* The following Test Case does negative tests on hipMemRangeGetAttribute()*/
TEST_CASE("Unit_hipMemRangeGetAttribute_Positive_AccessedBy_MultiDevice") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
TEST_CASE("Unit_hipMemRangeGetAttribute_NegativeTests") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999;
float *devPtr = nullptr;
int NumDevs;
HIP_CHECK(hipGetDeviceCount(&NumDevs));
int data = RND_NUM;
int *OutData = new int[NumDevs];
for (int m = 0; m < NumDevs; ++m) {
OutData[m] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Two or more device are required");
return;
}
// checking the behavior with dataSize 0
SECTION("checking the behavior with dataSize 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, 0,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and even
SECTION("checking the behavior with dataSize > 4 and even") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 6,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and odd
SECTION("checking the behavior with dataSize > 4 and odd") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 7,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize which is not multiple of 4
SECTION("checking the behavior with dataSize which is not multiple of 4") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 27,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behaviour with devPtr(4th param) as NULL
SECTION("checking the behaviour with devPtr(4th param) as NULL") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
NULL, MEM_SIZE), __LINE__));
}
// checking the behaviour with count(5th param) as 0
SECTION("checking the behaviour with count(5th param) as 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, 0), __LINE__));
}
// checking the behavior with invalid attribute (3rd param) as 0
// as it is attribute hence avoiding the negative tests with 3rd param
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
// checking the behaviour of the api with ptr allocated using
// hipHostMalloc
void *ptr = nullptr;
SECTION("Checking behavior with hipHostMalloc ptr") {
HIP_CHECK(hipHostMalloc(&ptr, MEM_SIZE, 0));
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
ptr, MEM_SIZE), __LINE__));
HIP_CHECK(hipHostFree(ptr));
}
HIP_CHECK(hipFree(devPtr));
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
std::vector<int32_t> data(device_count);
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), kPageSize));
for (auto device : data) {
REQUIRE(device == hipInvalidDeviceId);
}
for (auto device = 0; device < device_count; ++device) {
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, device));
}
HIP_CHECK(hipMemRangeGetAttribute(data.data(), sizeof(data), hipMemRangeAttributeAccessedBy,
allocation.ptr(), kPageSize));
// Use std::find since there is no guaranteed order in which devices will be returned
for (auto device = 0; device < device_count; ++device) {
REQUIRE(std::find(cbegin(data), cend(data), device) != cend(data));
}
}
/* This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part*/
TEST_CASE("Unit_hipMemRangeGetAttribute_AccessedBy1") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
if (OutData[0] != 0) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
for (int i = 1; i < Ngpus; ++i) {
if (OutData[i] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (Ngpus >= 2) {
for (int i = 0; i < Ngpus; ++i) {
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, i));
}
// checking the behavior with dataSize less than the number of gpus
// This should not result in segfault.
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*(Ngpus-1),
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
// OutData should have stored the gpu ordinals for which AccessedBy is
// assigned except for the last element which should have -2 stored
// so as to be consistent with cuda's behavior
for (int i = 0; i < (Ngpus - 1); ++i) {
if (OutData[i] != i) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (OutData[Ngpus - 1] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
TEST_CASE("Unit_hipMemRangeGetAttribute_Negative_Parameters") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
int32_t data;
LinearAllocGuard<void> managed(LinearAllocs::hipMallocManaged, kPageSize);
SECTION("data == nullptr") {
HIP_CHECK_ERROR(hipMemRangeGetAttribute(nullptr, 4, hipMemRangeAttributeReadMostly,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_size == 0") {
HIP_CHECK_ERROR(
hipMemRangeGetAttribute(&data, 0, hipMemRangeAttributeReadMostly, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_size != 4 with hipMemRangeAttributeReadMostly") {
HIP_CHECK_ERROR(
hipMemRangeGetAttribute(&data, 8, hipMemRangeAttributeReadMostly, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_size != 4 with hipMemRangeAttributePreferredLocation") {
HIP_CHECK_ERROR(hipMemRangeGetAttribute(&data, 8, hipMemRangeAttributePreferredLocation,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_size != 4 with hipMemRangeAttributeLastPrefetchLocation") {
HIP_CHECK_ERROR(hipMemRangeGetAttribute(&data, 8, hipMemRangeAttributeLastPrefetchLocation,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_size is not a multiple of 4 with hipMemRangeAttributeAccessedBy") {
HIP_CHECK_ERROR(hipMemRangeGetAttribute(&data, 10, hipMemRangeAttributeAccessedBy,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("invalid attribute") {
HIP_CHECK_ERROR(hipMemRangeGetAttribute(&data, 4, static_cast<hipMemRangeAttribute>(999),
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("dev_ptr == nullptr") {
HIP_CHECK_ERROR(
hipMemRangeGetAttribute(&data, 4, hipMemRangeAttributeReadMostly, nullptr, kPageSize),
hipErrorInvalidValue);
}
SECTION("dev_ptr is not managed memory") {
LinearAllocGuard<void> non_managed(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK_ERROR(hipMemRangeGetAttribute(&data, 4, hipMemRangeAttributeReadMostly,
non_managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("count == 0") {
HIP_CHECK_ERROR(
hipMemRangeGetAttribute(&data, 4, hipMemRangeAttributeReadMostly, managed.ptr(), 0),
hipErrorInvalidValue);
}
}
/* Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).*/
/* Need to discuss the difference in behavior w.r.t cuda*/
TEST_CASE("Unit_hipMemRangeGetAttribte_3") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096*4, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetReadMostly, 0));
// The Api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetPreferredLocation, 0));
// The api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
(Hmm), MEM_SZ));
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash*/
TEST_CASE("Unit_hipMemRangeGetAttribute_4") {
int managed = HmmAttrPrint();
if (managed == 1) {
int *Hmm = NULL, PageSz = 4096, Ngpus, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[i] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, 4*PageSz));
SECTION("Set ReadMostly & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetReadMostly, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetAccessedBy, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetPreferredLocation,
0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetPreferredLocation,
0));
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute*/
TEST_CASE("Unit_hipMemRangeGetAttribute_PrefetchAndGtAttr") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, RND_NUM = 999;
size_t PageSz = 4096;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, PageSz*4));
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(Hmm, PageSz*4, 0, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeLastPrefetchLocation,
Hmm, PageSz*4));
HIP_CHECK(hipStreamDestroy(strm));
HIP_CHECK(hipFree(Hmm));
if (OutData[0] != 0) {
WARN("Didnt receive expected value at line: " << __LINE__);
delete[] OutData;
REQUIRE(false);
}
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
+408
Просмотреть файл
@@ -0,0 +1,408 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description:
Scenario-1: The following function tests the count parameter(last param) to
hipMemRangeGetAttribute api by passing possible extreme values.
Curently the only way to test if count param working properly is to verify
the first parameter of hipMemRangeGetAttribute() api has value 1 stored
Scenario-2: This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part
Scenario-3: Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).
Scenario-4: The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash
Scenario-5: The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute
Scenario-6: The following Test Case does negative tests on hipMemRangeGetAttribute()*/
#include <hip_test_common.hh>
#include <stdlib.h>
#ifdef __linux__
#include <unistd.h>
#include <sys/sysinfo.h>
#endif
static bool CheckError(hipError_t err, int LineNo) {
if (err == hipSuccess) {
WARN("Error expected but received hipSuccess at line no.:"
<< LineNo);
return false;
} else {
return true;
}
}
static int HmmAttrPrint() {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
return managed;
}
// The following function tests the count parameter(last param) to
// hipMemRangeGetAttribute api by passing possible extreme values.
// Curently the only way to test if count param working properly is to verify
// the first parameter of hipMemRangeGetAttribute() api has value 1 stored
TEST_CASE("Unit_hipMemRangeGetAttribute_TstCountParam") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999, FLG_READMOSTLY_ENBLD = 1;
bool IfTestPassed = true;
int data = RND_NUM, *devPtr = nullptr;
size_t TotGpuMem, TotGpuFreeMem;
HIP_CHECK(hipMemGetInfo(&TotGpuFreeMem, &TotGpuMem));
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(reinterpret_cast<void*>(&data),
sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, TotGpuFreeMem, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, TotGpuFreeMem, hipMemAdviseSetReadMostly,
0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, TotGpuFreeMem));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, (TotGpuFreeMem - 1),
hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, (TotGpuFreeMem - 1),
hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, (TotGpuFreeMem - 1)));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following Test Case does negative tests on hipMemRangeGetAttribute()*/
TEST_CASE("Unit_hipMemRangeGetAttribute_NegativeTests") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999;
float *devPtr = nullptr;
int NumDevs;
HIP_CHECK(hipGetDeviceCount(&NumDevs));
int data = RND_NUM;
int *OutData = new int[NumDevs];
for (int m = 0; m < NumDevs; ++m) {
OutData[m] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
// checking the behavior with dataSize 0
SECTION("checking the behavior with dataSize 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, 0,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and even
SECTION("checking the behavior with dataSize > 4 and even") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 6,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and odd
SECTION("checking the behavior with dataSize > 4 and odd") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 7,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize which is not multiple of 4
SECTION("checking the behavior with dataSize which is not multiple of 4") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 27,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behaviour with devPtr(4th param) as NULL
SECTION("checking the behaviour with devPtr(4th param) as NULL") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
NULL, MEM_SIZE), __LINE__));
}
// checking the behaviour with count(5th param) as 0
SECTION("checking the behaviour with count(5th param) as 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, 0), __LINE__));
}
// checking the behavior with invalid attribute (3rd param) as 0
// as it is attribute hence avoiding the negative tests with 3rd param
// checking the behaviour of the api with ptr allocated using
// hipHostMalloc
void *ptr = nullptr;
SECTION("Checking behavior with hipHostMalloc ptr") {
HIP_CHECK(hipHostMalloc(&ptr, MEM_SIZE, 0));
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
ptr, MEM_SIZE), __LINE__));
HIP_CHECK(hipHostFree(ptr));
}
HIP_CHECK(hipFree(devPtr));
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part*/
TEST_CASE("Unit_hipMemRangeGetAttribute_AccessedBy1") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
if (OutData[0] != 0) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
for (int i = 1; i < Ngpus; ++i) {
if (OutData[i] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (Ngpus >= 2) {
for (int i = 0; i < Ngpus; ++i) {
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, i));
}
// checking the behavior with dataSize less than the number of gpus
// This should not result in segfault.
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*(Ngpus-1),
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
// OutData should have stored the gpu ordinals for which AccessedBy is
// assigned except for the last element which should have -2 stored
// so as to be consistent with cuda's behavior
for (int i = 0; i < (Ngpus - 1); ++i) {
if (OutData[i] != i) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (OutData[Ngpus - 1] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).*/
/* Need to discuss the difference in behavior w.r.t cuda*/
TEST_CASE("Unit_hipMemRangeGetAttribte_3") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096*4, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetReadMostly, 0));
// The Api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetPreferredLocation, 0));
// The api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
(Hmm), MEM_SZ));
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash*/
TEST_CASE("Unit_hipMemRangeGetAttribute_4") {
int managed = HmmAttrPrint();
if (managed == 1) {
int *Hmm = NULL, PageSz = 4096, Ngpus, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[i] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, 4*PageSz));
SECTION("Set ReadMostly & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetReadMostly, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetAccessedBy, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetPreferredLocation,
0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetPreferredLocation,
0));
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute*/
TEST_CASE("Unit_hipMemRangeGetAttribute_PrefetchAndGtAttr") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, RND_NUM = 999;
size_t PageSz = 4096;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, PageSz*4));
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(Hmm, PageSz*4, 0, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeLastPrefetchLocation,
Hmm, PageSz*4));
HIP_CHECK(hipStreamDestroy(strm));
HIP_CHECK(hipFree(Hmm));
if (OutData[0] != 0) {
WARN("Didnt receive expected value at line: " << __LINE__);
delete[] OutData;
REQUIRE(false);
}
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
+127 -297
Просмотреть файл
@@ -1,325 +1,155 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description:
Scenario-1: Testing basic working of hipMemRangeGetAttributes()
api with different flags
Scenario-2: Negative testing with hipMemRangeGetAttributes() api
*/
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#define MEM_SIZE 8192
#include <resource_guards.hh>
#include <utils.hh>
static bool CheckError(hipError_t err, int LineNo) {
if (err == hipSuccess) {
WARN("Error expected but received hipSuccess at line no.:"
<< LineNo);
return false;
} else {
return true;
TEST_CASE("Unit_hipMemRangeGetAttributes_Positive_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
LinearAllocGuard<void> allocation(LinearAllocs::hipMallocManaged, kPageSize);
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetPreferredLocation, 0));
HIP_CHECK(hipMemPrefetchAsync(allocation.ptr(), kPageSize, hipCpuDeviceId));
HIP_CHECK(hipMemAdvise(allocation.ptr(), kPageSize, hipMemAdviseSetAccessedBy, 0));
constexpr size_t num_attributes = 4;
std::array<hipMemRangeAttribute, num_attributes> attributes = {
hipMemRangeAttributeReadMostly, hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeLastPrefetchLocation, hipMemRangeAttributeAccessedBy};
std::array<int32_t*, num_attributes> data;
for (auto& ptr : data) {
ptr = new int32_t;
}
std::array<size_t, num_attributes> data_sizes = {4, 4, 4, 4};
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(data.data()), data_sizes.data(),
attributes.data(), num_attributes, allocation.ptr(),
kPageSize));
REQUIRE(data[0][0] == 1);
REQUIRE(data[1][0] == 0);
REQUIRE(data[2][0] == hipCpuDeviceId);
REQUIRE(data[3][0] == 0);
for (auto ptr : data) {
delete ptr;
}
}
static int HmmAttrPrint() {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
return managed;
}
TEST_CASE("Unit_hipMemRangeGetAttributes_Negative_Parameters") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory not supported");
return;
}
#ifdef __linux__
/* Test Scenario: Testing basic working of hipMemRangeGetAttributes()
api with different flags */
constexpr size_t num_attributes = 4;
hipMemRangeAttribute attributes[] = {
hipMemRangeAttributeReadMostly, hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeLastPrefetchLocation, hipMemRangeAttributeAccessedBy};
TEST_CASE("Unit_hipMemRangeGetAttributes_TstFlgs") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
bool IfTestPassed = true;
int NumDevs = 0;
int *Outpt[4], *AcsdBy = nullptr;
float *Hmm = nullptr;
hipStream_t strm;
hipMemRangeAttribute AttrArr[4] =
{hipMemRangeAttributeReadMostly,
hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeAccessedBy,
hipMemRangeAttributeLastPrefetchLocation};
HIP_CHECK(hipGetDeviceCount(&NumDevs));
AcsdBy = new int(NumDevs);
size_t dataSizes[4] = {sizeof(int), sizeof(int),
(NumDevs * sizeof(int)), sizeof(int)};
Outpt[0] = new int;
Outpt[1] = new int;
Outpt[2] = new int[NumDevs];
Outpt[3] = new int;
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SIZE, hipMemAttachGlobal));
for (int i = 0; i < NumDevs; ++i) {
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseSetReadMostly, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
dataSizes, AttrArr, 4, Hmm,
MEM_SIZE));
if (*(Outpt[0]) != 1) {
WARN("Attempt to set hipMemAdviseSetReadMostly flag failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseUnsetReadMostly, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
int32_t* data[num_attributes];
for (auto& ptr : data) {
ptr = new int32_t;
}
size_t data_sizes[] = {4, 4, 4, 4};
if (*(Outpt[0]) != 0) {
WARN("Attempt to set hipMemAdviseUnsetReadMostly flag failed!\n");
IfTestPassed = false;
}
LinearAllocGuard<void> managed(LinearAllocs::hipMallocManaged, kPageSize);
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE,
hipMemAdviseSetPreferredLocation, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[1]) != i) {
WARN("Attempt to set hipMemAdviseSetPreferredLocation flag");
WARN(" failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseSetAccessedBy, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if ((Outpt[2][0]) != i) {
WARN("Attempt to set hipMemAdviseSetAccessedBy flag");
WARN(" failed!\n");
IfTestPassed = false;
}
SECTION("data == nullptr") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(nullptr, data_sizes, attributes, num_attributes,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseUnsetAccessedBy, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (!((Outpt[2][i]) < 0)) {
WARN("Attempt to set hipMemAdviseUnsetAccessedBy flag failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(Hmm, MEM_SIZE, i, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[3]) != i) {
WARN("Attempt to prefetch memory to device: " << i);
WARN("failed!\n");
IfTestPassed = false;
}
// Prefetching back to Host
HIP_CHECK(hipMemPrefetchAsync(Hmm, MEM_SIZE, -1, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[3]) != -1) {
WARN("Attempt to prefetch memory to Host failed!\n");
IfTestPassed = false;
}
}
SECTION("data contains invalid pointers") {
void* invalid_data[num_attributes] = {nullptr};
HIP_CHECK_ERROR(hipMemRangeGetAttributes(invalid_data, data_sizes, attributes, num_attributes,
managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
HIP_CHECK(hipFree(Hmm));
delete[] AcsdBy;
for (int i = 0; i < 4; ++i) {
delete Outpt[i];
}
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
SECTION("data_sizes == nullptr") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), nullptr, attributes,
num_attributes, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("data_sizes contains invalid values") {
size_t invalid_data_sizes[] = {4, 5, 4, 6};
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), invalid_data_sizes,
attributes, num_attributes, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("attributes == nullptr") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, nullptr,
num_attributes, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("attributes contains invalid attributes") {
hipMemRangeAttribute invalid_attributes[] = {
hipMemRangeAttributeReadMostly, hipMemRangeAttributePreferredLocation,
static_cast<hipMemRangeAttribute>(999), hipMemRangeAttributeAccessedBy};
HIP_CHECK_ERROR(
hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, invalid_attributes,
num_attributes, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("num_attributes == 0") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, attributes,
0, managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("dev_ptr == nullptr") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, attributes,
num_attributes, nullptr, kPageSize),
hipErrorInvalidValue);
}
SECTION("dev_ptr is not managed memory") {
LinearAllocGuard<void> non_managed(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, attributes,
num_attributes, non_managed.ptr(), kPageSize),
hipErrorInvalidValue);
}
SECTION("count == 0") {
HIP_CHECK_ERROR(hipMemRangeGetAttributes(reinterpret_cast<void**>(data), data_sizes, attributes,
num_attributes, managed.ptr(), 0),
hipErrorInvalidValue);
}
for (auto ptr : data) {
delete ptr;
}
}
/* Test Scenario: Negative testing with hipMemRangeGetAttributes() api*/
TEST_CASE("Unit_hipMemRangeGetAttributes_NegativeTst") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
bool IfTestPassed = true;
int NumDevs = 0, *Outpt[4];
float *Hmm = nullptr;
hipMemRangeAttribute AttrArr[4] =
{hipMemRangeAttributeReadMostly,
hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeAccessedBy,
hipMemRangeAttributeLastPrefetchLocation};
HIP_CHECK(hipGetDeviceCount(&NumDevs));
size_t dataSizes[4] = {sizeof(int), sizeof(int),
(NumDevs * sizeof(int)), sizeof(int)};
Outpt[0] = new int;
Outpt[1] = new int;
Outpt[2] = new int[NumDevs];
Outpt[3] = new int;
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(Hmm , MEM_SIZE, hipMemAdviseSetReadMostly, 0));
// passing zero for num of attributes param(4th)
SECTION("passing zero for num of attributes param(4th)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 0, Hmm, MEM_SIZE), __LINE__)) {
IfTestPassed = false;
}
}
// the first dataSize element passed as 0
dataSizes[0] = 0;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("the first dataSize element passed as 0") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 2 while the requirement is multiple of 4
dataSizes[0] = 2;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 2 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 6 while the requirement is multiple of 4
dataSizes[0] = 6;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 6 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 7 while the requirement is multiple of 4
dataSizes[0] = 7;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 7 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing dataSize as 7 for attribute hipMemRangeAttributeAccessedBy
hipMemRangeAttribute AttrArr1[1] = {hipMemRangeAttributeAccessedBy};
dataSizes[2] = {7};
SECTION("passing dataSize as 7 for attribute hipMemRangeAttrAccessedBy") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr1, 1, Hmm, MEM_SIZE), __LINE__)) {
IfTestPassed = false;
}
}
// Passing NULL as first parameter
SECTION("Passing NULL as first parameter") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(NULL),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing count parameter as zero
SECTION("Passing count parameter as zero") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, 0),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing NULL for Attribute array(3rd param)
SECTION("Passing NULL for Attribute array(3rd param)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
NULL, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing 0 for Attribute array(3rd param)
SECTION("Passing 0 for Attribute array(3rd param)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
0, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
for (int i = 0; i < 4; ++i) {
delete Outpt[i];
}
REQUIRE(IfTestPassed);
// The following scenarios have been removed considering the nature of the
// api. With Consultation with Maneesh Gupta, the following scenarios
// have been removed.
// passing numAttributes as 4 while the attributes array has only 2 members
// passing numAttributes as 10 while the attributes array has only 2 members
// length of the list of dataSizes less than the number of
// attributes being probed
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
#endif
+325
Просмотреть файл
@@ -0,0 +1,325 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description:
Scenario-1: Testing basic working of hipMemRangeGetAttributes()
api with different flags
Scenario-2: Negative testing with hipMemRangeGetAttributes() api
*/
#include <hip_test_common.hh>
#define MEM_SIZE 8192
static bool CheckError(hipError_t err, int LineNo) {
if (err == hipSuccess) {
WARN("Error expected but received hipSuccess at line no.:"
<< LineNo);
return false;
} else {
return true;
}
}
static int HmmAttrPrint() {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
return managed;
}
#ifdef __linux__
/* Test Scenario: Testing basic working of hipMemRangeGetAttributes()
api with different flags */
TEST_CASE("Unit_hipMemRangeGetAttributes_TstFlgs") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
bool IfTestPassed = true;
int NumDevs = 0;
int *Outpt[4], *AcsdBy = nullptr;
float *Hmm = nullptr;
hipStream_t strm;
hipMemRangeAttribute AttrArr[4] =
{hipMemRangeAttributeReadMostly,
hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeAccessedBy,
hipMemRangeAttributeLastPrefetchLocation};
HIP_CHECK(hipGetDeviceCount(&NumDevs));
AcsdBy = new int(NumDevs);
size_t dataSizes[4] = {sizeof(int), sizeof(int),
(NumDevs * sizeof(int)), sizeof(int)};
Outpt[0] = new int;
Outpt[1] = new int;
Outpt[2] = new int[NumDevs];
Outpt[3] = new int;
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SIZE, hipMemAttachGlobal));
for (int i = 0; i < NumDevs; ++i) {
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseSetReadMostly, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
dataSizes, AttrArr, 4, Hmm,
MEM_SIZE));
if (*(Outpt[0]) != 1) {
WARN("Attempt to set hipMemAdviseSetReadMostly flag failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseUnsetReadMostly, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[0]) != 0) {
WARN("Attempt to set hipMemAdviseUnsetReadMostly flag failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE,
hipMemAdviseSetPreferredLocation, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[1]) != i) {
WARN("Attempt to set hipMemAdviseSetPreferredLocation flag");
WARN(" failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseSetAccessedBy, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if ((Outpt[2][0]) != i) {
WARN("Attempt to set hipMemAdviseSetAccessedBy flag");
WARN(" failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipMemAdvise(Hmm, MEM_SIZE, hipMemAdviseUnsetAccessedBy, i));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (!((Outpt[2][i]) < 0)) {
WARN("Attempt to set hipMemAdviseUnsetAccessedBy flag failed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(Hmm, MEM_SIZE, i, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[3]) != i) {
WARN("Attempt to prefetch memory to device: " << i);
WARN("failed!\n");
IfTestPassed = false;
}
// Prefetching back to Host
HIP_CHECK(hipMemPrefetchAsync(Hmm, MEM_SIZE, -1, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttributes(reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE));
if (*(Outpt[3]) != -1) {
WARN("Attempt to prefetch memory to Host failed!\n");
IfTestPassed = false;
}
}
HIP_CHECK(hipFree(Hmm));
delete[] AcsdBy;
for (int i = 0; i < 4; ++i) {
delete Outpt[i];
}
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* Test Scenario: Negative testing with hipMemRangeGetAttributes() api*/
TEST_CASE("Unit_hipMemRangeGetAttributes_NegativeTst") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
bool IfTestPassed = true;
int NumDevs = 0, *Outpt[4];
float *Hmm = nullptr;
hipMemRangeAttribute AttrArr[4] =
{hipMemRangeAttributeReadMostly,
hipMemRangeAttributePreferredLocation,
hipMemRangeAttributeAccessedBy,
hipMemRangeAttributeLastPrefetchLocation};
HIP_CHECK(hipGetDeviceCount(&NumDevs));
size_t dataSizes[4] = {sizeof(int), sizeof(int),
(NumDevs * sizeof(int)), sizeof(int)};
Outpt[0] = new int;
Outpt[1] = new int;
Outpt[2] = new int[NumDevs];
Outpt[3] = new int;
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(Hmm , MEM_SIZE, hipMemAdviseSetReadMostly, 0));
// passing zero for num of attributes param(4th)
SECTION("passing zero for num of attributes param(4th)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 0, Hmm, MEM_SIZE), __LINE__)) {
IfTestPassed = false;
}
}
// the first dataSize element passed as 0
dataSizes[0] = 0;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("the first dataSize element passed as 0") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 2 while the requirement is multiple of 4
dataSizes[0] = 2;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 2 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 6 while the requirement is multiple of 4
dataSizes[0] = 6;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 6 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing datasize as 7 while the requirement is multiple of 4
dataSizes[0] = 7;
dataSizes[1] = sizeof(int);
dataSizes[2] = NumDevs * sizeof(int);
dataSizes[3] = sizeof(int);
SECTION("datasize as 7 while the requirement is multiple of 4") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// passing dataSize as 7 for attribute hipMemRangeAttributeAccessedBy
hipMemRangeAttribute AttrArr1[1] = {hipMemRangeAttributeAccessedBy};
dataSizes[2] = {7};
SECTION("passing dataSize as 7 for attribute hipMemRangeAttrAccessedBy") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr1, 1, Hmm, MEM_SIZE), __LINE__)) {
IfTestPassed = false;
}
}
// Passing NULL as first parameter
SECTION("Passing NULL as first parameter") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(NULL),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing count parameter as zero
SECTION("Passing count parameter as zero") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
AttrArr, 4, Hmm, 0),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing NULL for Attribute array(3rd param)
SECTION("Passing NULL for Attribute array(3rd param)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
NULL, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
// Passing 0 for Attribute array(3rd param)
SECTION("Passing 0 for Attribute array(3rd param)") {
if (!CheckError(hipMemRangeGetAttributes(
reinterpret_cast<void**>(Outpt),
reinterpret_cast<size_t*>(dataSizes),
0, 4, Hmm, MEM_SIZE),
__LINE__)) {
IfTestPassed = false;
}
}
for (int i = 0; i < 4; ++i) {
delete Outpt[i];
}
REQUIRE(IfTestPassed);
// The following scenarios have been removed considering the nature of the
// api. With Consultation with Maneesh Gupta, the following scenarios
// have been removed.
// passing numAttributes as 4 while the attributes array has only 2 members
// passing numAttributes as 10 while the attributes array has only 2 members
// length of the list of dataSizes less than the number of
// attributes being probed
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
#endif
+219 -296
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,316 +16,239 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DFromArray API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DFromArray Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and API is triggered from peer GPU.
Testcase Scenarios :
Unit_hipMemcpy2DFromArray_Positive_Default - Test basic memcpy between 2D array
and host/device with hipMemcpy2DFromArray api
Unit_hipMemcpy2DFromArray_Positive_Synchronization_Behavior - Test
synchronization behavior for hipMemcpy2DFromArray api
Unit_hipMemcpy2DFromArray_Positive_ZeroWidthHeight - Test that no data is copied
when width/height is set to 0 Unit_hipMemcpy2DFromArray_Negative_Parameters -
Test unsuccessful execution of hipMemcpy2DFromArray api when parameters are
invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <resource_guards.hh>
#include <utils.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This testcase verifies device to host copy for hipMemcpy2DFromArray API
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
TEST_CASE("Unit_hipMemcpy2DFromArray_Positive_Default") {
using namespace std::placeholders;
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(1, 16, 32, 48);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
* of hipMemcpy2DFromArray API
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr}, *valData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &valData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Destination width is 0") {
REQUIRE(hipMemcpy2DFromArray(A_h, 0, A_d,
0, 0, NUM_W*sizeof(float),
NUM_H, hipMemcpyDeviceToHost) != hipSuccess);
}
// hipMemcpy2DFromArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with height 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width,
0, hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// hipMemcpy2DFromArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with width 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, 0,
NUM_H, hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
SECTION("Array to host") {
Memcpy2DHostFromAShell<false, int>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToHost),
width, height);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
nullptr, valData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_PinnedMemSameGPU") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
SECTION("Array to host with default kind") {
Memcpy2DHostFromAShell<false, int>(std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0,
width * sizeof(int), height, hipMemcpyDefault),
width, height);
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Intializa A_d with A_h
* Copy A_d->E_h which is a pinned host memory
* OUTPUT: For validating the result,Copying A_d device variable
* --> E_h host variable
* and verifying A_h with E_h
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_multiDevicePinnedMemPeerGpu") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, A_h,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DFromArray(E_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
#if HT_NVIDIA // EXSWHTEC-120
SECTION("Array to device") {
SECTION("Peer access disabled") {
Memcpy2DDeviceFromAShell<false, false, int>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DFromArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DFromArray_multiDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
SECTION("Peer access enabled") {
Memcpy2DDeviceFromAShell<false, true, int>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios of
* hipMemcpy2DFromArray API
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DFromArray(nullptr, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, nullptr,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
SECTION("Array to device with default kind") {
SECTION("Peer access disabled") {
Memcpy2DDeviceFromAShell<false, false, int>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
SECTION("Peer access enabled") {
Memcpy2DDeviceFromAShell<false, true, int>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, A_d, 1,
1, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, A_d, 0,
0, width+2, NUM_H+2,
hipMemcpyDeviceToHost) != hipSuccess);
}
// Cleaning of memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
#endif
}
TEST_CASE("Unit_hipMemcpy2DFromArray_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
SECTION("Array to host") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyAtoHPageableSyncBehavior(std::bind(hipMemcpy2DFromArray, _1, width * sizeof(int), _2, 0,
0, width * sizeof(int), height, hipMemcpyDeviceToHost),
width, height, true);
MemcpyAtoHPinnedSyncBehavior(std::bind(hipMemcpy2DFromArray, _1, width * sizeof(int), _2, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost),
width, height, true);
}
#if HT_NVIDIA // EXSWHTEC-214
SECTION("Array to device") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyAtoDSyncBehavior(std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToDevice),
width, height, false);
}
#endif
}
TEST_CASE("Unit_hipMemcpy2DFromArray_Positive_ZeroWidthHeight") {
using namespace std::placeholders;
const auto width = 16;
const auto height = 16;
SECTION("Array to host") {
SECTION("Height is 0") {
Memcpy2DFromArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), 0,
hipMemcpyDeviceToHost),
width, height);
}
SECTION("Width is 0") {
Memcpy2DFromArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, 0, height, hipMemcpyDeviceToHost),
width, height);
}
}
SECTION("Array to device") {
SECTION("Height is 0") {
Memcpy2DFromArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, width * sizeof(int), 0,
hipMemcpyDeviceToDevice),
width, height);
}
SECTION("Width is 0") {
Memcpy2DFromArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DFromArray, _1, _2, _3, 0, 0, 0, height, hipMemcpyDeviceToDevice),
width, height);
}
}
}
TEST_CASE("Unit_hipMemcpy2DFromArray_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 32;
const auto height = 32;
const auto allocation_size = 2 * width * height * sizeof(int);
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("Array to host") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DFromArray(nullptr, 2 * width * sizeof(int), array_alloc.ptr(), 0,
0, width * sizeof(int), height, hipMemcpyDeviceToHost),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), nullptr, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost),
hipErrorInvalidHandle);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("dpitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), width * sizeof(int) - 10, array_alloc.ptr(), 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 1, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 0, 1,
width * sizeof(int), height, hipMemcpyDeviceToHost),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 0, 0,
width * sizeof(int) + 1, height, hipMemcpyDeviceToHost),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 0, 0,
width * sizeof(int), height + 1, hipMemcpyDeviceToHost),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 0, 0,
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
SECTION("Array to device") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DFromArray(nullptr, device_alloc.pitch(), array_alloc.ptr(), 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), nullptr, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidHandle);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("dpitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), width * sizeof(int) - 10, array_alloc.ptr(), 0,
0, width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr(), 1, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr(), 0, 1,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr(), 0, 0,
width * sizeof(int) + 1, height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr(), 0, 0,
width * sizeof(int), height + 1, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArray(device_alloc.ptr(), device_alloc.pitch(), array_alloc.ptr(), 0, 0,
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
}
+252 -337
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,357 +16,272 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DFromArrayAsync API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DFromArrayAsync Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and stream is created in peer GPU.
Testcase Scenarios :
Unit_hipMemcpy2DFromArrayAsync_Positive_Default - Test basic async memcpy
between 2D array and host/device with hipMemcpy2DFromArrayAsync api
Unit_hipMemcpy2DFromArrayAsync_Positive_Synchronization_Behavior - Test
synchronization behavior for hipMemcpy2DFromArrayAsync api
Unit_hipMemcpy2DFromArrayAsync_Positive_ZeroWidthHeight - Test that no data is
copied when width/height is set to 0
Unit_hipMemcpy2DFromArrayAsync_Negative_Parameters - Test unsuccessful execution
of hipMemcpy2DFromArrayAsync api when parameters are invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <resource_guards.hh>
#include <utils.hh>
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Positive_Default") {
using namespace std::placeholders;
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
const StreamGuard stream_guard(stream_type);
const hipStream_t stream = stream_guard.stream();
/*
* This testcase copies the data from host to device of
hipMemcpy2DFromArrayAsync API
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(1, 16, 32, 48);
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
SECTION("Calling hipMemcpy2DFromArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DFromArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
* of hipMemcpy2DFromArrayAsync API
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr}, *valData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &valData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Destination width is 0") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, 0, A_d,
0, 0, NUM_W*sizeof(float),
NUM_H, hipMemcpyDeviceToHost, stream)
!= hipSuccess);
}
// hipMemcpy2DFromArrayAsync API would return success for
// width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with height 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(hData, width, A_d,
0, 0, NUM_W*sizeof(float),
0, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// hipMemcpy2DFromArrayAsync API would return success for
// width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with width 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(hData, width, A_d,
0, 0, 0,
NUM_H, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
SECTION("Array to host") {
Memcpy2DHostFromAShell<true, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToHost, stream),
width, height, stream);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
nullptr, valData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArrayAsync API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_PinnedHostMemSameGpu") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
SECTION("Array to host with default kind") {
Memcpy2DHostFromAShell<true, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArrayAsync API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Initialize data, A_h --> A_d device variable
* whose memory is allocated in GPU 0
then A_d-->E_h in GPU1
* OUTPUT: validating the result by comparing A_h and E_h
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_multiDevicePinnedHostMem") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DFromArrayAsync(E_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
#if HT_NVIDIA // EXSWHTEC-213
SECTION("Array to device") {
SECTION("Peer access disabled") {
Memcpy2DDeviceFromAShell<true, false, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DFromArrayAsync API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_multiDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
SECTION("Peer access enabled") {
Memcpy2DDeviceFromAShell<true, true, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
* of hipMemcpy2DFromArrayAsync API
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DFromArrayAsync(nullptr, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, nullptr,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
SECTION("Array to device with default kind") {
SECTION("Peer access disabled") {
Memcpy2DDeviceFromAShell<true, false, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
SECTION("Peer access enabled") {
Memcpy2DDeviceFromAShell<true, true, int>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, A_d, 1,
1, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, A_d, 0,
0, width+2, NUM_H+2,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
// Cleaning of Memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
#endif
}
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
SECTION("Array to host") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyAtoHPageableSyncBehavior(
std::bind(hipMemcpy2DFromArrayAsync, _1, width * sizeof(int), _2, 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToHost, nullptr),
width, height, false);
MemcpyAtoHPinnedSyncBehavior(
std::bind(hipMemcpy2DFromArrayAsync, _1, width * sizeof(int), _2, 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToHost, nullptr),
width, height, false);
}
SECTION("Array to device") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyAtoDSyncBehavior(std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
width, height, false);
}
}
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Positive_ZeroWidthHeight") {
using namespace std::placeholders;
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
const StreamGuard stream_guard(stream_type);
const hipStream_t stream = stream_guard.stream();
const auto width = 16;
const auto height = 16;
SECTION("Array to host") {
SECTION("Height is 0") {
Memcpy2DFromArrayZeroWidthHeight<true>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), 0,
hipMemcpyDeviceToHost, stream),
width, height, stream);
}
SECTION("Width is 0") {
Memcpy2DFromArrayZeroWidthHeight<true>(std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0,
0, height, hipMemcpyDeviceToHost, stream),
width, height, stream);
}
}
SECTION("Array to device") {
SECTION("Height is 0") {
Memcpy2DFromArrayZeroWidthHeight<true>(
std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0, width * sizeof(int), 0,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
SECTION("Width is 0") {
Memcpy2DFromArrayZeroWidthHeight<true>(std::bind(hipMemcpy2DFromArrayAsync, _1, _2, _3, 0, 0,
0, height, hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
}
}
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 32;
const auto height = 32;
const auto allocation_size = 2 * width * height * sizeof(int);
const unsigned int flag = hipArrayDefault;
#if HT_NVIDIA
constexpr auto InvalidStream = [] {
StreamGuard sg(Streams::created);
return sg.stream();
};
#endif
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("Array to host") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(nullptr, 2 * width * sizeof(int), array_alloc.ptr(), 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int), nullptr, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidHandle);
}
#if HT_NVIDIA // EXSWHTEC-212
SECTION("dpitch < width") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(host_alloc.ptr(), width * sizeof(int) - 10,
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 1,
0, width * sizeof(int), height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int), array_alloc.ptr(), 0,
1, width * sizeof(int), height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int),
array_alloc.ptr(), 0, 0, width * sizeof(int) + 1,
height, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height + 1, hipMemcpyDeviceToHost, nullptr),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, static_cast<hipMemcpyKind>(-1), nullptr),
hipErrorInvalidMemcpyDirection);
}
SECTION("Invalid stream") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(host_alloc.ptr(), 2 * width * sizeof(int),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToHost, InvalidStream()),
hipErrorContextIsDestroyed);
}
#endif
}
SECTION("Array to device") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(nullptr, device_alloc.pitch(), array_alloc.ptr(), 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(), nullptr, 0, 0,
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidHandle);
}
#if HT_NVIDIA // EXSWHTEC-212
SECTION("dpitch < width") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), width * sizeof(int) - 10,
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 1, 0, width * sizeof(int),
height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 0, 1, width * sizeof(int),
height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 0, 0, width * sizeof(int) + 1,
height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height + 1, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, static_cast<hipMemcpyKind>(-1), nullptr),
hipErrorInvalidMemcpyDirection);
}
SECTION("Invalid stream") {
HIP_CHECK_ERROR(hipMemcpy2DFromArrayAsync(device_alloc.ptr(), device_alloc.pitch(),
array_alloc.ptr(), 0, 0, width * sizeof(int),
height, hipMemcpyDeviceToDevice, InvalidStream()),
hipErrorContextIsDestroyed);
}
#endif
}
}
+372
Просмотреть файл
@@ -0,0 +1,372 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DFromArrayAsync API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DFromArrayAsync Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and stream is created in peer GPU.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This testcase copies the data from host to device of
hipMemcpy2DFromArrayAsync API
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
SECTION("Calling hipMemcpy2DFromArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DFromArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
* of hipMemcpy2DFromArrayAsync API
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr}, *valData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &valData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Destination width is 0") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, 0, A_d,
0, 0, NUM_W*sizeof(float),
NUM_H, hipMemcpyDeviceToHost, stream)
!= hipSuccess);
}
// hipMemcpy2DFromArrayAsync API would return success for
// width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with height 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(hData, width, A_d,
0, 0, NUM_W*sizeof(float),
0, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// hipMemcpy2DFromArrayAsync API would return success for
// width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with width 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(hData, width, A_d,
0, 0, 0,
NUM_H, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
nullptr, valData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArrayAsync API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_PinnedHostMemSameGpu") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
}
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArrayAsync API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Initialize data, A_h --> A_d device variable
* whose memory is allocated in GPU 0
then A_d-->E_h in GPU1
* OUTPUT: validating the result by comparing A_h and E_h
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_multiDevicePinnedHostMem") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DFromArrayAsync(E_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DFromArrayAsync API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_multiDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
* of hipMemcpy2DFromArrayAsync API
*/
TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DFromArrayAsync(nullptr, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, nullptr,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, A_d, 1,
1, width, NUM_H,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DFromArrayAsync(A_h, width, A_d, 0,
0, width+2, NUM_H+2,
hipMemcpyDeviceToHost,
stream) != hipSuccess);
}
// Cleaning of Memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
+331
Просмотреть файл
@@ -0,0 +1,331 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DFromArray API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DFromArray Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and API is triggered from peer GPU.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This testcase verifies device to host copy for hipMemcpy2DFromArray API
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
* of hipMemcpy2DFromArray API
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr}, *valData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &valData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Destination width is 0") {
REQUIRE(hipMemcpy2DFromArray(A_h, 0, A_d,
0, 0, NUM_W*sizeof(float),
NUM_H, hipMemcpyDeviceToHost) != hipSuccess);
}
// hipMemcpy2DFromArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with height 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width,
0, hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// hipMemcpy2DFromArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying A_d-->hData variable
// with width 0(copy will not be performed)
// 3 validating hData<-->A_h which will not be equal as copy is not done.
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, 0,
NUM_H, hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, valData, NUM_W, NUM_H) == true);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
nullptr, valData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_PinnedMemSameGPU") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DFromArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Intializa A_d with A_h
* Copy A_d->E_h which is a pinned host memory
* OUTPUT: For validating the result,Copying A_d device variable
* --> E_h host variable
* and verifying A_h with E_h
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_multiDevicePinnedMemPeerGpu") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, A_h,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DFromArray(E_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DFromArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DFromArray_multiDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Device Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios of
* hipMemcpy2DFromArray API
*/
TEST_CASE("Unit_hipMemcpy2DFromArray_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DFromArray(nullptr, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, nullptr,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, A_d, 1,
1, width, NUM_H,
hipMemcpyDeviceToHost) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DFromArray(A_h, width, A_d, 0,
0, width+2, NUM_H+2,
hipMemcpyDeviceToHost) != hipSuccess);
}
// Cleaning of memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
+214 -297
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,317 +16,234 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DToArray API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DToArray Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and API is triggered from peer GPU.
Testcase Scenarios :
Unit_hipMemcpy2DToArray_Positive_Default - Test basic memcpy between host/device
and 2D array with hipMemcpy2DToArray api
Unit_hipMemcpy2DToArray_Positive_Synchronization_Behavior - Test synchronization
behavior for hipMemcpy2DToArray api
Unit_hipMemcpy2DToArray_Positive_ZeroWidthHeight - Test that no data is copied
when width/height is set to 0 Unit_hipMemcpy2DToArray_Negative_Parameters - Test
unsuccessful execution of hipMemcpy2DToArray api when parameters are invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <iostream>
#include <resource_guards.hh>
#include <utils.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This Scenario copies the data from host to device
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_Default") {
using namespace std::placeholders;
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(1, 16, 32, 48);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Source width is 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0, hData, 0,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with height 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
width, 0, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with width 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
0, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
SECTION("Host to Array") {
Memcpy2DHosttoAShell<false, int>(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3,
width * sizeof(int), height, hipMemcpyHostToDevice),
width, height);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_PinnedMemSameGPU") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
SECTION("Host to Array with default kind") {
Memcpy2DHosttoAShell<false, int>(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3,
width * sizeof(int), height, hipMemcpyDefault),
width, height);
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Copying Host variable E_h(Initialized with value 10+i(numelements))
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with E_h[0]+i(i.e., 10+i)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_multiDevicePinnedMemPeerGpu") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, E_h,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
#if HT_NVIDIA // EXSWHTEC-120
SECTION("Device to Array") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<false, false, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DToArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DToArray_multiDeviceDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<false, true, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DToArray(nullptr, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
nullptr, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
SECTION("Device to Array with default kind") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<false, false, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<false, true, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 1, 1,
hData, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
hData, width, width+2,
NUM_H+2, hipMemcpyHostToDevice) != hipSuccess);
}
// Cleaning of memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
#endif
}
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
SECTION("Host to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyHtoASyncBehavior(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
width, height, true);
}
#if HT_NVIDIA // EXSWHTEC-214
SECTION("Device to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyDtoASyncBehavior(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int),
height, hipMemcpyDeviceToDevice),
width, height, false);
}
#endif
}
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_ZeroWidthHeight") {
using namespace std::placeholders;
const auto width = 16;
const auto height = 16;
SECTION("Array to host") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyHostToDevice),
width, height);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, 0, height, hipMemcpyHostToDevice), width,
height);
}
}
SECTION("Array to device") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyDeviceToDevice),
width, height);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, 0, height, hipMemcpyDeviceToDevice),
width, height);
}
}
}
TEST_CASE("Unit_hipMemcpy2DToArray_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 32;
const auto height = 32;
const auto allocation_size = 2 * width * height * sizeof(int);
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("Host to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(nullptr, 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, nullptr, 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("spitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), width * sizeof(int) - 10,
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 1, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 1, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int) + 1, height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height + 1, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
SECTION("Device to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(nullptr, 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, nullptr, device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("spitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), width * sizeof(int) - 10,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 1, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 1, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int) + 1, height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height + 1, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
}
+246 -333
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,354 +16,267 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DToArrayAsync API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DToArrayAsync Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and stream is created in peer GPU.
Testcase Scenarios :
Unit_hipMemcpy2DToArrayAsync_Positive_Default - Test basic async memcpy between
host/device and 2D array with hipMemcpy2DToArrayAsync api
Unit_hipMemcpy2DToArrayAsync_Positive_Synchronization_Behavior - Test
synchronization behavior for hipMemcpy2DToArrayAsync api
Unit_hipMemcpy2DToArrayAsync_Positive_ZeroWidthHeight - Test that no data is
copied when width/height is set to 0
Unit_hipMemcpy2DToArrayAsync_Negative_Parameters - Test unsuccessful execution
of hipMemcpy2DToArrayAsync api when parameters are invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <iostream>
#include <resource_guards.hh>
#include <utils.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Positive_Default") {
using namespace std::placeholders;
/*
* This Scenario copies the data from host to device
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
const StreamGuard stream_guard(stream_type);
const hipStream_t stream = stream_guard.stream();
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Calling hipMemcpy2DToArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DToArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(1, 16, 32, 48);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Source width is 0") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, 0,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
HIP_CHECK(hipStreamSynchronize(stream));
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with height 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, 0, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with width 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
0, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
SECTION("Host to Array") {
Memcpy2DHosttoAShell<true, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyHostToDevice, stream),
width, height, stream);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_PinnedHostMemSameGpu") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
SECTION("Host to Array with default kind") {
Memcpy2DHosttoAShell<true, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, PinnMem,
width, width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Copying Host variable E_h(Initialized with value 10+i(numelements))
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with E_h[0]+i(i.e., 10+i)
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_multiDevicePinnedHostMem") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, E_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
#if HT_NVIDIA // EXSWHTEC-213
SECTION("Device to Array") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<true, false, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DToArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_multiDeviceDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width, width,
NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<true, true, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DToArrayAsync(nullptr, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, nullptr,
width, width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
SECTION("Device to Array with default kind") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<true, false, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<true, true, int>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault, stream),
width, height, stream);
}
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 1, 1, hData, width,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width+2, NUM_H+2, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
// Cleaning of Memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
#endif
}
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
SECTION("Host to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyHtoASyncBehavior(std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice, nullptr),
width, height, false);
}
SECTION("Device to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyDtoASyncBehavior(std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int),
height, hipMemcpyDeviceToDevice, nullptr),
width, height, false);
}
}
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Positive_ZeroWidthHeight") {
using namespace std::placeholders;
const auto width = 16;
const auto height = 16;
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
const StreamGuard stream_guard(stream_type);
const hipStream_t stream = stream_guard.stream();
SECTION("Array to host") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyHostToDevice, stream),
width, height, stream);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, 0,
height, hipMemcpyHostToDevice, stream),
width, height, stream);
}
}
SECTION("Array to device") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(std::bind(hipMemcpy2DToArrayAsync, _1, 0, 0, _2, _3, 0,
height, hipMemcpyDeviceToDevice, stream),
width, height, stream);
}
}
}
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 32;
const auto height = 32;
const auto allocation_size = 2 * width * height * sizeof(int);
const unsigned int flag = hipArrayDefault;
#if HT_NVIDIA
constexpr auto InvalidStream = [] {
StreamGuard sg(Streams::created);
return sg.stream();
};
#endif
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("Host to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(nullptr, 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice, nullptr),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, nullptr, 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice, nullptr),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-212
SECTION("spitch < width") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, host_alloc.ptr(),
width * sizeof(int) - 10, width * sizeof(int), height,
hipMemcpyHostToDevice, nullptr),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 1, 0, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int), height,
hipMemcpyHostToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 1, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int), height,
hipMemcpyHostToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int) + 1,
height, hipMemcpyHostToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int),
height + 1, hipMemcpyHostToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int), height,
static_cast<hipMemcpyKind>(-1), nullptr),
hipErrorInvalidMemcpyDirection);
}
SECTION("Invalid stream") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, host_alloc.ptr(),
2 * width * sizeof(int), width * sizeof(int), height,
hipMemcpyHostToDevice, InvalidStream()),
hipErrorContextIsDestroyed);
}
#endif
}
SECTION("Device to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(nullptr, 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, nullptr, device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-212
SECTION("spitch < width") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, device_alloc.ptr(),
width * sizeof(int) - 10, width * sizeof(int), height,
hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(array_alloc.ptr(), 1, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 1, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, device_alloc.ptr(),
device_alloc.pitch(), width * sizeof(int) + 1, height,
hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, device_alloc.ptr(),
device_alloc.pitch(), width * sizeof(int), height + 1,
hipMemcpyDeviceToDevice, nullptr),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, device_alloc.ptr(),
device_alloc.pitch(), width * sizeof(int), height,
static_cast<hipMemcpyKind>(-1), nullptr),
hipErrorInvalidMemcpyDirection);
}
SECTION("Invalid stream") {
HIP_CHECK_ERROR(hipMemcpy2DToArrayAsync(array_alloc.ptr(), 0, 0, device_alloc.ptr(),
device_alloc.pitch(), width * sizeof(int), height,
hipMemcpyDeviceToDevice, InvalidStream()),
hipErrorContextIsDestroyed);
}
#endif
}
}
+369
Просмотреть файл
@@ -0,0 +1,369 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DToArrayAsync API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DToArrayAsync Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and stream is created in peer GPU.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <iostream>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This Scenario copies the data from host to device
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Calling hipMemcpy2DToArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DToArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Source width is 0") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, 0,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
HIP_CHECK(hipStreamSynchronize(stream));
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with height 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, 0, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with width 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, A_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
0, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_PinnedHostMemSameGpu") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
}
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, PinnMem,
width, width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Copying Host variable E_h(Initialized with value 10+i(numelements))
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with E_h[0]+i(i.e., 10+i)
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_multiDevicePinnedHostMem") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, E_h, width,
width, NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DToArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_multiDeviceDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width, width,
NUM_H, hipMemcpyHostToDevice,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DToArrayAsync(nullptr, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, nullptr,
width, width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 1, 1, hData, width,
width, NUM_H, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width+2, NUM_H+2, hipMemcpyHostToDevice,
stream) != hipSuccess);
}
// Cleaning of Memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipStreamDestroy(stream));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
+332
Просмотреть файл
@@ -0,0 +1,332 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DToArray API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DToArray Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and API is triggered from peer GPU.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <iostream>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This Scenario copies the data from host to device
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Source width is 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0, hData, 0,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with height 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
width, 0, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with width 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
0, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_PinnedMemSameGPU") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Copying Host variable E_h(Initialized with value 10+i(numelements))
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with E_h[0]+i(i.e., 10+i)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_multiDevicePinnedMemPeerGpu") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, E_h,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DToArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DToArray_multiDeviceDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DToArray(nullptr, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
nullptr, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 1, 1,
hData, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
hData, width, width+2,
NUM_H+2, hipMemcpyHostToDevice) != hipSuccess);
}
// Cleaning of memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
+85 -178
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -17,164 +17,43 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Test Scenarios:
* 1. Perform host and Pinned host Memory
* 2. Perform bytecount 0 validation for hipMemcpyAtoH API
* 3. Allocate Memory from one GPU device and call hipMemcpyAtoH from Peer
* GPU device
* 4. Perform hipMemcpyAtoH Negative Scenarios
*/
Testcase Scenarios :
Unit_hipMemcpy2DFromArray_Positive_Default - Test basic memcpy between 2D array
and host/device with hipMemcpy2DFromArray api
Unit_hipMemcpy2DFromArray_Positive_Synchronization_Behavior - Test
synchronization behavior for hipMemcpy2DFromArray api
Unit_hipMemcpy2DFromArray_Positive_ZeroWidthHeight - Test that no data is copied
when width/height is set to 0 Unit_hipMemcpy2DFromArray_Negative_Parameters -
Test unsuccessful execution of hipMemcpy2DFromArray api when parameters are
invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <resource_guards.hh>
#include <utils.hh>
TEST_CASE("Unit_hipMemcpyAtoH_Positive_Default") {
using namespace std::placeholders;
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{1};
static constexpr auto copy_bytes{2};
const auto width = GENERATE(512, 1024, 2048);
const auto allocation_size = width * sizeof(int);
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyAtoH API
Input: "A_d" initialized with "hData" Pi value
Output:"B_h" host variable output of hipMemcpyAtoH API
is then validated with "hData"
The same scenario is then verified with pinned host memory
*/
TEMPLATE_TEST_CASE("Unit_hipMemcpyAtoH_Basic", "[hipMemcpyAtoH]",
char, int, float) {
HIP_CHECK(hipSetDevice(0));
// 1 refers to pinned host memory scenario
auto memtype_check = GENERATE(0, 1);
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
if (memtype_check) {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W, true);
} else {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
}
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Performing API call
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, copy_bytes*sizeof(TestType))
== hipSuccess);
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
if (memtype_check) {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, true) == true);
} else {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
MemcpyAtoHShell<false, int>(std::bind(hipMemcpyAtoH, _1, _2, 0, allocation_size), width);
}
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyAtoH API
Memory is allocated in GPU-0 and the API is triggered from GPU-1
Input: "A_d" initialized with "hData" Pi value
Output:"B_h" host variable output of hipMemcpyAtoH API
is then validated with "hData"
*/
#if HT_AMD
TEMPLATE_TEST_CASE("Unit_hipMemcpyAtoH_multiDevice-PeerDeviceContext",
"[hipMemcpyAtoH]",
char, int, float) {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int peerAccess = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&peerAccess, 1, 0));
if (!peerAccess) {
SUCCEED("Skipped the test as there is no peer access");
} else {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
TEST_CASE("Unit_hipMemcpyAtoH_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
// Initialization of data
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
const auto width = GENERATE(512, 1024, 2048);
const auto height = 0;
const auto allocation_size = width * sizeof(int);
HIP_CHECK(hipDeviceSynchronize());
// Changing the device context
HIP_CHECK(hipSetDevice(1));
// Performing API call
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, copy_bytes*sizeof(TestType))
== hipSuccess);
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr,
hData, B_h,
nullptr, false) == true);
}
} else {
SUCCEED("skipping the testcases as numDevices < 2");
}
}
#endif
/*
This testcase verifies the negative scenarios of hipMemcpyAtoH API
*/
TEST_CASE("Unit_hipMemcpyAtoH_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Destination pointer is nullptr") {
REQUIRE(hipMemcpyAtoH(nullptr, A_d, 0, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("Source offset is more than allocated size") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 100, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("ByteCount is greater than allocated size") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, 12*sizeof(float)) != hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
MemcpyAtoHPageableSyncBehavior(std::bind(hipMemcpyAtoH, _1, _2, 0, allocation_size), width,
height, true);
MemcpyAtoHPinnedSyncBehavior(std::bind(hipMemcpyAtoH, _1, _2, 0, allocation_size), width, height,
true);
}
/*
@@ -183,37 +62,65 @@ Excluded the testcase for amd,as there is already a bug raised
SWDEV-274683
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipMemcpyAtoH_SizeCheck") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr}, *def_data{nullptr};
size_t width{NUM_W * sizeof(float)};
TEST_CASE("Unit_hipMemcpyAtoH_Positive_ZeroCount") {
const auto width = 1024;
const auto height = 0;
const auto allocation_size = width * sizeof(int);
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &def_data, nullptr, NUM_W);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
HipTest::setDefaultData<float>(NUM_W, nullptr, def_data, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
const unsigned int flag = hipArrayDefault;
SECTION("Passing 0 to copy bytes") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, 0) == hipSuccess);
REQUIRE(HipTest::checkArray(B_h, def_data, NUM_W, NUM_H) == true);
}
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<uint8_t> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION(" Source Array is nullptr") {
REQUIRE(hipMemcpyAtoH(B_h, nullptr, 0, copy_bytes*sizeof(float))
!= hipSuccess);
}
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(), sizeof(int) * width,
sizeof(int) * width, 1, hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width, fill_value);
HIP_CHECK(hipMemcpyAtoH(host_alloc.ptr(), array_alloc.ptr(), 0, 0));
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
def_data, false) == true);
ArrayFindIfNot(host_alloc.host_ptr(), static_cast<uint8_t>(fill_value), width);
}
#endif
TEST_CASE("Unit_hipMemcpyAtoH_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 1024;
const auto height = 0;
const auto allocation_size = width * sizeof(int);
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpyAtoH(nullptr, array_alloc.ptr(), 0, allocation_size),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpyAtoH(host_alloc.ptr(), nullptr, 0, allocation_size),
hipErrorInvalidValue);
}
SECTION("Offset is greater than allocated size") {
HIP_CHECK_ERROR(
hipMemcpyAtoH(host_alloc.ptr(), array_alloc.ptr(), allocation_size + 10, allocation_size),
hipErrorInvalidValue);
}
SECTION("Count is greater than allocated size") {
HIP_CHECK_ERROR(hipMemcpyAtoH(host_alloc.ptr(), array_alloc.ptr(), 0, allocation_size + 10),
hipErrorInvalidValue);
}
SECTION("2D array is allocated") {
const auto width_2d = 32;
const auto height_2d = width_2d;
const auto allocation_size_2d = width_2d * height_2d * sizeof(int);
ArrayAllocGuard<int> array_alloc_2d(make_hipExtent(width_2d, height_2d, 0), flag);
LinearAllocGuard<int> host_alloc_2d(LinearAllocs::hipHostMalloc, allocation_size_2d);
HIP_CHECK_ERROR(hipMemcpyAtoH(host_alloc_2d.ptr(), array_alloc_2d.ptr(), 0, allocation_size_2d),
hipErrorInvalidValue);
}
}
+219
Просмотреть файл
@@ -0,0 +1,219 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Test Scenarios:
* 1. Perform host and Pinned host Memory
* 2. Perform bytecount 0 validation for hipMemcpyAtoH API
* 3. Allocate Memory from one GPU device and call hipMemcpyAtoH from Peer
* GPU device
* 4. Perform hipMemcpyAtoH Negative Scenarios
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{1};
static constexpr auto copy_bytes{2};
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyAtoH API
Input: "A_d" initialized with "hData" Pi value
Output:"B_h" host variable output of hipMemcpyAtoH API
is then validated with "hData"
The same scenario is then verified with pinned host memory
*/
TEMPLATE_TEST_CASE("Unit_hipMemcpyAtoH_Basic", "[hipMemcpyAtoH]",
char, int, float) {
HIP_CHECK(hipSetDevice(0));
// 1 refers to pinned host memory scenario
auto memtype_check = GENERATE(0, 1);
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
if (memtype_check) {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W, true);
} else {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
}
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Performing API call
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, copy_bytes*sizeof(TestType))
== hipSuccess);
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
if (memtype_check) {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, true) == true);
} else {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
}
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyAtoH API
Memory is allocated in GPU-0 and the API is triggered from GPU-1
Input: "A_d" initialized with "hData" Pi value
Output:"B_h" host variable output of hipMemcpyAtoH API
is then validated with "hData"
*/
#if HT_AMD
TEMPLATE_TEST_CASE("Unit_hipMemcpyAtoH_multiDevice-PeerDeviceContext",
"[hipMemcpyAtoH]",
char, int, float) {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int peerAccess = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&peerAccess, 1, 0));
if (!peerAccess) {
SUCCEED("Skipped the test as there is no peer access");
} else {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipDeviceSynchronize());
// Changing the device context
HIP_CHECK(hipSetDevice(1));
// Performing API call
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, copy_bytes*sizeof(TestType))
== hipSuccess);
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr,
hData, B_h,
nullptr, false) == true);
}
} else {
SUCCEED("skipping the testcases as numDevices < 2");
}
}
#endif
/*
This testcase verifies the negative scenarios of hipMemcpyAtoH API
*/
TEST_CASE("Unit_hipMemcpyAtoH_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Destination pointer is nullptr") {
REQUIRE(hipMemcpyAtoH(nullptr, A_d, 0, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("Source offset is more than allocated size") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 100, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("ByteCount is greater than allocated size") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, 12*sizeof(float)) != hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
/*
This testcase verifies size 0 check of hipMemcpyAtoH API
Excluded the testcase for amd,as there is already a bug raised
SWDEV-274683
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipMemcpyAtoH_SizeCheck") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr}, *def_data{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &def_data, nullptr, NUM_W);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
HipTest::setDefaultData<float>(NUM_W, nullptr, def_data, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Passing 0 to copy bytes") {
REQUIRE(hipMemcpyAtoH(B_h, A_d, 0, 0) == hipSuccess);
REQUIRE(HipTest::checkArray(B_h, def_data, NUM_W, NUM_H) == true);
}
SECTION(" Source Array is nullptr") {
REQUIRE(hipMemcpyAtoH(B_h, nullptr, 0, copy_bytes*sizeof(float))
!= hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
def_data, false) == true);
}
#endif
+83 -185
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,171 +16,41 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Test Scenarios:
* 1. Perform simple and pinned host memory of hipMemcpyHtoA API
* 2. Allocate Memory from one GPU device and call hipMemcpyHtoA from Peer
* GPU device
* 3. Perform hipMemcpyHtoA Negative Scenarios
* 4. Perform bytecount 0 validation for hipMemcpyHtoA API
Testcase Scenarios :
Unit_hipMemcpyHtoA_Positive_Default - Test basic memcpy between host and 1D
array with hipMemcpyHtoA api
Unit_hipMemcpyHtoA_Positive_Synchronization_Behavior - Test synchronization
behavior for hipMemcpyHtoA api Unit_hipMemcpyHtoA_Positive_ZeroCount - Test that
no data is copied when allocation_size is set to 0
Unit_hipMemcpyHtoA_Negative_Parameters - Test unsuccessful execution of
hipMemcpyHtoA api when parameters are invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <resource_guards.hh>
#include <utils.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{1};
static constexpr auto copy_bytes{2};
TEST_CASE("Unit_hipMemcpyHtoA_Positive_Default") {
using namespace std::placeholders;
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyHtoA API
Input: "B_h" which is initialized with 1.6
Output: "A_d" output of hipMemcpyHtoA is copied to "hData" host variable
validated the result with "B_h"
const auto width = GENERATE(512, 1024, 2048);
const auto allocation_size = width * sizeof(int);
The same scenario is then verified with pinned host memory
*/
TEMPLATE_TEST_CASE("Unit_hipMemcpyHtoA_Basic", "[hipMemcpyHtoA]",
char, int, float) {
HIP_CHECK(hipSetDevice(0));
auto memtype_check = GENERATE(0, 1);
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
if (memtype_check) {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W, true);
} else {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
}
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Performing API call
HIP_CHECK(hipMemcpyHtoA(A_d, 0, B_h, copy_bytes*sizeof(TestType)));
HIP_CHECK(hipMemcpy2DFromArray(hData, sizeof(TestType)*NUM_W, A_d,
0, 0, sizeof(TestType)*NUM_W, 1, hipMemcpyDeviceToHost));
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
if (memtype_check) {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, true) == true);
} else {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
MemcpyHtoAShell<false, int>(std::bind(hipMemcpyHtoA, _1, 0, _2, allocation_size), width);
}
TEST_CASE("Unit_hipMemcpyHtoA_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
/*
This testcase performs the peer device context scenario
of hipMemcpyHtoA API
Memory is allocated in GPU-0 and the API is triggered from GPU-1
Input: "B_h" which is initialized with 1.6
Output: "A_d" output of hipMemcpyHtoA is copied to "hData" host variable
validated the result with "B_h"
*/
#if HT_AMD
TEMPLATE_TEST_CASE("Unit_hipMemcpyHtoA_multiDevice-PeerDeviceContext",
"[hipMemcpyHtoA]",
char, int, float) {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int peerAccess = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&peerAccess, 1, 0));
if (!peerAccess) {
SUCCEED("Skipped the test as there is no peer access");
} else {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
const auto width = GENERATE(512, 1024, 2048);
const auto height = 0;
const auto allocation_size = width * sizeof(int);
// Initialization of data
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Changing the device context
HIP_CHECK(hipSetDevice(1));
// Performing API call
HIP_CHECK(hipMemcpyHtoA(A_d, 0, B_h, copy_bytes*sizeof(TestType)));
HIP_CHECK(hipMemcpy2DFromArray(hData, sizeof(TestType)*NUM_W, A_d,
0, 0, sizeof(TestType)*NUM_W, 1,
hipMemcpyDeviceToHost));
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr,
hData, B_h,
nullptr, false) == true);
}
} else {
SUCCEED("skipping the testcases as numDevices < 2");
}
}
#endif
/*
This testcase verifies the negative scenarios of hipMemcpyHtoA API
*/
TEST_CASE("Unit_hipMemcpyHtoA_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Source pointer is nullptr") {
REQUIRE(hipMemcpyHtoA(A_d, 0, nullptr, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("Source offset is more than allocated size") {
REQUIRE(hipMemcpyHtoA(A_d, 100, B_h, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("ByteCount is greater than allocated size") {
REQUIRE(hipMemcpyHtoA(A_d, 0, B_h, 12*sizeof(float)) != hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
MemcpyHtoASyncBehavior(std::bind(hipMemcpyHtoA, _1, 0, _2, allocation_size), width, height, true);
}
/*
@@ -189,41 +59,69 @@ This is excluded for AMD as we have a bug already raised
SWDEV-274683
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipMemcpyHtoA_SizeCheck") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr}, *def_data{nullptr};
size_t width{NUM_W * sizeof(float)};
TEST_CASE("Unit_hipMemcpyHtoA_Positive_ZeroCount") {
const auto width = 1024;
const auto height = 0;
const auto allocation_size = width * sizeof(int);
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &def_data, nullptr, NUM_W);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
HipTest::setDefaultData<float>(NUM_W, nullptr, def_data, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
const unsigned int flag = hipArrayDefault;
SECTION("Passing 0 to copy bytes") {
REQUIRE(hipMemcpyHtoA(A_d, 0, B_h, 0) == hipSuccess);
HIP_CHECK(hipMemcpy2DFromArray(def_data, sizeof(float)*NUM_W, A_d,
0, 0, sizeof(float)*NUM_W, 1,
hipMemcpyDeviceToHost));
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<uint8_t> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
REQUIRE(HipTest::checkArray(hData, def_data, NUM_W, NUM_H) == true);
}
int fill_value = 42;
std::fill_n(host_alloc.host_ptr(), width, fill_value);
HIP_CHECK(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.host_ptr(), sizeof(int) * width,
sizeof(int) * width, 1, hipMemcpyHostToDevice));
fill_value = 41;
std::fill_n(host_alloc.host_ptr(), width, fill_value);
HIP_CHECK(hipMemcpyHtoA(array_alloc.ptr(), 0, host_alloc.ptr(), 0));
SECTION(" Source Array is nullptr") {
REQUIRE(hipMemcpyHtoA(nullptr, 0, B_h, copy_bytes*sizeof(float))
!= hipSuccess);
}
HIP_CHECK(hipMemcpy2DFromArray(host_alloc.host_ptr(), sizeof(int) * width, array_alloc.ptr(), 0,
0, sizeof(int) * width, 1, hipMemcpyDeviceToHost));
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
def_data, false) == true);
ArrayFindIfNot(host_alloc.host_ptr(), static_cast<uint8_t>(42), width);
}
#endif
TEST_CASE("Unit_hipMemcpyHtoA_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 1024;
const auto height = 0;
const auto allocation_size = width * sizeof(int);
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpyHtoA(nullptr, 0, host_alloc.ptr(), allocation_size),
hipErrorInvalidValue);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpyHtoA(array_alloc.ptr(), 0, nullptr, allocation_size),
hipErrorInvalidValue);
}
SECTION("Offset is greater than allocated size") {
HIP_CHECK_ERROR(
hipMemcpyHtoA(array_alloc.ptr(), allocation_size + 10, host_alloc.ptr(), allocation_size),
hipErrorInvalidValue);
}
SECTION("Count is greater than allocated size") {
HIP_CHECK_ERROR(hipMemcpyHtoA(array_alloc.ptr(), 0, host_alloc.ptr(), allocation_size + 10),
hipErrorInvalidValue);
}
SECTION("2D array is allocated") {
const auto width_2d = 32;
const auto height_2d = width_2d;
const auto allocation_size_2d = width_2d * height_2d * sizeof(int);
ArrayAllocGuard<int> array_alloc_2d(make_hipExtent(width_2d, height_2d, 0), flag);
LinearAllocGuard<int> host_alloc_2d(LinearAllocs::hipHostMalloc, allocation_size_2d);
HIP_CHECK_ERROR(hipMemcpyHtoA(array_alloc_2d.ptr(), 0, host_alloc_2d.ptr(), allocation_size_2d),
hipErrorInvalidValue);
}
}
+229
Просмотреть файл
@@ -0,0 +1,229 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Test Scenarios:
* 1. Perform simple and pinned host memory of hipMemcpyHtoA API
* 2. Allocate Memory from one GPU device and call hipMemcpyHtoA from Peer
* GPU device
* 3. Perform hipMemcpyHtoA Negative Scenarios
* 4. Perform bytecount 0 validation for hipMemcpyHtoA API
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{1};
static constexpr auto copy_bytes{2};
/*
This testcase performs the basic and pinned host memory scenarios
of hipMemcpyHtoA API
Input: "B_h" which is initialized with 1.6
Output: "A_d" output of hipMemcpyHtoA is copied to "hData" host variable
validated the result with "B_h"
The same scenario is then verified with pinned host memory
*/
TEMPLATE_TEST_CASE("Unit_hipMemcpyHtoA_Basic", "[hipMemcpyHtoA]",
char, int, float) {
HIP_CHECK(hipSetDevice(0));
auto memtype_check = GENERATE(0, 1);
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
if (memtype_check) {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W, true);
} else {
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
}
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Performing API call
HIP_CHECK(hipMemcpyHtoA(A_d, 0, B_h, copy_bytes*sizeof(TestType)));
HIP_CHECK(hipMemcpy2DFromArray(hData, sizeof(TestType)*NUM_W, A_d,
0, 0, sizeof(TestType)*NUM_W, 1, hipMemcpyDeviceToHost));
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
if (memtype_check) {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, true) == true);
} else {
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
}
/*
This testcase performs the peer device context scenario
of hipMemcpyHtoA API
Memory is allocated in GPU-0 and the API is triggered from GPU-1
Input: "B_h" which is initialized with 1.6
Output: "A_d" output of hipMemcpyHtoA is copied to "hData" host variable
validated the result with "B_h"
*/
#if HT_AMD
TEMPLATE_TEST_CASE("Unit_hipMemcpyHtoA_multiDevice-PeerDeviceContext",
"[hipMemcpyHtoA]",
char, int, float) {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int peerAccess = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&peerAccess, 1, 0));
if (!peerAccess) {
SUCCEED("Skipped the test as there is no peer access");
} else {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
TestType *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(TestType)};
// Initialization of data
HipTest::initArrays<TestType>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<TestType>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
// Changing the device context
HIP_CHECK(hipSetDevice(1));
// Performing API call
HIP_CHECK(hipMemcpyHtoA(A_d, 0, B_h, copy_bytes*sizeof(TestType)));
HIP_CHECK(hipMemcpy2DFromArray(hData, sizeof(TestType)*NUM_W, A_d,
0, 0, sizeof(TestType)*NUM_W, 1,
hipMemcpyDeviceToHost));
// Validating the result
REQUIRE(HipTest::checkArray(B_h, hData, copy_bytes, NUM_H) == true);
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<TestType>(nullptr, nullptr, nullptr,
hData, B_h,
nullptr, false) == true);
}
} else {
SUCCEED("skipping the testcases as numDevices < 2");
}
}
#endif
/*
This testcase verifies the negative scenarios of hipMemcpyHtoA API
*/
TEST_CASE("Unit_hipMemcpyHtoA_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Source pointer is nullptr") {
REQUIRE(hipMemcpyHtoA(A_d, 0, nullptr, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("Source offset is more than allocated size") {
REQUIRE(hipMemcpyHtoA(A_d, 100, B_h, copy_bytes*sizeof(float))
!= hipSuccess);
}
SECTION("ByteCount is greater than allocated size") {
REQUIRE(hipMemcpyHtoA(A_d, 0, B_h, 12*sizeof(float)) != hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
nullptr, false) == true);
}
/*
This testcase verifies the size 0 check of hipMemcpyHtoA API
This is excluded for AMD as we have a bug already raised
SWDEV-274683
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipMemcpyHtoA_SizeCheck") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d;
float *hData{nullptr}, *B_h{nullptr}, *def_data{nullptr};
size_t width{NUM_W * sizeof(float)};
// Initialization of data
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
nullptr, &def_data, nullptr, NUM_W);
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&hData, &B_h, nullptr, NUM_W);
HipTest::setDefaultData<float>(NUM_W, hData, B_h, nullptr);
HipTest::setDefaultData<float>(NUM_W, nullptr, def_data, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H, hipMemcpyHostToDevice));
SECTION("Passing 0 to copy bytes") {
REQUIRE(hipMemcpyHtoA(A_d, 0, B_h, 0) == hipSuccess);
HIP_CHECK(hipMemcpy2DFromArray(def_data, sizeof(float)*NUM_W, A_d,
0, 0, sizeof(float)*NUM_W, 1,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, def_data, NUM_W, NUM_H) == true);
}
SECTION(" Source Array is nullptr") {
REQUIRE(hipMemcpyHtoA(nullptr, 0, B_h, copy_bytes*sizeof(float))
!= hipSuccess);
}
// DeAllocating the memory
HIP_CHECK(hipFreeArray(A_d));
REQUIRE(HipTest::freeArrays<float>(nullptr, nullptr, nullptr, hData, B_h,
def_data, false) == true);
}
#endif
+179 -121
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,143 +16,201 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Testcase Scenarios :
Unit_hipMemcpyPeer_Positive_Default - Test basic P2P memcpy between two devices
with hipMemcpyPeer api Unit_hipMemcpyPeer_Positive_Synchronization_Behavior -
Test synchronization behavior for hipMemcpyPeer api
Unit_hipMemcpyPeer_Positive_ZeroSize - Test that no data is copied when
sizeBytes is set to 0 Unit_hipMemcpyPeer_Negative_Parameters - Test unsuccessful
execution of hipMemcpyPeer api when parameters are invalid
*/
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
/*
This testfile verifies the following scenarios of hipMemcpyPeer API
1. Negative Scenarios
2. Basic scenario of hipMemcpyPeer API
*/
#include <resource_guards.hh>
#include <utils.hh>
/*This testcase verifies the negative scenarios of hipmemcpypeer
*/
TEST_CASE("Unit_hipMemcpyPeer_Negative") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of variables
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(nullptr, &B_d, nullptr,
nullptr, nullptr, nullptr, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
SECTION("Nullptr to Destination Pointer") {
REQUIRE(hipMemcpyPeer(nullptr, 1, A_d, 0, copy_bytes) != hipSuccess);
}
TEST_CASE("Unit_hipMemcpyPeer_Positive_Default") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
SECTION("Nullptr to Source Pointer") {
REQUIRE(hipMemcpyPeer(B_d, 1, nullptr, 0, copy_bytes) != hipSuccess);
}
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
SECTION("Pass NumElements as 0") {
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpyPeer(B_d, 1, A_d, 0, 0));
HIP_CHECK(hipMemcpy(A_h, B_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkTest<int>(A_h, B_h, numElements);
}
int can_access_peer = 0;
const auto src_device = GENERATE(range(0, HipTest::getDeviceCount()));
const auto dst_device = GENERATE(range(0, HipTest::getDeviceCount()));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
SECTION("Passing more than allocated size") {
REQUIRE(hipMemcpyPeer(B_d, 1, A_d, 0,
((numElements+40)*sizeof(int))) != hipSuccess);
}
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
SECTION("Passing invalid Destination device ID") {
REQUIRE(hipMemcpyPeer(B_d, numDevices, A_d, 0, copy_bytes) !=
hipSuccess);
}
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, allocation_size);
LinearAllocGuard<int> result(LinearAllocs::hipHostMalloc, allocation_size);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, allocation_size);
SECTION("Passing invalid Source device ID") {
REQUIRE(hipMemcpyPeer(B_d, 1, A_d, numDevices, copy_bytes) !=
hipSuccess);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
const auto element_count = allocation_size / sizeof(*src_alloc.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int expected_value = 22;
HIP_CHECK(hipSetDevice(src_device));
VectorSet<<<block_count, thread_count, 0>>>(src_alloc.ptr(), expected_value, element_count);
HIP_CHECK(hipGetLastError());
HIP_CHECK(
hipMemcpyPeer(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device, allocation_size));
HIP_CHECK(
hipMemcpy(result.host_ptr(), dst_alloc.ptr(), allocation_size, hipMemcpyDeviceToHost));
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
ArrayFindIfNot(result.host_ptr(), expected_value, element_count);
} else {
SUCCEED("Number of devices are < 2");
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
/*
* This test case verifies the basic scenario of hipMemcpyPeer API
* Initializes data in GPU-0
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeer API
* Then performs the addition and validates the sum
*/
TEST_CASE("Unit_hipMemcpyPeer_Basic") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
TEST_CASE("Unit_hipMemcpyPeer_Positive_Synchronization_Behavior") {
HIP_CHECK(hipDeviceSynchronize());
// Initialization of Variables on GPU-0
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
// Initialization of Variables on GPU-1
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
// Launching kernel and performing vector addition on GPU-0
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
HIP_CHECK(hipSetDevice(1));
// Copying data from GPU-0 to GPU-1 and performing vector addition
HIP_CHECK(hipMemcpyPeer(X_d, 1, A_d, 0, copy_bytes));
HIP_CHECK(hipMemcpyPeer(Y_d, 1, B_d, 0, copy_bytes));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
// Cleaning the memory
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
HIP_CHECK(hipSetDevice(src_device));
LaunchDelayKernel(std::chrono::milliseconds{100}, nullptr);
HIP_CHECK(hipMemcpyPeer(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device, kPageSize));
HIP_CHECK_ERROR(hipStreamQuery(nullptr), hipErrorNotReady);
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
} else {
SUCCEED("Number of devices are < 2");
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
TEST_CASE("Unit_hipMemcpyPeer_Positive_ZeroSize") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
const auto allocation_size = kPageSize;
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, allocation_size);
LinearAllocGuard<int> result(LinearAllocs::hipHostMalloc, allocation_size,
hipHostMallocPortable);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, allocation_size);
const auto element_count = allocation_size / sizeof(*src_alloc.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int set_value = 22;
HIP_CHECK(hipSetDevice(src_device));
VectorSet<<<block_count, thread_count, 0>>>(src_alloc.ptr(), set_value, element_count);
HIP_CHECK(hipGetLastError());
constexpr int expected_value = 21;
std::fill_n(src_alloc.host_ptr(), element_count, expected_value);
HIP_CHECK(hipMemcpyPeer(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device, 0));
HIP_CHECK(
hipMemcpy(result.host_ptr(), dst_alloc.ptr(), allocation_size, hipMemcpyDeviceToHost));
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
ArrayFindIfNot(result.host_ptr(), expected_value, element_count);
} else {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
TEST_CASE("Unit_hipMemcpyPeer_Negative_Parameters") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(src_device));
SECTION("Nullptr to Destination Pointer") {
HIP_CHECK_ERROR(hipMemcpyPeer(nullptr, dst_device, src_alloc.ptr(), src_device, kPageSize),
hipErrorInvalidValue);
}
SECTION("Nullptr to Source Pointer") {
HIP_CHECK_ERROR(hipMemcpyPeer(dst_alloc.ptr(), dst_device, nullptr, src_device, kPageSize),
hipErrorInvalidValue);
}
SECTION("Passing more than allocated size") {
HIP_CHECK_ERROR(
hipMemcpyPeer(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device, kPageSize + 1),
hipErrorInvalidValue);
}
SECTION("Passing invalid Destination device ID") {
HIP_CHECK_ERROR(
hipMemcpyPeer(dst_alloc.ptr(), device_count, src_alloc.ptr(), src_device, kPageSize),
hipErrorInvalidDevice);
}
SECTION("Passing invalid Source device ID") {
HIP_CHECK_ERROR(
hipMemcpyPeer(dst_alloc.ptr(), dst_device, src_alloc.ptr(), device_count, kPageSize),
hipErrorInvalidDevice);
}
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
} else {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
+209 -220
Просмотреть файл
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,247 +16,236 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This testfile verifies the following scenarios of hipMemcpyPeerAsync API
1. Negative Scenarios
2. Memory on one GPU and stream created on another GPU
3. Basic scenario of hipMemcpyPeerAsync API
Testcase Scenarios :
Unit_hipMemcpyPeerAsync_Positive_Default - Test basic P2P async memcpy between
two devices with hipMemcpyPeerAsync api
Unit_hipMemcpyPeerAsync_Positive_Synchronization_Behavior - Test synchronization
behavior for hipMemcpyPeerAsync api Unit_hipMemcpyPeerAsync_Positive_ZeroSize -
Test that no data is copied when sizeBytes is set to 0
Unit_hipMemcpyPeerAsync_Negative_Parameters - Test unsuccessful execution of
hipMemcpyPeerAsync api when parameters are invalid
*/
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
#include <iostream>
#include <resource_guards.hh>
#include <utils.hh>
/*This testcase verifies the negative scenarios of hipmemcpypeerAsync
*/
TEST_CASE("Unit_hipMemcpyPeerAsync_Negative") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of variables
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&stream));
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(nullptr, &B_d, nullptr,
nullptr, nullptr, nullptr, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
SECTION("Nullptr to Destination Pointer") {
REQUIRE(hipMemcpyPeerAsync(nullptr, 1, A_d, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Nullptr to Source Pointer") {
REQUIRE(hipMemcpyPeerAsync(B_d, 1, nullptr, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Pass NumElements as 0") {
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpyPeerAsync(B_d, 1, A_d, 0, 0,
stream));
HIP_CHECK(hipMemcpy(A_h, B_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkTest<int>(A_h, B_h, numElements);
}
SECTION("Passing more than allocated size") {
REQUIRE(hipMemcpyPeerAsync(B_d, 1, A_d, 0,
100*sizeof(int), stream) != hipSuccess);
}
SECTION("Passing invalid Destination device ID") {
REQUIRE(hipMemcpyPeerAsync(B_d, numDevices, A_d, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Passing invalid Source device ID") {
REQUIRE(hipMemcpyPeerAsync(B_d, 0, A_d, numDevices, copy_bytes,
stream) != hipSuccess);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
TEST_CASE("Unit_hipMemcpyPeerAsync_Positive_Default") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
}
/*
* This test case verifies the basic scenario of hipMemcpyPeer API
* Initializes data in GPU-0
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeerAsync API
* Then performs the addition and validates the sum
*/
const auto stream_type = GENERATE(Streams::nullstream, Streams::perThread, Streams::created);
const StreamGuard stream_guard(stream_type);
const hipStream_t stream = stream_guard.stream();
TEST_CASE("Unit_hipMemcpyPeerAsync_Basic") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of Variables on GPU-0
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipStreamCreate(&stream));
int can_access_peer = 0;
// Initialization of Variables in GPU-1
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
const auto src_device = GENERATE(range(0, HipTest::getDeviceCount()));
const auto dst_device = GENERATE(range(0, HipTest::getDeviceCount()));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
// Launching kernel and performing vector addition in GPU-0
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
// Copying data from GPU-0 to GPU-1 and performing vector addition
HIP_CHECK(hipSetDevice(1));
SECTION("Calling hipMemcpyPerAsync() using user defined stream obj") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpyPerAsync() using hipStreamPerThread") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, allocation_size);
LinearAllocGuard<int> result(LinearAllocs::hipHostMalloc, allocation_size,
hipHostMallocPortable);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, allocation_size);
// Cleaning the Memory
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
const auto element_count = allocation_size / sizeof(*src_alloc.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int expected_value = 22;
HIP_CHECK(hipSetDevice(src_device));
VectorSet<<<block_count, thread_count, 0, stream>>>(src_alloc.ptr(), expected_value,
element_count);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device,
allocation_size, stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(
hipMemcpy(result.host_ptr(), dst_alloc.ptr(), allocation_size, hipMemcpyDeviceToHost));
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
ArrayFindIfNot(result.host_ptr(), expected_value, element_count);
} else {
SUCCEED("Number of devices are < 2");
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
/*
* This test case verifies the following functionality where
Memory is allocated in One GPU and
stream created on another GPU
* Initializes all the data in GPU-0
* Creating stream in GPU-1
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeerAsync API
* where stream is created in GPU-1
* Then performs the addition and validates the sum
*/
TEST_CASE("Unit_hipMemcpyPeerAsync_StreamOnDiffDevice") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
TEST_CASE("Unit_hipMemcpyPeerAsync_Positive_Synchronization_Behavior") {
HIP_CHECK(hipDeviceSynchronize());
// Initialization of all variables in GPU-0
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
// Stream created in GPU-1
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
const StreamGuard stream_guard(Streams::created);
const hipStream_t stream = stream_guard.stream();
// Performing vector addition and validate the data
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
// Copying the data from GPU-0 to GPU-1 where stream is from diff device
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
// Cleaning the data
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(src_device));
LaunchDelayKernel(std::chrono::milliseconds{100}, nullptr);
HIP_CHECK(hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device,
kPageSize, stream));
HIP_CHECK_ERROR(hipStreamQuery(nullptr), hipErrorNotReady);
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
} else {
SUCCEED("Number of devices are < 2");
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
TEST_CASE("Unit_hipMemcpyPeerAsync_Positive_ZeroSize") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
const StreamGuard stream_guard(Streams::created);
const hipStream_t stream = stream_guard.stream();
const auto allocation_size = kPageSize;
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, allocation_size);
LinearAllocGuard<int> result(LinearAllocs::hipHostMalloc, allocation_size,
hipHostMallocPortable);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, allocation_size);
const auto element_count = allocation_size / sizeof(*src_alloc.ptr());
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int set_value = 22;
HIP_CHECK(hipSetDevice(src_device));
VectorSet<<<block_count, thread_count, 0, stream>>>(src_alloc.ptr(), set_value, element_count);
HIP_CHECK(hipGetLastError());
constexpr int expected_value = 21;
std::fill_n(src_alloc.host_ptr(), element_count, expected_value);
HIP_CHECK(
hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device, 0, stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(
hipMemcpy(result.host_ptr(), dst_alloc.ptr(), allocation_size, hipMemcpyDeviceToHost));
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
ArrayFindIfNot(result.host_ptr(), expected_value, element_count);
} else {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
TEST_CASE("Unit_hipMemcpyPeerAsync_Negative_Parameters") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
const StreamGuard stream_guard(Streams::created);
const hipStream_t stream = stream_guard.stream();
constexpr auto InvalidStream = [] {
StreamGuard sg(Streams::created);
return sg.stream();
};
int can_access_peer = 0;
const auto src_device = 0;
const auto dst_device = 1;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
HIP_CHECK(hipDeviceEnablePeerAccess(dst_device, 0));
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(dst_device));
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
HIP_CHECK(hipSetDevice(src_device));
SECTION("Nullptr to Destination Pointer") {
HIP_CHECK_ERROR(
hipMemcpyPeerAsync(nullptr, dst_device, src_alloc.ptr(), src_device, kPageSize, stream),
hipErrorInvalidValue);
}
SECTION("Nullptr to Source Pointer") {
HIP_CHECK_ERROR(
hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, nullptr, src_device, kPageSize, stream),
hipErrorInvalidValue);
}
SECTION("Passing more than allocated size") {
HIP_CHECK_ERROR(hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device,
kPageSize + 1, stream),
hipErrorInvalidValue);
}
SECTION("Passing invalid Destination device ID") {
HIP_CHECK_ERROR(hipMemcpyPeerAsync(dst_alloc.ptr(), device_count, src_alloc.ptr(), src_device,
kPageSize, stream),
hipErrorInvalidDevice);
}
SECTION("Passing invalid Source device ID") {
HIP_CHECK_ERROR(hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), device_count,
kPageSize, stream),
hipErrorInvalidDevice);
}
SECTION("Passing invalid Stream") {
HIP_CHECK_ERROR(hipMemcpyPeerAsync(dst_alloc.ptr(), dst_device, src_alloc.ptr(), src_device,
kPageSize, InvalidStream()),
hipErrorContextIsDestroyed);
}
HIP_CHECK(hipDeviceDisablePeerAccess(dst_device));
} else {
INFO("Peer access cannot be enabled between devices " << src_device << " " << dst_device);
}
}
+262
Просмотреть файл
@@ -0,0 +1,262 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This testfile verifies the following scenarios of hipMemcpyPeerAsync API
1. Negative Scenarios
2. Memory on one GPU and stream created on another GPU
3. Basic scenario of hipMemcpyPeerAsync API
*/
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
#include <iostream>
/*This testcase verifies the negative scenarios of hipmemcpypeerAsync
*/
TEST_CASE("Unit_hipMemcpyPeerAsync_Negative") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of variables
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&stream));
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(nullptr, &B_d, nullptr,
nullptr, nullptr, nullptr, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
SECTION("Nullptr to Destination Pointer") {
REQUIRE(hipMemcpyPeerAsync(nullptr, 1, A_d, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Nullptr to Source Pointer") {
REQUIRE(hipMemcpyPeerAsync(B_d, 1, nullptr, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Pass NumElements as 0") {
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpyPeerAsync(B_d, 1, A_d, 0, 0,
stream));
HIP_CHECK(hipMemcpy(A_h, B_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkTest<int>(A_h, B_h, numElements);
}
SECTION("Passing more than allocated size") {
REQUIRE(hipMemcpyPeerAsync(B_d, 1, A_d, 0,
100*sizeof(int), stream) != hipSuccess);
}
SECTION("Passing invalid Destination device ID") {
REQUIRE(hipMemcpyPeerAsync(B_d, numDevices, A_d, 0, copy_bytes,
stream) != hipSuccess);
}
SECTION("Passing invalid Source device ID") {
REQUIRE(hipMemcpyPeerAsync(B_d, 0, A_d, numDevices, copy_bytes,
stream) != hipSuccess);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This test case verifies the basic scenario of hipMemcpyPeer API
* Initializes data in GPU-0
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeerAsync API
* Then performs the addition and validates the sum
*/
TEST_CASE("Unit_hipMemcpyPeerAsync_Basic") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of Variables on GPU-0
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipStreamCreate(&stream));
// Initialization of Variables in GPU-1
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
// Launching kernel and performing vector addition in GPU-0
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
// Copying data from GPU-0 to GPU-1 and performing vector addition
HIP_CHECK(hipSetDevice(1));
SECTION("Calling hipMemcpyPerAsync() using user defined stream obj") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpyPerAsync() using hipStreamPerThread") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
// Cleaning the Memory
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This test case verifies the following functionality where
Memory is allocated in One GPU and
stream created on another GPU
* Initializes all the data in GPU-0
* Creating stream in GPU-1
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeerAsync API
* where stream is created in GPU-1
* Then performs the addition and validates the sum
*/
TEST_CASE("Unit_hipMemcpyPeerAsync_StreamOnDiffDevice") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
hipStream_t stream;
HIP_CHECK(hipSetDevice(0));
// Initialization of all variables in GPU-0
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
// Stream created in GPU-1
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipStreamCreate(&stream));
// Performing vector addition and validate the data
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
// Copying the data from GPU-0 to GPU-1 where stream is from diff device
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
// Cleaning the data
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
HIP_CHECK(hipStreamDestroy(stream));
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
+158
Просмотреть файл
@@ -0,0 +1,158 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
/*
This testfile verifies the following scenarios of hipMemcpyPeer API
1. Negative Scenarios
2. Basic scenario of hipMemcpyPeer API
*/
/*This testcase verifies the negative scenarios of hipmemcpypeer
*/
TEST_CASE("Unit_hipMemcpyPeer_Negative") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
// Initialization of variables
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, numElements*sizeof(int));
HipTest::setDefaultData<int>(numElements, A_h, B_h, nullptr);
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(nullptr, &B_d, nullptr,
nullptr, nullptr, nullptr, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
SECTION("Nullptr to Destination Pointer") {
REQUIRE(hipMemcpyPeer(nullptr, 1, A_d, 0, copy_bytes) != hipSuccess);
}
SECTION("Nullptr to Source Pointer") {
REQUIRE(hipMemcpyPeer(B_d, 1, nullptr, 0, copy_bytes) != hipSuccess);
}
SECTION("Pass NumElements as 0") {
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpyPeer(B_d, 1, A_d, 0, 0));
HIP_CHECK(hipMemcpy(A_h, B_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkTest<int>(A_h, B_h, numElements);
}
SECTION("Passing more than allocated size") {
REQUIRE(hipMemcpyPeer(B_d, 1, A_d, 0,
((numElements+40)*sizeof(int))) != hipSuccess);
}
SECTION("Passing invalid Destination device ID") {
REQUIRE(hipMemcpyPeer(B_d, numDevices, A_d, 0, copy_bytes) !=
hipSuccess);
}
SECTION("Passing invalid Source device ID") {
REQUIRE(hipMemcpyPeer(B_d, 1, A_d, numDevices, copy_bytes) !=
hipSuccess);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This test case verifies the basic scenario of hipMemcpyPeer API
* Initializes data in GPU-0
* Launches the kernel and performs addition in GPU-0
* Copies the data from GPU-0 to GPU-1 using hipMemcpyPeer API
* Then performs the addition and validates the sum
*/
TEST_CASE("Unit_hipMemcpyPeer_Basic") {
constexpr auto numElements{10};
constexpr auto copy_bytes{numElements*sizeof(int)};
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *X_d{nullptr}, *Y_d{nullptr}, *Z_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
// Initialization of Variables on GPU-0
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
&A_h, &B_h, &C_h, numElements*sizeof(int));
HIP_CHECK(hipMemcpy(A_d, A_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy(B_d, B_h, numElements*sizeof(int),
hipMemcpyHostToDevice));
// Initialization of Variables on GPU-1
HIP_CHECK(hipSetDevice(1));
HipTest::initArrays<int>(&X_d, &Y_d, &Z_d, nullptr,
nullptr, nullptr, numElements*sizeof(int));
// Launching kernel and performing vector addition on GPU-0
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, C_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
HIP_CHECK(hipSetDevice(1));
// Copying data from GPU-0 to GPU-1 and performing vector addition
HIP_CHECK(hipMemcpyPeer(X_d, 1, A_d, 0, copy_bytes));
HIP_CHECK(hipMemcpyPeer(Y_d, 1, B_d, 0, copy_bytes));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipMemcpy(C_h, Z_d, numElements*sizeof(int),
hipMemcpyDeviceToHost));
HipTest::checkVectorADD<int>(A_h, B_h, C_h, numElements);
// Cleaning the memory
HipTest::freeArrays<int>(A_d, B_d, C_d, A_h, B_h, C_h, false);
HipTest::freeArrays<int>(X_d, Y_d, Z_d, nullptr, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
}
} else {
SUCCEED("Number of devices are < 2");
}
}
+72 -557
Просмотреть файл
@@ -1,13 +1,15 @@
/*
Copyright (c) 2021-22-present Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -17,570 +19,83 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Different test for checking functionality of
* hipError_t hipMemcpyWithStream(void* dst, const void* src, size_t sizeBytes,hipMemcpyKind kind,
* hipStream_t stream);
*/
/*
This testfile verifies the following scenarios
1. hipMemcpyWithStream with one stream
2. hipMemcpyWithStream with two streams
3. Multi GPU and single stream
4. hipMemcpyWithStream API with testkind DtoH
5. hipMemcpyWithStream API with testkind DtoD
6. hipMemcpyWithStream API with testkind HtoH
7. hipMemcpyWithStream API with testkind TestkindDefault
8. hipMemcpyWithStream API with testkind TestkindDefaultForDtoD
9. hipMemcpyWithStream API DtoD on same device
*/
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
#include <hip/hip_runtime_api.h>
#include <memcpy1d_tests_common.hh>
#include <resource_guards.hh>
#include <utils.hh>
#include<vector>
#include<thread>
#include<chrono>
TEST_CASE("Unit_hipMemcpy_Positive_Basic") { MemcpyWithDirectionCommonTests<false>(hipMemcpy); }
#define LEN 64
#define SIZE LEN << 2
#define THREADS 2
#define MAX_THREADS 16
TEST_CASE("Unit_hipMemcpy_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
static constexpr size_t N{4 * 1024 * 1024};
static const auto MaxGPUDevices{256};
static constexpr unsigned blocksPerCU{6}; // to hide latency
static constexpr unsigned threadsPerBlock{256};
enum class ops
{ TestwithOnestream,
TestwithTwoStream,
TestOnMultiGPUwithOneStream,
TestkindDtoH,
TestkindDtoD,
TestkindHtoH,
TestkindDefault,
TestkindDefaultForDtoD,
TestDtoDonSameDevice,
END_OF_LIST
};
struct joinable_thread : std::thread {
template <class... Xs>
explicit joinable_thread(Xs&&... xs) : std::thread(std::forward<Xs>(xs)...)
{} // NOLINT
joinable_thread& operator=(joinable_thread&& other) = default;
joinable_thread(joinable_thread&& other) = default;
~joinable_thread() {
if (this->joinable())
this->join();
}
};
void TestwithOnestream(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes,
hipMemcpyHostToDevice, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestwithTwoStream(void) {
size_t Nbytes = N * sizeof(int);
const int NUM_STREAMS = 2;
int *A_d[NUM_STREAMS], *B_d[NUM_STREAMS], *C_d[NUM_STREAMS];
int *A_h[NUM_STREAMS], *B_h[NUM_STREAMS], *C_h[NUM_STREAMS];
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
for (int i=0; i < NUM_STREAMS; ++i) {
HipTest::initArrays(&A_d[i], &B_d[i], &C_d[i],
&A_h[i], &B_h[i], &C_h[i], N, false);
// For transfers from pageable host memory to device memory, a stream sync is performed before
// the copy is initiated. The function will return once the pageable buffer has been copied to
// the staging memory for DMA transfer to device memory, but the DMA to final destination may
// not have completed.
// For transfers from pinned host memory to device memory, the function is synchronous with
// respect to the host
SECTION("Host memory to device memory") {
MemcpyHtoDSyncBehavior(std::bind(hipMemcpy, _1, _2, _3, hipMemcpyHostToDevice), true);
}
hipStream_t stream[NUM_STREAMS];
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamCreate(&stream[i]));
// For transfers from device to either pageable or pinned host memory, the function returns only
// once the copy has completed
SECTION("Device memory to host memory") {
const auto f = std::bind(hipMemcpy, _1, _2, _3, hipMemcpyDeviceToHost);
MemcpyDtoHPageableSyncBehavior(f, true);
MemcpyDtoHPinnedSyncBehavior(f, true);
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
}
for (int i=0; i < NUM_STREAMS; ++i) {
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[i], B_h[i], C_h[i], N);
}
for (int i=0; i < NUM_STREAMS; ++i) {
HipTest::freeArrays(A_d[i], B_d[i], C_d[i], A_h[i], B_h[i], C_h[i], false);
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
void TestDtoDonSameDevice(void) {
size_t Nbytes = N * sizeof(int);
const int NUM_STREAMS = 2;
int *A_d[NUM_STREAMS], *B_d[NUM_STREAMS], *C_d[NUM_STREAMS];
int *A_h[NUM_STREAMS], *B_h[NUM_STREAMS], *C_h[NUM_STREAMS];
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
hipStream_t stream[NUM_STREAMS];
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMalloc(&A_d[1], Nbytes));
HIP_CHECK(hipMalloc(&B_d[1], Nbytes));
HIP_CHECK(hipMalloc(&C_d[1], Nbytes));
C_h[1] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[1] != NULL);
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(A_d[1], A_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[1]));
HIP_CHECK(hipMemcpyWithStream(B_d[1], B_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[1]));
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
if (A_d[1]) {
HIP_CHECK(hipFree(A_d[1]));
}
if (B_d[1]) {
HIP_CHECK(hipFree(B_d[1]));
}
if (C_d[1]) {
HIP_CHECK(hipFree(C_d[1]));
}
if (C_h[1]) {
free(C_h[1]);
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
void TestOnMultiGPUwithOneStream(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// If you have single GPU machine the return
if (NumDevices <= 1) {
SUCCEED("NumDevices <2");
} else {
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HipTest::initArrays(&A_d[i], &B_d[i], &C_d[i],
&A_h[i], &B_h[i], &C_h[i], N, false);
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock), 0, stream[i],
static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[i], B_h[i], C_h[i], N);
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HipTest::freeArrays(A_d[i], B_d[i], C_d[i],
A_h[i], B_h[i], C_h[i], false);
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindDtoH(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes,
hipMemcpyHostToDevice, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpyWithStream(C_h, C_d, Nbytes,
hipMemcpyDeviceToHost, stream));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestkindDtoD(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// If you have single GPU machine the return
if (NumDevices <= 1) {
SUCCEED("NumDevices are less than 2");
} else {
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
// Initialize and create the host and device elements for first device
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i))
HIP_CHECK(hipMalloc(&A_d[i], Nbytes));
HIP_CHECK(hipMalloc(&B_d[i], Nbytes));
HIP_CHECK(hipMalloc(&C_d[i], Nbytes));
C_h[i] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[i] != NULL);
}
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
// Copying device data from 1st GPU to the rest of the the GPUs that is
// NumDevices in the setup. 1st GPU start numbering from 0,1,2..n etc.
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[i]));
}
// Launching the kernel including the 1st GPU to the no of GPUs present
// in the setup. 1st GPU start numbering from 0,1,2..n etc.
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
HIP_CHECK(hipStreamDestroy(stream[0]));
for (int i=1; i < NumDevices; ++i) {
if (A_d[i]) {
HIP_CHECK(hipFree(A_d[i]));
}
if (B_d[i]) {
HIP_CHECK(hipFree(B_d[i]));
}
if (C_d[i]) {
HIP_CHECK(hipFree(C_d[i]));
}
if (C_h[i]) {
free(C_h[i]);
}
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindDefault(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes, hipMemcpyDefault, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes, hipMemcpyDefault, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpyWithStream(C_h, C_d, Nbytes, hipMemcpyDefault, stream));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestkindDefaultForDtoD(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// Test case will not run on single GPU setup.
if (NumDevices <= 1) {
SUCCEED("No of Devices < 2");
} else {
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
// Initialize and create the host and device elements for first device
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMalloc(&A_d[i], Nbytes));
HIP_CHECK(hipMalloc(&B_d[i], Nbytes));
HIP_CHECK(hipMalloc(&C_d[i], Nbytes));
C_h[i] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[i] != NULL);
}
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
// Copying device data from 1st GPU to the rest of the the GPUs
// using hipMemcpyDefault kind that is NumDevices in the setup.
// 1st GPU start numbering from 0,1,2..n etc.
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_d[0], Nbytes,
hipMemcpyDefault, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_d[0], Nbytes,
hipMemcpyDefault, stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i)); // hipMemcpy will be on this device
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
// Output of each GPU is getting validated with input of 1st GPU.
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
HIP_CHECK(hipStreamDestroy(stream[0]));
for (int i=1; i < NumDevices; ++i) {
if (A_d[i]) {
HIP_CHECK(hipFree(A_d[i]));
}
if (B_d[i]) {
HIP_CHECK(hipFree(B_d[i]));
}
if (C_d[i]) {
HIP_CHECK(hipFree(C_d[i]));
}
if (C_h[i]) {
free(C_h[i]);
}
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindHtoH(void) {
size_t Nbytes = N * sizeof(int);
int *A_h, *B_h;
// Allocate memory to A_h and B_h
A_h = static_cast<int*>(malloc(Nbytes));
HIP_ASSERT(A_h != NULL);
B_h = static_cast<int*>(malloc(Nbytes));
HIP_ASSERT(B_h != NULL);
for (size_t i = 0; i < N; ++i) {
if (A_h) {
(A_h)[i] = 3.146f + i; // Pi
}
}
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(B_h, A_h, Nbytes, hipMemcpyHostToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
for (size_t i = 0; i < N; i++) {
HIP_ASSERT(A_h[i] == B_h[i]);
}
if (A_h) {
free(A_h);
}
if (B_h) {
free(B_h);
}
HIP_CHECK(hipStreamDestroy(stream));
}
TEST_CASE("Unit_hipMemcpyWithStream_TestWithOneStream") {
TestwithOnestream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestwithTwoStream") {
TestwithTwoStream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDtoH") {
TestkindDtoH();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindHtoH") {
TestkindHtoH();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDtoD") {
TestkindDtoD();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestOnMultiGPUwithOneStream") {
TestOnMultiGPUwithOneStream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDefault") {
TestkindDefault();
}
#ifndef __HIP_PLATFORM_NVCC__
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDefaultForDtoD") {
TestkindDefaultForDtoD();
}
// For transfers from device memory to device memory, no host-side synchronization is performed.
SECTION("Device memory to device memory") {
// This behavior differs on NVIDIA and AMD, on AMD the hipMemcpy calls is synchronous with
// respect to the host
#if HT_AMD
HipTest::HIP_SKIP_TEST(
"EXSWCPHIPT-127 - Memcpy from device to device memory behavior differs on AMD and Nvidia");
return;
#endif
MemcpyDtoDSyncBehavior(std::bind(hipMemcpy, _1, _2, _3, hipMemcpyDeviceToDevice), false);
}
TEST_CASE("Unit_hipMemcpyWithStream_TestDtoDonSameDevice") {
TestDtoDonSameDevice();
// For transfers from any host memory to any host memory, the function is fully synchronous with
// respect to the host
SECTION("Host memory to host memory") {
MemcpyHtoHSyncBehavior(std::bind(hipMemcpy, _1, _2, _3, hipMemcpyHostToHost), true);
}
}
TEST_CASE("Unit_hipMemcpy_Negative_Parameters") {
using namespace std::placeholders;
SECTION("Host to device") {
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, kPageSize);
MemcpyWithDirectionCommonNegativeTests(hipMemcpy, device_alloc.ptr(), host_alloc.ptr(),
kPageSize, hipMemcpyHostToDevice);
}
SECTION("Device to host") {
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, kPageSize);
MemcpyWithDirectionCommonNegativeTests(hipMemcpy, host_alloc.ptr(), device_alloc.ptr(),
kPageSize, hipMemcpyDeviceToHost);
}
SECTION("Host to host") {
LinearAllocGuard<int> src_alloc(LinearAllocs::hipHostMalloc, kPageSize);
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipHostMalloc, kPageSize);
MemcpyWithDirectionCommonNegativeTests(hipMemcpy, dst_alloc.ptr(), src_alloc.ptr(), kPageSize,
hipMemcpyHostToHost);
}
SECTION("Device to device") {
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
MemcpyWithDirectionCommonNegativeTests(hipMemcpy, dst_alloc.ptr(), src_alloc.ptr(), kPageSize,
hipMemcpyDeviceToDevice);
}
}
+586
Просмотреть файл
@@ -0,0 +1,586 @@
/*
Copyright (c) 2021-22-present Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
* Different test for checking functionality of
* hipError_t hipMemcpyWithStream(void* dst, const void* src, size_t sizeBytes,hipMemcpyKind kind,
* hipStream_t stream);
*/
/*
This testfile verifies the following scenarios
1. hipMemcpyWithStream with one stream
2. hipMemcpyWithStream with two streams
3. Multi GPU and single stream
4. hipMemcpyWithStream API with testkind DtoH
5. hipMemcpyWithStream API with testkind DtoD
6. hipMemcpyWithStream API with testkind HtoH
7. hipMemcpyWithStream API with testkind TestkindDefault
8. hipMemcpyWithStream API with testkind TestkindDefaultForDtoD
9. hipMemcpyWithStream API DtoD on same device
*/
#include <hip_test_common.hh>
#include <hip_test_kernels.hh>
#include <hip_test_checkers.hh>
#include<vector>
#include<thread>
#include<chrono>
#define LEN 64
#define SIZE LEN << 2
#define THREADS 2
#define MAX_THREADS 16
static constexpr size_t N{4 * 1024 * 1024};
static const auto MaxGPUDevices{256};
static constexpr unsigned blocksPerCU{6}; // to hide latency
static constexpr unsigned threadsPerBlock{256};
enum class ops
{ TestwithOnestream,
TestwithTwoStream,
TestOnMultiGPUwithOneStream,
TestkindDtoH,
TestkindDtoD,
TestkindHtoH,
TestkindDefault,
TestkindDefaultForDtoD,
TestDtoDonSameDevice,
END_OF_LIST
};
struct joinable_thread : std::thread {
template <class... Xs>
explicit joinable_thread(Xs&&... xs) : std::thread(std::forward<Xs>(xs)...)
{} // NOLINT
joinable_thread& operator=(joinable_thread&& other) = default;
joinable_thread(joinable_thread&& other) = default;
~joinable_thread() {
if (this->joinable())
this->join();
}
};
void TestwithOnestream(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes,
hipMemcpyHostToDevice, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestwithTwoStream(void) {
size_t Nbytes = N * sizeof(int);
const int NUM_STREAMS = 2;
int *A_d[NUM_STREAMS], *B_d[NUM_STREAMS], *C_d[NUM_STREAMS];
int *A_h[NUM_STREAMS], *B_h[NUM_STREAMS], *C_h[NUM_STREAMS];
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
for (int i=0; i < NUM_STREAMS; ++i) {
HipTest::initArrays(&A_d[i], &B_d[i], &C_d[i],
&A_h[i], &B_h[i], &C_h[i], N, false);
}
hipStream_t stream[NUM_STREAMS];
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamCreate(&stream[i]));
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
}
for (int i=0; i < NUM_STREAMS; ++i) {
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[i], B_h[i], C_h[i], N);
}
for (int i=0; i < NUM_STREAMS; ++i) {
HipTest::freeArrays(A_d[i], B_d[i], C_d[i], A_h[i], B_h[i], C_h[i], false);
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
void TestDtoDonSameDevice(void) {
size_t Nbytes = N * sizeof(int);
const int NUM_STREAMS = 2;
int *A_d[NUM_STREAMS], *B_d[NUM_STREAMS], *C_d[NUM_STREAMS];
int *A_h[NUM_STREAMS], *B_h[NUM_STREAMS], *C_h[NUM_STREAMS];
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
hipStream_t stream[NUM_STREAMS];
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMalloc(&A_d[1], Nbytes));
HIP_CHECK(hipMalloc(&B_d[1], Nbytes));
HIP_CHECK(hipMalloc(&C_d[1], Nbytes));
C_h[1] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[1] != NULL);
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(A_d[1], A_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[1]));
HIP_CHECK(hipMemcpyWithStream(B_d[1], B_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[1]));
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
if (A_d[1]) {
HIP_CHECK(hipFree(A_d[1]));
}
if (B_d[1]) {
HIP_CHECK(hipFree(B_d[1]));
}
if (C_d[1]) {
HIP_CHECK(hipFree(C_d[1]));
}
if (C_h[1]) {
free(C_h[1]);
}
for (int i=0; i < NUM_STREAMS; ++i) {
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
void TestOnMultiGPUwithOneStream(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// If you have single GPU machine the return
if (NumDevices <= 1) {
SUCCEED("NumDevices <2");
} else {
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HipTest::initArrays(&A_d[i], &B_d[i], &C_d[i],
&A_h[i], &B_h[i], &C_h[i], N, false);
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_h[i], Nbytes,
hipMemcpyHostToDevice, stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock), 0, stream[i],
static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[i], B_h[i], C_h[i], N);
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HipTest::freeArrays(A_d[i], B_d[i], C_d[i],
A_h[i], B_h[i], C_h[i], false);
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindDtoH(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes,
hipMemcpyHostToDevice, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpyWithStream(C_h, C_d, Nbytes,
hipMemcpyDeviceToHost, stream));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestkindDtoD(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// If you have single GPU machine the return
if (NumDevices <= 1) {
SUCCEED("NumDevices are less than 2");
} else {
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
// Initialize and create the host and device elements for first device
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i))
HIP_CHECK(hipMalloc(&A_d[i], Nbytes));
HIP_CHECK(hipMalloc(&B_d[i], Nbytes));
HIP_CHECK(hipMalloc(&C_d[i], Nbytes));
C_h[i] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[i] != NULL);
}
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
// Copying device data from 1st GPU to the rest of the the GPUs that is
// NumDevices in the setup. 1st GPU start numbering from 0,1,2..n etc.
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_d[0], Nbytes,
hipMemcpyDeviceToDevice, stream[i]));
}
// Launching the kernel including the 1st GPU to the no of GPUs present
// in the setup. 1st GPU start numbering from 0,1,2..n etc.
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
HIP_CHECK(hipStreamDestroy(stream[0]));
for (int i=1; i < NumDevices; ++i) {
if (A_d[i]) {
HIP_CHECK(hipFree(A_d[i]));
}
if (B_d[i]) {
HIP_CHECK(hipFree(B_d[i]));
}
if (C_d[i]) {
HIP_CHECK(hipFree(C_d[i]));
}
if (C_h[i]) {
free(C_h[i]);
}
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindDefault(void) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(A_d, A_h, Nbytes, hipMemcpyDefault, stream));
HIP_CHECK(hipMemcpyWithStream(B_d, B_h, Nbytes, hipMemcpyDefault, stream));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, stream, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIP_CHECK(hipGetLastError());
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpyWithStream(C_h, C_d, Nbytes, hipMemcpyDefault, stream));
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipStreamDestroy(stream));
}
void TestkindDefaultForDtoD(void) {
size_t Nbytes = N * sizeof(int);
int NumDevices = 0;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGetDeviceCount(&NumDevices));
// Test case will not run on single GPU setup.
if (NumDevices <= 1) {
SUCCEED("No of Devices < 2");
} else {
int *A_d[MaxGPUDevices], *B_d[MaxGPUDevices], *C_d[MaxGPUDevices];
int *A_h[MaxGPUDevices], *B_h[MaxGPUDevices], *C_h[MaxGPUDevices];
// Initialize and create the host and device elements for first device
HIP_CHECK(hipSetDevice(0));
HipTest::initArrays(&A_d[0], &B_d[0], &C_d[0],
&A_h[0], &B_h[0], &C_h[0], N, false);
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMalloc(&A_d[i], Nbytes));
HIP_CHECK(hipMalloc(&B_d[i], Nbytes));
HIP_CHECK(hipMalloc(&C_d[i], Nbytes));
C_h[i] = reinterpret_cast<int*>(malloc(Nbytes));
HIP_ASSERT(C_h[i] != NULL);
}
hipStream_t stream[MaxGPUDevices];
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipStreamCreate(&stream[i]));
}
HIP_CHECK(hipMemcpyWithStream(A_d[0], A_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
HIP_CHECK(hipMemcpyWithStream(B_d[0], B_h[0], Nbytes,
hipMemcpyHostToDevice, stream[0]));
// Copying device data from 1st GPU to the rest of the the GPUs
// using hipMemcpyDefault kind that is NumDevices in the setup.
// 1st GPU start numbering from 0,1,2..n etc.
for (int i=1; i < NumDevices; ++i) {
HIP_CHECK(hipMemcpyWithStream(A_d[i], A_d[0], Nbytes,
hipMemcpyDefault, stream[i]));
HIP_CHECK(hipMemcpyWithStream(B_d[i], B_d[0], Nbytes,
hipMemcpyDefault, stream[i]));
}
for (int i=0; i < NumDevices; ++i) {
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
dim3(threadsPerBlock),
0, stream[i], static_cast<const int*>(A_d[i]),
static_cast<const int*>(B_d[i]), C_d[i], N);
HIP_CHECK(hipGetLastError());
}
for (int i=0; i < NumDevices; ++i) {
HIP_CHECK(hipSetDevice(i)); // hipMemcpy will be on this device
HIP_CHECK(hipStreamSynchronize(stream[i]));
HIP_CHECK(hipMemcpy(C_h[i], C_d[i], Nbytes, hipMemcpyDeviceToHost));
// Output of each GPU is getting validated with input of 1st GPU.
HipTest::checkVectorADD(A_h[0], B_h[0], C_h[i], N);
}
HipTest::freeArrays(A_d[0], B_d[0], C_d[0], A_h[0], B_h[0], C_h[0], false);
HIP_CHECK(hipStreamDestroy(stream[0]));
for (int i=1; i < NumDevices; ++i) {
if (A_d[i]) {
HIP_CHECK(hipFree(A_d[i]));
}
if (B_d[i]) {
HIP_CHECK(hipFree(B_d[i]));
}
if (C_d[i]) {
HIP_CHECK(hipFree(C_d[i]));
}
if (C_h[i]) {
free(C_h[i]);
}
HIP_CHECK(hipStreamDestroy(stream[i]));
}
}
}
void TestkindHtoH(void) {
size_t Nbytes = N * sizeof(int);
int *A_h, *B_h;
// Allocate memory to A_h and B_h
A_h = static_cast<int*>(malloc(Nbytes));
HIP_ASSERT(A_h != NULL);
B_h = static_cast<int*>(malloc(Nbytes));
HIP_ASSERT(B_h != NULL);
for (size_t i = 0; i < N; ++i) {
if (A_h) {
(A_h)[i] = 3.146f + i; // Pi
}
}
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyWithStream(B_h, A_h, Nbytes, hipMemcpyHostToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
for (size_t i = 0; i < N; i++) {
HIP_ASSERT(A_h[i] == B_h[i]);
}
if (A_h) {
free(A_h);
}
if (B_h) {
free(B_h);
}
HIP_CHECK(hipStreamDestroy(stream));
}
TEST_CASE("Unit_hipMemcpyWithStream_TestWithOneStream") {
TestwithOnestream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestwithTwoStream") {
TestwithTwoStream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDtoH") {
TestkindDtoH();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindHtoH") {
TestkindHtoH();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDtoD") {
TestkindDtoD();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestOnMultiGPUwithOneStream") {
TestOnMultiGPUwithOneStream();
}
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDefault") {
TestkindDefault();
}
#ifndef __HIP_PLATFORM_NVCC__
TEST_CASE("Unit_hipMemcpyWithStream_TestkindDefaultForDtoD") {
TestkindDefaultForDtoD();
}
#endif
TEST_CASE("Unit_hipMemcpyWithStream_TestDtoDonSameDevice") {
TestDtoDonSameDevice();
}
+119
Просмотреть файл
@@ -0,0 +1,119 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#include <memcpy1d_tests_common.hh>
#include <resource_guards.hh>
#include <utils.hh>
// hipMemcpyDtoH
TEST_CASE("Unit_hipMemcpyDtoH_Positive_Basic") {
MemcpyDeviceToHostShell<false>([](void* dst, void* src, size_t count) {
return hipMemcpyDtoH(dst, reinterpret_cast<hipDeviceptr_t>(src), count);
});
}
TEST_CASE("Unit_hipMemcpyDtoH_Positive_Synchronization_Behavior") {
const auto f = [](void* dst, void* src, size_t count) {
return hipMemcpyDtoH(dst, reinterpret_cast<hipDeviceptr_t>(src), count);
};
MemcpyDtoHPageableSyncBehavior(f, true);
MemcpyDtoHPinnedSyncBehavior(f, true);
}
TEST_CASE("Unit_hipMemcpyDtoH_Negative_Parameters") {
using namespace std::placeholders;
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, kPageSize);
MemcpyCommonNegativeTests(
[](void* dst, void* src, size_t count) {
return hipMemcpyDtoH(dst, reinterpret_cast<hipDeviceptr_t>(src), count);
},
host_alloc.ptr(), device_alloc.ptr(), kPageSize);
}
// hipMemcpyHtoD
TEST_CASE("Unit_hipMemcpyHtoD_Positive_Basic") {
MemcpyHostToDeviceShell<false>([](void* dst, void* src, size_t count) {
return hipMemcpyHtoD(reinterpret_cast<hipDeviceptr_t>(dst), src, count);
});
}
TEST_CASE("Unit_hipMemcpyHtoD_Positive_Synchronization_Behavior") {
MemcpyHtoDSyncBehavior(
[](void* dst, void* src, size_t count) {
return hipMemcpyHtoD(reinterpret_cast<hipDeviceptr_t>(dst), src, count);
},
true);
}
TEST_CASE("Unit_hipMemcpyHtoD_Negative_Parameters") {
using namespace std::placeholders;
LinearAllocGuard<int> device_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, kPageSize);
MemcpyCommonNegativeTests(
[](void* dst, void* src, size_t count) {
return hipMemcpyHtoD(reinterpret_cast<hipDeviceptr_t>(dst), src, count);
},
device_alloc.ptr(), host_alloc.ptr(), kPageSize);
}
// hipMemcpyDtoD
TEST_CASE("Unit_hipMemcpyDtoD_Positive_Basic") {
const auto f = [](void* dst, void* src, size_t count) {
return hipMemcpyDtoD(reinterpret_cast<hipDeviceptr_t>(dst),
reinterpret_cast<hipDeviceptr_t>(src), count);
};
SECTION("Peer access enabled") { MemcpyDeviceToDeviceShell<false, true>(f); }
SECTION("Peer access disabled") { MemcpyDeviceToDeviceShell<false, false>(f); }
}
TEST_CASE("Unit_hipMemcpyDtoD_Positive_Synchronization_Behavior") {
// This behavior differs on NVIDIA and AMD, on AMD the hipMemcpy calls is synchronous with
// respect to the host
#if HT_AMD
HipTest::HIP_SKIP_TEST(
"EXSWCPHIPT-127 - Memcpy from device to device memory behavior differs on AMD and Nvidia");
return;
#endif
MemcpyDtoDSyncBehavior(
[](void* dst, void* src, size_t count) {
return hipMemcpyDtoD(reinterpret_cast<hipDeviceptr_t>(dst),
reinterpret_cast<hipDeviceptr_t>(src), count);
},
false);
}
TEST_CASE("Unit_hipMemcpyDtoD_Negative_Parameters") {
using namespace std::placeholders;
LinearAllocGuard<int> src_alloc(LinearAllocs::hipMalloc, kPageSize);
LinearAllocGuard<int> dst_alloc(LinearAllocs::hipMalloc, kPageSize);
MemcpyCommonNegativeTests(
[](void* dst, void* src, size_t count) {
return hipMemcpyDtoD(reinterpret_cast<hipDeviceptr_t>(dst),
reinterpret_cast<hipDeviceptr_t>(src), count);
},
dst_alloc.ptr(), src_alloc.ptr(), kPageSize);
}
Просмотреть файл
+224
Просмотреть файл
@@ -0,0 +1,224 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <kernels.hh>
#include <resource_guards.hh>
#include <utils.hh>
TEST_CASE("Unit_hipStreamAttachMemAsync_Positive_Basic") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
StreamGuard stream(Streams::created);
LinearAllocGuard<hipDeviceptr_t> managed(LinearAllocs::hipMallocManaged, kPageSize,
hipMemAttachHost);
HIP_CHECK(hipStreamAttachMemAsync(stream.stream(), managed.ptr(), 0));
HIP_CHECK(hipStreamSynchronize(stream.stream()));
}
TEST_CASE("Unit_hipStreamAttachMemAsync_Positive_Pageable") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
if (!DeviceAttributesSupport(0, hipDeviceAttributePageableMemoryAccess)) {
HipTest::HIP_SKIP_TEST("Pageable memory access is not supported");
return;
}
StreamGuard stream(Streams::created);
LinearAllocGuard<hipDeviceptr_t> pageable(LinearAllocs::malloc, kPageSize);
HIP_CHECK(hipStreamAttachMemAsync(stream.stream(), pageable.ptr(), kPageSize));
HIP_CHECK(hipStreamSynchronize(stream.stream()));
}
// CUDA docs:
// If the cudaMemAttachGlobal flag is specified, the memory can be accessed by any stream on any
// device.
TEST_CASE("Unit_hipStreamAttachMemAsync_Positive_AttachGlobal") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
const auto device_count = HipTest::getDeviceCount();
const auto stream_count = device_count < 2 ? 8 : device_count;
std::vector<std::unique_ptr<StreamGuard>> streams;
streams.reserve(stream_count);
for (int i = 0; i < stream_count; ++i) {
if (device_count > 1) {
HIP_CHECK(hipSetDevice(i));
}
streams.push_back(std::make_unique<StreamGuard>(Streams::created));
}
LinearAllocGuard<int> managed_global(LinearAllocs::hipMallocManaged, sizeof(int) * stream_count,
hipMemAttachHost);
HIP_CHECK(hipStreamAttachMemAsync(
nullptr, reinterpret_cast<hipDeviceptr_t*>(managed_global.ptr()), 0, hipMemAttachGlobal));
HIP_CHECK(hipStreamSynchronize(nullptr));
for (int i = 0; i < stream_count; ++i) {
HipTest::launchKernel(Set, 1, 1, 0, streams.at(i)->stream(), managed_global.ptr() + i, i);
}
for (auto&& stream : streams) {
HIP_CHECK(hipStreamSynchronize(stream->stream()));
}
for (int i = 0; i < stream_count; ++i) {
REQUIRE(managed_global.ptr()[i] == i);
}
}
// CUDA docs:
// If the cudaMemAttachHost flag is specified, the program makes a guarantee that it won't access
// the memory on the device from any stream on a device that has a zero value for the device
// attribute cudaDevAttrConcurrentManagedAccess.
TEST_CASE("Unit_hipStreamAttachMemAsync_Positive_AttachHost") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
if (DeviceAttributesSupport(0, hipDeviceAttributeConcurrentManagedAccess)) {
HipTest::HIP_SKIP_TEST("Device supports concurrent managed access");
return;
}
StreamGuard stream(Streams::created);
LinearAllocGuard<int> managed_global(LinearAllocs::hipMallocManaged, sizeof(int));
LinearAllocGuard<int> managed_host(LinearAllocs::hipMallocManaged, sizeof(int));
HIP_CHECK(hipStreamAttachMemAsync(
stream.stream(), reinterpret_cast<hipDeviceptr_t*>(managed_host.ptr()), 0, hipMemAttachHost));
HIP_CHECK(hipStreamSynchronize(stream.stream()));
HipTest::launchKernel(Set, 1, 1, 0, stream.stream(), managed_global.ptr(), 32);
*managed_host.ptr() = 64;
HIP_CHECK(hipStreamSynchronize(stream.stream()));
REQUIRE(*managed_global.ptr() == 32);
REQUIRE(*managed_host.ptr() == 64);
}
// CUDA docs:
// If the cudaMemAttachSingle flag is specified and stream is associated with a device that has a
// zero value for the device attribute cudaDevAttrConcurrentManagedAccess, the program makes a
// guarantee that it will only access the memory on the device from stream.
TEST_CASE("Unit_hipStreamAttachMemAsync_Positive_AttachSingle") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
if (DeviceAttributesSupport(0, hipDeviceAttributeConcurrentManagedAccess)) {
HipTest::HIP_SKIP_TEST("Device supports concurrent managed access");
return;
}
StreamGuard stream1(Streams::created);
StreamGuard stream2(Streams::created);
LinearAllocGuard<int> managed_global(LinearAllocs::hipMallocManaged, sizeof(int));
LinearAllocGuard<int> managed_single(LinearAllocs::hipMallocManaged, sizeof(int),
hipMemAttachHost);
HIP_CHECK(hipStreamAttachMemAsync(stream1.stream(),
reinterpret_cast<hipDeviceptr_t*>(managed_single.ptr()), 0,
hipMemAttachSingle));
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HipTest::launchKernel(Set, 1, 1, 0, stream1.stream(), managed_single.ptr(), 64);
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HipTest::launchKernel(Set, 1, 1, 0, stream2.stream(), managed_global.ptr(), 32);
REQUIRE(*managed_single.ptr() == 64);
*managed_single.ptr() = 128;
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
REQUIRE(*managed_global.ptr() == 32);
REQUIRE(*managed_single.ptr() == 128);
}
TEST_CASE("Unit_hipStreamAttachMemAsync_Negative_Parameters") {
if (!DeviceAttributesSupport(0, hipDeviceAttributeManagedMemory)) {
HipTest::HIP_SKIP_TEST("Managed memory is not supported");
return;
}
StreamGuard stream(Streams::created);
LinearAllocGuard<hipDeviceptr_t> managed(LinearAllocs::hipMallocManaged, kPageSize,
hipMemAttachHost);
SECTION("invalid stream") {
HIP_CHECK(hipStreamDestroy(stream.stream()));
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream.stream(), managed.ptr()),
hipErrorContextIsDestroyed);
}
SECTION("dev_ptr == nullptr") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream.stream(), nullptr), hipErrorInvalidValue);
}
SECTION("length is not zero nor entire allocation size") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream.stream(), managed.ptr(), kPageSize / 2),
hipErrorInvalidValue);
}
SECTION("invalid flags") {
HIP_CHECK_ERROR(
hipStreamAttachMemAsync(stream.stream(), managed.ptr(), 0,
hipMemAttachGlobal | hipMemAttachHost | hipMemAttachSingle),
hipErrorInvalidValue);
}
SECTION("attach single to nullstream") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(nullptr, managed.ptr(), 0, hipMemAttachSingle),
hipErrorInvalidValue);
}
LinearAllocGuard<hipDeviceptr_t> pageable(LinearAllocs::malloc, kPageSize);
if (!DeviceAttributesSupport(0, hipDeviceAttributePageableMemoryAccess)) {
SECTION("dev_ptr is pageable memory") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream.stream(), pageable.ptr(), kPageSize),
hipErrorInvalidValue);
}
} else {
SECTION("length is zero for pageable memory") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream.stream(), pageable.ptr(), 0),
hipErrorInvalidValue);
}
}
}
+4 -4
Просмотреть файл
@@ -18,8 +18,8 @@ elseif (HIP_PLATFORM MATCHES "nvidia")
endif()
# Standalone exes
add_executable(printfFlags EXCLUDE_FROM_ALL printfFlags_exe.cc)
add_executable(printfSpecifiers EXCLUDE_FROM_ALL printfSpecifiers_exe.cc)
add_executable(printfFlags_exe EXCLUDE_FROM_ALL printfFlags_exe.cc)
add_executable(printfSpecifiers_exe EXCLUDE_FROM_ALL printfSpecifiers_exe.cc)
add_dependencies(printfTests printfFlags)
add_dependencies(printfTests printfSpecifiers)
add_dependencies(build_tests printfFlags_exe)
add_dependencies(build_tests printfSpecifiers_exe)
+1 -1
Просмотреть файл
@@ -37,7 +37,7 @@ xyzzy
00000042
)here");
hip::SpawnProc proc("printfFlags", true);
hip::SpawnProc proc("printfFlags_exe", true);
REQUIRE(proc.run() == 0);
REQUIRE(proc.getOutput() == reference);
}
+1 -1
Просмотреть файл
@@ -89,7 +89,7 @@ x
)here");
#endif
hip::SpawnProc proc("printfSpecifiers", true);
hip::SpawnProc proc("printfSpecifiers_exe", true);
REQUIRE(0 == proc.run());
REQUIRE(proc.getOutput() == reference);
}
+7 -6
Просмотреть файл
@@ -1,3 +1,5 @@
set(COMMON_SHARED_SRC streamCommon.cc)
if(HIP_PLATFORM MATCHES "amd")
set(TEST_SRC
hipStreamCreate.cc
@@ -10,7 +12,6 @@ set(TEST_SRC
hipStreamDestroy.cc
hipStreamGetCUMask.cc
hipAPIStreamDisable.cc
streamCommon.cc
hipStreamValue.cc
hipStreamWithCUMask.cc
hipStreamACb_MultiThread.cc
@@ -32,9 +33,8 @@ set(TEST_SRC
hipStreamCreateWithPriority.cc
hipStreamDestroy.cc
hipAPIStreamDisable.cc
# hipStreamAttachMemAsync.cc # Disabling it on nvidia due to issue in function definition of hipStreamAttachMemAsync
# Fixing would break ABI, to be re-enabled when the fix is made.
streamCommon.cc
# hipStreamAttachMemAsync_old.cc # Disabling it on nvidia due to issue in function definition of hipStreamAttachMemAsync
# Fixing would break ABI, to be re-enabled when the fix is made.
hipStreamValue.cc
hipStreamSynchronize.cc
hipStreamQuery.cc
@@ -42,10 +42,11 @@ set(TEST_SRC
hipStreamACb_StrmSyncTiming.cc
)
# set_source_files_properties(hipStreamAttachMemAsync.cc PROPERTIES COMPILE_FLAGS -std=c++17)
# set_source_files_properties(hipStreamAttachMemAsync_old.cc PROPERTIES COMPILE_FLAGS -std=c++17)
endif()
hip_add_exe_to_target(NAME StreamTest
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests
COMPILE_OPTIONS -std=c++17)
COMPILE_OPTIONS -std=c++17
COMMON_SHARED_SRC ${COMMON_SHARED_SRC})
+143
Просмотреть файл
@@ -0,0 +1,143 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// TODO Enable it after hipStreamAttachMemAsync is feature complete on HIP
#include <hip_test_common.hh>
#include <memory>
__device__ __managed__ int var = 0;
enum class StreamAttachTestType { NullStream = 0, StreamPerThread, CreatedStream };
TEST_CASE("Unit_hipStreamAttachMemAsync_Negative") {
hipStream_t stream{nullptr};
auto streamType =
GENERATE(StreamAttachTestType::NullStream, StreamAttachTestType::StreamPerThread,
StreamAttachTestType::CreatedStream);
if (streamType == StreamAttachTestType::StreamPerThread) {
stream = hipStreamPerThread;
} else if (streamType == StreamAttachTestType::CreatedStream) {
HIP_CHECK(hipStreamCreate(&stream));
REQUIRE(stream != nullptr);
}
SECTION("Invalid Resource Handle") {
int definitelyNotAManagedVariable = 0;
HIP_CHECK_ERROR(
hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(&definitelyNotAManagedVariable),
sizeof(int), hipMemAttachSingle),
hipErrorInvalidValue);
}
SECTION("Invalid devptr") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream, nullptr, sizeof(int), hipMemAttachSingle),
hipErrorInvalidValue);
}
SECTION("Invalid Resource Size") {
HIP_CHECK_ERROR(hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(&var), sizeof(int) - 1,
hipMemAttachSingle),
hipErrorInvalidValue);
}
SECTION("Invalid Flags") {
HIP_CHECK_ERROR(
hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(&var), sizeof(int) - 1,
hipMemAttachSingle | hipMemAttachHost | hipMemAttachGlobal),
hipErrorInvalidValue);
}
if (streamType == StreamAttachTestType::CreatedStream) {
HIP_CHECK(hipStreamDestroy(stream));
}
}
__global__ void kernel(int* ptr, size_t size) {
auto i = threadIdx.x;
if (i < size) {
ptr[i] = 1024;
}
}
constexpr size_t size = 1024;
__device__ __managed__ int m_memory[size];
TEST_CASE("Unit_hipStreamAttachMemAsync_UseCase") {
hipStream_t stream{nullptr};
auto streamType =
GENERATE(StreamAttachTestType::NullStream, StreamAttachTestType::StreamPerThread,
StreamAttachTestType::CreatedStream);
if (streamType == StreamAttachTestType::CreatedStream) {
HIP_CHECK(hipStreamCreate(&stream));
REQUIRE(stream != nullptr);
}
SECTION("Size zero is valid") {
int* d_memory{nullptr};
HIP_CHECK(hipMallocManaged(&d_memory, sizeof(int) * size, hipMemAttachHost));
HIP_CHECK(
hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(d_memory), 0, hipMemAttachHost));
HIP_CHECK(hipStreamSynchronize(stream)); // Wait for command to complete
HIP_CHECK(hipFree(d_memory));
}
SECTION("Access from device and host") {
int* d_memory{nullptr};
HIP_CHECK(hipMallocManaged(&d_memory, sizeof(int) * size, hipMemAttachHost));
HIP_CHECK(hipMemset(d_memory, 0, sizeof(int) * size));
HIP_CHECK(
hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(d_memory), 0, hipMemAttachHost));
HIP_CHECK(hipStreamSynchronize(stream)); // Wait for the command to complete
kernel<<<1, size, 0, stream>>>(d_memory, size);
HIP_CHECK(hipStreamSynchronize(stream)); // Wait for the kernel to complete
auto ptr = std::make_unique<int[]>(size);
std::copy(d_memory, d_memory + size, ptr.get());
HIP_CHECK(hipFree(d_memory));
REQUIRE(std::all_of(ptr.get(), ptr.get() + size, [](int n) { return n == size; }));
}
SECTION("Access ManagedMemory") {
HIP_CHECK(hipMemset(m_memory, 0, sizeof(int) * size));
HIP_CHECK(
hipStreamAttachMemAsync(stream, reinterpret_cast<void*>(m_memory), 0, hipMemAttachHost));
HIP_CHECK(hipStreamSynchronize(stream)); // Wait for the command to complete
kernel<<<1, size, 0, stream>>>(m_memory, size);
HIP_CHECK(hipStreamSynchronize(stream)); // Wait for the kernel to complete
auto ptr = std::make_unique<int[]>(size);
std::copy(m_memory, m_memory + size, ptr.get());
REQUIRE(std::all_of(ptr.get(), ptr.get() + size, [](int n) { return n == size; }));
}
if (streamType == StreamAttachTestType::CreatedStream) {
HIP_CHECK(hipStreamDestroy(stream));
}
}
-3
Просмотреть файл
@@ -37,9 +37,6 @@ set(TEST_SRC
hipGetChanDesc.cc
hipTexObjPitch.cc
hipTextureObj1DFetch.cc
hipBindTex2DPitch.cc
hipBindTexRef1DFetch.cc
hipTex1DFetchCheckModes.cc
hipTextureObj1DCheckModes.cc
hipTextureObj2DCheckModes.cc
hipTextureObj3DCheckModes.cc
+26
Просмотреть файл
@@ -0,0 +1,26 @@
set(TEST_SRC
vulkan_test.cc
hipExternalMemoryGetMappedBuffer.cc
)
find_package(Vulkan)
if(NOT Vulkan_FOUND)
if(EXISTS "${VULKAN_PATH}")
message(STATUS "Vulkan SDK: ${VULKAN_PATH}")
elseif (EXISTS "$ENV{VULKAN_SDK}")
message(STATUS "FOUND VULKAN SDK: $ENV{VULKAN_SDK}")
set(VULKAN_PATH $ENV{VULKAN_SDK})
else()
message("Error: Unable to locate Vulkan SDK. please specify VULKAN_PATH")
return()
endif()
endif()
hip_add_exe_to_target(NAME VulkanInteropTest
TEST_SRC ${TEST_SRC}
TEST_TARGET_NAME build_tests)
if (WIN32)
target_link_libraries(VulkanInteropTest vulkan-1)
else (WIN32)
target_link_libraries(VulkanInteropTest vulkan)
endif (WIN32)
+153
Просмотреть файл
@@ -0,0 +1,153 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "vulkan_test.hh"
constexpr bool enable_validation = false;
template <typename T> __global__ void Set(T* ptr, const T val) { ptr[threadIdx.x] = val; }
TEST_CASE("Unit_hipExternalMemoryGetMappedBuffer_Vulkan_Positive_Read_Write") {
VulkanTest vkt(enable_validation);
using type = uint8_t;
constexpr uint32_t count = 3;
const auto vk_storage =
vkt.CreateMappedStorage<type>(count, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true);
const auto hip_ext_mem_desc = vkt.BuildMemoryDescriptor(vk_storage.memory, vk_storage.size);
hipExternalMemory_t hip_ext_memory;
HIP_CHECK(hipImportExternalMemory(&hip_ext_memory, &hip_ext_mem_desc));
hipExternalMemoryBufferDesc external_mem_buffer_desc = {};
external_mem_buffer_desc.size = vk_storage.size;
type* hip_dev_ptr = nullptr;
HIP_CHECK(hipExternalMemoryGetMappedBuffer(reinterpret_cast<void**>(&hip_dev_ptr), hip_ext_memory,
&external_mem_buffer_desc));
REQUIRE(nullptr != hip_dev_ptr);
vk_storage.host_ptr[0] = 41;
vk_storage.host_ptr[1] = 40;
vk_storage.host_ptr[2] = 43;
std::vector<type> read_buffer(count, 0);
HIP_CHECK(
hipMemcpy(read_buffer.data(), hip_dev_ptr, count * sizeof(type), hipMemcpyDeviceToHost));
REQUIRE(41 == read_buffer[0]);
REQUIRE(40 == read_buffer[1]);
REQUIRE(43 == read_buffer[2]);
Set<<<1, 1>>>(hip_dev_ptr + 1, static_cast<type>(42));
HIP_CHECK(hipDeviceSynchronize());
REQUIRE(41 == vk_storage.host_ptr[0]);
REQUIRE(42 == vk_storage.host_ptr[1]);
REQUIRE(43 == vk_storage.host_ptr[2]);
// Defect - EXSWHTEC-181
// HIP_CHECK(hipFree(hip_dev_ptr));
HIP_CHECK(hipDestroyExternalMemory(hip_ext_memory));
}
// Disabled on AMD due to defect - EXSWHTEC-175
#if HT_NVIDIA
TEST_CASE("Unit_hipExternalMemoryGetMappedBuffer_Vulkan_Positive_Read_Write_With_Offset") {
VulkanTest vkt(enable_validation);
using type = uint8_t;
constexpr uint32_t count = 2;
const auto vk_storage =
vkt.CreateMappedStorage<type>(count, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true);
const auto hip_ext_mem_desc = vkt.BuildMemoryDescriptor(vk_storage.memory, vk_storage.size);
hipExternalMemory_t hip_ext_memory;
HIP_CHECK(hipImportExternalMemory(&hip_ext_memory, &hip_ext_mem_desc));
hipExternalMemoryBufferDesc external_mem_buffer_desc = {};
constexpr auto offset = (count - 1) * sizeof(type);
external_mem_buffer_desc.size = vk_storage.size - offset;
external_mem_buffer_desc.offset = offset;
type* hip_dev_ptr = nullptr;
HIP_CHECK(hipExternalMemoryGetMappedBuffer(reinterpret_cast<void**>(&hip_dev_ptr), hip_ext_memory,
&external_mem_buffer_desc));
vk_storage.host_ptr[0] = 41;
vk_storage.host_ptr[1] = 42;
type read_val = 0;
HIP_CHECK(hipMemcpy(&read_val, hip_dev_ptr, 1, hipMemcpyDeviceToHost));
REQUIRE(42 == read_val);
// Defect - EXSWHTEC-181
// HIP_CHECK(hipFree(hip_dev_ptr));
HIP_CHECK(hipDestroyExternalMemory(hip_ext_memory));
}
#endif
TEST_CASE("Unit_hipExternalMemoryGetMappedBuffer_Vulkan_Negative_Parameters") {
VulkanTest vkt(enable_validation);
const auto vk_storage = vkt.CreateMappedStorage<int>(1, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true);
const auto hip_ext_mem_desc = vkt.BuildMemoryDescriptor(vk_storage.memory, vk_storage.size);
hipExternalMemory_t hip_ext_memory;
HIP_CHECK(hipImportExternalMemory(&hip_ext_memory, &hip_ext_mem_desc));
hipExternalMemoryBufferDesc external_mem_buffer_desc = {};
external_mem_buffer_desc.size = vk_storage.size;
void* hip_dev_ptr = nullptr;
// Disabled on AMD due to defect - EXSWHTEC-176
#if HT_NVIDIA
SECTION("devPtr == nullptr") {
HIP_CHECK_ERROR(
hipExternalMemoryGetMappedBuffer(nullptr, hip_ext_memory, &external_mem_buffer_desc),
hipErrorInvalidValue);
}
#endif
// Disabled on AMD due to defect - EXSWHTEC-177
#if HT_NVIDIA
SECTION("bufferDesc == nullptr") {
HIP_CHECK_ERROR(hipExternalMemoryGetMappedBuffer(&hip_dev_ptr, hip_ext_memory, nullptr),
hipErrorInvalidValue);
}
#endif
// Disabled on AMD due to defect - EXSWHTEC-179
#if HT_NVIDIA
SECTION("bufferDesc.flags != 0") {
external_mem_buffer_desc.flags = 1;
HIP_CHECK_ERROR(
hipExternalMemoryGetMappedBuffer(&hip_dev_ptr, hip_ext_memory, &external_mem_buffer_desc),
hipErrorInvalidValue);
}
#endif
// Disabled on AMD due to defect - EXSWHTEC-180
#if HT_NVIDIA
SECTION("bufferDesc.offset + bufferDesc.size > hipExternalMemHandleDesc.size") {
external_mem_buffer_desc.offset = 1;
HIP_CHECK_ERROR(
hipExternalMemoryGetMappedBuffer(&hip_dev_ptr, hip_ext_memory, &external_mem_buffer_desc),
hipErrorInvalidValue);
}
#endif
}
+410
Просмотреть файл
@@ -0,0 +1,410 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "vulkan_test.hh"
#include <iostream>
#include <algorithm>
VkFence VulkanTest::CreateFence() {
VkFence fence;
VkFenceCreateInfo fence_create_info = {};
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_create_info.flags = 0;
VK_CHECK_RESULT(vkCreateFence(_device, &fence_create_info, nullptr, &fence));
_fences.push_back(fence);
return fence;
}
VkSemaphore VulkanTest::CreateExternalSemaphore(VkSemaphoreType sem_type, uint64_t initial_value) {
VkExportSemaphoreCreateInfoKHR export_sem_create_info = {};
export_sem_create_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR;
export_sem_create_info.handleTypes = _sem_handle_type;
if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE) {
VkSemaphoreTypeCreateInfo timeline_create_info = {};
timeline_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO;
timeline_create_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
timeline_create_info.initialValue = initial_value;
export_sem_create_info.pNext = &timeline_create_info;
} else {
export_sem_create_info.pNext = nullptr;
}
VkSemaphoreCreateInfo semaphore_create_info = {};
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphore_create_info.pNext = &export_sem_create_info;
VkSemaphore semaphore;
VK_CHECK_RESULT(vkCreateSemaphore(_device, &semaphore_create_info, nullptr, &semaphore));
_semaphores.push_back(semaphore);
return semaphore;
}
hipExternalSemaphoreHandleDesc VulkanTest::BuildSemaphoreDescriptor(VkSemaphore vk_sem,
VkSemaphoreType sem_type) {
hipExternalSemaphoreHandleDesc sem_handle_desc = {};
sem_handle_desc.type = VulkanSemHandleTypeToHIPHandleType(sem_type);
#ifdef _WIN64
sem_handle_desc.handle.win32.handle = GetSemaphoreHandle(vk_sem);
#else
sem_handle_desc.handle.fd = GetSemaphoreHandle(vk_sem);
#endif
sem_handle_desc.flags = 0;
return sem_handle_desc;
}
hipExternalMemoryHandleDesc VulkanTest::BuildMemoryDescriptor(VkDeviceMemory vk_mem,
uint32_t size) {
hipExternalMemoryHandleDesc mem_handle_desc = {};
mem_handle_desc.type = VulkanMemHandleTypeToHIPHandleType();
#ifdef _WIN64
mem_handle_desc.handle.win32.handle = GetMemoryHandle(ck_mem);
#else
mem_handle_desc.handle.fd = GetMemoryHandle(vk_mem);
#endif
mem_handle_desc.size = size;
return mem_handle_desc;
}
void VulkanTest::CreateInstance() {
UNSCOPED_INFO("Not all of the required instance extensions are supported");
REQUIRE(CheckExtensionSupport(_required_instance_extensions));
if (_enable_validation) {
EnableValidationLayer();
}
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.apiVersion = VK_API_VERSION_1_2;
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &app_info;
create_info.enabledExtensionCount = static_cast<uint32_t>(_required_instance_extensions.size());
create_info.ppEnabledExtensionNames = _required_instance_extensions.data();
create_info.enabledLayerCount = static_cast<uint32_t>(_enabled_layers.size());
create_info.ppEnabledLayerNames = _enabled_layers.data();
VK_CHECK_RESULT(vkCreateInstance(&create_info, nullptr, &_instance));
}
void VulkanTest::CreateDevice() {
UNSCOPED_INFO("Not all of the required device extensions are supported");
REQUIRE(CheckExtensionSupport(_required_device_extensions));
FindPhysicalDevice();
VkDeviceQueueCreateInfo queue_create_info = {};
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info.queueFamilyIndex = _compute_family_queue_idx = GetComputeQueueFamilyIndex();
queue_create_info.queueCount = 1;
float queue_priorities = 1.0;
queue_create_info.pQueuePriorities = &queue_priorities;
VkPhysicalDeviceVulkan12Features features = {};
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
features.timelineSemaphore = true;
VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.enabledLayerCount = _enabled_layers.size();
device_create_info.ppEnabledLayerNames = _enabled_layers.data();
device_create_info.enabledExtensionCount = _required_device_extensions.size();
device_create_info.ppEnabledExtensionNames = _required_device_extensions.data();
device_create_info.pQueueCreateInfos = &queue_create_info;
device_create_info.queueCreateInfoCount = 1;
device_create_info.pNext = &features;
VK_CHECK_RESULT(vkCreateDevice(_physical_device, &device_create_info, nullptr, &_device));
vkGetDeviceQueue(_device, _compute_family_queue_idx, 0, &_queue);
}
void VulkanTest::CreateCommandBuffer() {
VkCommandPoolCreateInfo command_pool_create_info = {};
command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
command_pool_create_info.flags = 0;
command_pool_create_info.queueFamilyIndex = _compute_family_queue_idx;
VK_CHECK_RESULT(vkCreateCommandPool(_device, &command_pool_create_info, nullptr, &_command_pool));
VkCommandBufferAllocateInfo command_buffer_allocate_info = {};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.commandPool = _command_pool;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_allocate_info.commandBufferCount = 1;
VK_CHECK_RESULT(
vkAllocateCommandBuffers(_device, &command_buffer_allocate_info, &_command_buffer));
}
bool VulkanTest::CheckExtensionSupport(std::vector<const char*> expected_extensions) {
uint32_t extension_count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
std::vector<VkExtensionProperties> extension_properties(extension_count);
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_properties.data());
std::vector<const char*> supported_extensions;
supported_extensions.reserve(extension_count);
std::transform(extension_properties.begin(), extension_properties.end(),
std::back_inserter(supported_extensions),
[](const auto& p) { return p.extensionName; });
constexpr auto p = [](const char* l, const char* r) { return strcmp(l, r) < 0; };
std::sort(expected_extensions.begin(), expected_extensions.end(), p);
std::sort(supported_extensions.begin(), supported_extensions.end(), p);
return std::includes(supported_extensions.begin(), supported_extensions.end(),
expected_extensions.begin(), expected_extensions.end(),
[](const char* l, const char* r) { return strcmp(l, r) == 0; });
}
void VulkanTest::EnableValidationLayer() {
uint32_t layer_count = 0;
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
std::vector<VkLayerProperties> layer_properties(layer_count);
vkEnumerateInstanceLayerProperties(&layer_count, layer_properties.data());
const bool found_val_layer =
std::any_of(layer_properties.cbegin(), layer_properties.cend(), [](const auto& props) {
return strcmp(props.layerName, "VK_LAYER_KHRONOS_validation") == 0;
});
if (found_val_layer) {
_enabled_layers.push_back("VK_LAYER_KHRONOS_validation");
} else {
UNSCOPED_INFO("Validation was requested, but the validation layer could not be located");
REQUIRE(found_val_layer);
}
}
uint32_t VulkanTest::GetComputeQueueFamilyIndex() {
uint32_t queue_family_count = 0u;
vkGetPhysicalDeviceQueueFamilyProperties(_physical_device, &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(_physical_device, &queue_family_count,
queue_families.data());
const auto it =
std::find_if(queue_families.cbegin(), queue_families.cend(), [](const auto& props) {
return props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT);
});
REQUIRE(it != queue_families.cend());
return std::distance(queue_families.cbegin(), it);
}
void VulkanTest::FindPhysicalDevice() {
uint32_t device_count = 0;
vkEnumeratePhysicalDevices(_instance, &device_count, nullptr);
REQUIRE(device_count != 0u);
std::vector<VkPhysicalDevice> physical_devices(device_count);
vkEnumeratePhysicalDevices(_instance, &device_count, physical_devices.data());
_physical_device = physical_devices[0];
}
uint32_t VulkanTest::FindMemoryType(uint32_t memory_type_bits, VkMemoryPropertyFlags properties) {
VkPhysicalDeviceMemoryProperties memory_properties;
vkGetPhysicalDeviceMemoryProperties(_physical_device, &memory_properties);
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) {
if ((memory_type_bits & (1 << i)) &&
((memory_properties.memoryTypes[i].propertyFlags & properties) == properties)) {
return i;
}
}
return VK_MAX_MEMORY_TYPES;
}
hipExternalSemaphoreHandleType VulkanTest::VulkanSemHandleTypeToHIPHandleType(
VkSemaphoreType sem_type) {
if (sem_type == VK_SEMAPHORE_TYPE_BINARY) {
if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
return hipExternalSemaphoreHandleTypeOpaqueWin32;
} else if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
return hipExternalSemaphoreHandleTypeOpaqueWin32Kmt;
} else if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
return hipExternalSemaphoreHandleTypeOpaqueFd;
}
} else if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE) {
#if HT_AMD
throw std::invalid_argument("Timeline semaphore unsupported on AMD");
#else
if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
return hipExternalSemaphoreHandleTypeTimelineSemaphoreWin32;
} else if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
return hipExternalSemaphoreHandleTypeTimelineSemaphoreWin32;
} else if (_sem_handle_type & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
return hipExternalSemaphoreHandleTypeTimelineSemaphoreFd;
}
#endif
}
throw std::invalid_argument("Invalid vulkan semaphore handle type");
}
hipExternalMemoryHandleType VulkanTest::VulkanMemHandleTypeToHIPHandleType() {
if (_mem_handle_type & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) {
return hipExternalMemoryHandleTypeOpaqueWin32;
} else if (_mem_handle_type & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT) {
return hipExternalMemoryHandleTypeOpaqueWin32Kmt;
} else if (_mem_handle_type & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
return hipExternalMemoryHandleTypeOpaqueFd;
}
throw std::invalid_argument("Invalid vulkan memory handle type");
}
#ifdef _WIN64
HANDLE
VulkanTest::GetSemaphoreHandle(VkSemaphore semaphore) {
HANDLE handle = 0;
VkSemaphoreGetWin32HandleInfoKHR semaphoreGetWin32HandleInfoKHR = {};
semaphoreGetWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR;
semaphoreGetWin32HandleInfoKHR.pNext = NULL;
semaphoreGetWin32HandleInfoKHR.semaphore = semaphore;
semaphoreGetWin32HandleInfoKHR.handleType = _sem_handle_type;
PFN_vkGetSemaphoreWin32HandleKHR fpGetSemaphoreWin32HandleKHR;
fpGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR)vkGetDeviceProcAddr(
_device, "vkGetSemaphoreWin32HandleKHR");
if (!fpGetSemaphoreWin32HandleKHR) {
throw std::runtime_error("Failed to retrieve vkGetSemaphoreWin32HandleKHR");
}
if (fpGetSemaphoreWin32HandleKHR(_device, &semaphoreGetWin32HandleInfoKHR, &handle) !=
VK_SUCCESS) {
throw std::runtime_error("Failed to retrieve handle for buffer!");
}
return handle;
}
#else
int VulkanTest::GetSemaphoreHandle(VkSemaphore semaphore) {
int fd;
VkSemaphoreGetFdInfoKHR semaphoreGetFdInfoKHR = {};
semaphoreGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
semaphoreGetFdInfoKHR.pNext = NULL;
semaphoreGetFdInfoKHR.semaphore = semaphore;
semaphoreGetFdInfoKHR.handleType = _sem_handle_type;
PFN_vkGetSemaphoreFdKHR fpGetSemaphoreFdKHR;
fpGetSemaphoreFdKHR =
(PFN_vkGetSemaphoreFdKHR)vkGetDeviceProcAddr(_device, "vkGetSemaphoreFdKHR");
if (!fpGetSemaphoreFdKHR) {
throw std::runtime_error("Failed to retrieve vkGetSemaphoreFdKHR");
}
if (fpGetSemaphoreFdKHR(_device, &semaphoreGetFdInfoKHR, &fd) != VK_SUCCESS) {
throw std::runtime_error("Failed to retrieve semaphore handle");
}
return fd;
}
#endif
#ifdef _WIN64
HANDLE
VulkanTest::GetMemoryHandle(VkDeviceMemory memory) {
Handle handle = 0;
VkMemoryGetWin32HandleInfoKHR vkMemoryGetWin32HandleInfoKHR = {};
vkMemoryGetWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
vkMemoryGetWin32HandleInfoKHR.memory = memory;
vkMemoryGetWin32HandleInfoKHR.handleType = _mem_handle_type;
PFN_vkGetMemoryWin32HandleKHR fpGetMemoryWin32HandleKHR =
(PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr(m_device, "vkGetMemoryWin32HandleKHR");
if (!fpGetMemoryWin32HandleKHR) {
throw std::runtime_error("Failed to retrieve vkGetMemoryWin32HandleKHR");
}
if (fpGetMemoryWin32HandleKHR(_device, &vkMemoryGetWin32HandleInfoKHR, &handle) != VK_SUCCESS) {
throw std::runtime_error("Failed to retrieve memory handle");
}
return handle;
}
#else
int VulkanTest::GetMemoryHandle(VkDeviceMemory memory) {
int fd;
VkMemoryGetFdInfoKHR memoryGetFdInfoKHR = {};
memoryGetFdInfoKHR.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
memoryGetFdInfoKHR.memory = memory;
memoryGetFdInfoKHR.handleType = _mem_handle_type;
PFN_vkGetMemoryFdKHR fpGetMemoryFdKHR =
(PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(_device, "vkGetMemoryFdKHR");
if (!fpGetMemoryFdKHR) {
throw std::runtime_error("Failed to retrieve vkGetMemoryFdKHR");
}
if (fpGetMemoryFdKHR(_device, &memoryGetFdInfoKHR, &fd) != VK_SUCCESS) {
throw std::runtime_error("Failed to retrieve memory handle");
}
return fd;
}
#endif
VkExternalSemaphoreHandleTypeFlagBits VulkanTest::GetVkSemHandlePlatformType() const {
#ifdef _WIN64
return IsWindows8OrGreater() ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
#else
return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
}
VkExternalMemoryHandleTypeFlagBits VulkanTest::GetVkMemHandlePlatformType() const {
#ifdef _WIN64
return IsWindows8OrGreater() ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
#else
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
}
// Sometimes in CUDA the stream is not immediately ready after a semaphore has been signaled
void PollStream(hipStream_t stream, hipError_t expected, uint32_t num_iterations) {
hipError_t query_result;
for (uint32_t _ = 0; _ < num_iterations; ++_) {
if ((query_result = hipStreamQuery(stream)) != expected) {
std::this_thread::sleep_for(std::chrono::milliseconds{5});
} else {
break;
}
}
REQUIRE(expected == query_result);
}
hipExternalSemaphore_t ImportBinarySemaphore(VulkanTest& vkt) {
const auto semaphore = vkt.CreateExternalSemaphore(VK_SEMAPHORE_TYPE_BINARY);
const auto sem_handle_desc = vkt.BuildSemaphoreDescriptor(semaphore, VK_SEMAPHORE_TYPE_BINARY);
hipExternalSemaphore_t hip_ext_semaphore;
HIP_CHECK(hipImportExternalSemaphore(&hip_ext_semaphore, &sem_handle_desc));
return hip_ext_semaphore;
}
+259
Просмотреть файл
@@ -0,0 +1,259 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <vulkan/vulkan.h>
#include <vector>
#ifdef _WIN64
#include <VersionHelpers.h>
#endif
#include <hip_test_common.hh>
#include <hip/hip_runtime_api.h>
#define VK_CHECK_RESULT(code) \
{ \
VkResult res = (code); \
if (res != VK_SUCCESS) { \
INFO("Vulkan error: " << std::to_string(res) << "\n In File: " << __FILE__ \
<< "\n At line: " << __LINE__); \
REQUIRE(false); \
} \
}
class VulkanTest {
public:
VulkanTest(bool enable_validation)
: _enable_validation{enable_validation},
_sem_handle_type{GetVkSemHandlePlatformType()},
_mem_handle_type{GetVkMemHandlePlatformType()} {
CreateInstance();
CreateDevice();
CreateCommandBuffer();
}
~VulkanTest() {
for (const auto s : _semaphores) {
vkDestroySemaphore(_device, s, nullptr);
}
for (const auto f : _fences) {
vkDestroyFence(_device, f, nullptr);
}
for (const auto& s : _stores) {
vkUnmapMemory(_device, s.memory);
vkDestroyBuffer(_device, s.buffer, nullptr);
vkFreeMemory(_device, s.memory, nullptr);
}
if (_command_buffer != VK_NULL_HANDLE)
vkFreeCommandBuffers(_device, _command_pool, 1, &_command_buffer);
if (_command_pool != VK_NULL_HANDLE) vkDestroyCommandPool(_device, _command_pool, nullptr);
if (_device != VK_NULL_HANDLE) vkDestroyDevice(_device, nullptr);
if (_instance != VK_NULL_HANDLE) vkDestroyInstance(_instance, nullptr);
}
VulkanTest(const VulkanTest&) = delete;
VulkanTest(VulkanTest&&) = delete;
template <typename T> struct MappedBuffer {
VkDeviceMemory memory = VK_NULL_HANDLE;
VkBuffer buffer = VK_NULL_HANDLE;
uint32_t size = 0;
T* host_ptr = nullptr;
};
template <typename T>
MappedBuffer<T> CreateMappedStorage(uint32_t count, VkBufferUsageFlagBits transfer_flags,
bool external = false);
VkFence CreateFence();
VkSemaphore CreateExternalSemaphore(VkSemaphoreType sem_type, uint64_t initial_value = 0);
hipExternalSemaphoreHandleDesc BuildSemaphoreDescriptor(VkSemaphore vk_sem,
VkSemaphoreType sem_type);
hipExternalMemoryHandleDesc BuildMemoryDescriptor(VkDeviceMemory vk_mem, uint32_t size);
VkDevice GetDevice() const { return _device; }
VkCommandBuffer GetCommandBuffer() const { return _command_buffer; }
VkQueue GetQueue() const { return _queue; }
private:
void CreateInstance();
void CreateDevice();
void CreateCommandBuffer();
bool CheckExtensionSupport(std::vector<const char*> expected_extensions);
void EnableValidationLayer();
uint32_t GetComputeQueueFamilyIndex();
void FindPhysicalDevice();
uint32_t FindMemoryType(uint32_t memory_type_bits, VkMemoryPropertyFlags properties);
hipExternalSemaphoreHandleType VulkanSemHandleTypeToHIPHandleType(VkSemaphoreType sem_type);
hipExternalMemoryHandleType VulkanMemHandleTypeToHIPHandleType();
#ifdef _WIN64
HANDLE
GetSemaphoreHandle(VkSemaphore semaphore);
#else
int GetSemaphoreHandle(VkSemaphore semaphore);
#endif
#ifdef _WIN64
HANDLE
GetMemoryHandle(VkDeviceMemory memory);
#else
int GetMemoryHandle(VkDeviceMemory memory);
#endif
VkExternalSemaphoreHandleTypeFlagBits GetVkSemHandlePlatformType() const;
VkExternalMemoryHandleTypeFlagBits GetVkMemHandlePlatformType() const;
struct Storage {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
uint32_t size = 0u;
};
private:
const bool _enable_validation = false;
const VkExternalSemaphoreHandleTypeFlagBits _sem_handle_type;
const VkExternalMemoryHandleTypeFlagBits _mem_handle_type;
VkInstance _instance = VK_NULL_HANDLE;
VkPhysicalDevice _physical_device = VK_NULL_HANDLE;
VkDevice _device = VK_NULL_HANDLE;
VkQueue _queue = VK_NULL_HANDLE;
VkCommandPool _command_pool = VK_NULL_HANDLE;
VkCommandBuffer _command_buffer = VK_NULL_HANDLE;
uint32_t _compute_family_queue_idx = 0u;
std::vector<const char*> _enabled_layers;
std::vector<VkSemaphore> _semaphores;
std::vector<VkFence> _fences;
std::vector<Storage> _stores;
std::vector<const char*> _required_instance_extensions{
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME};
#ifdef _WIN64
std::vector<const char*> _required_device_extensions{
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME};
#else
std::vector<const char*> _required_device_extensions{
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME};
#endif
};
template <typename T>
VulkanTest::MappedBuffer<T> VulkanTest::CreateMappedStorage(uint32_t count,
VkBufferUsageFlagBits transfer_flags,
bool external) {
Storage storage;
const auto size = count * sizeof(T);
VkBufferCreateInfo buffer_create_info = {};
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_create_info.size = size;
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | transfer_flags;
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkExternalMemoryBufferCreateInfo external_memory_buffer_info = {};
if (external) {
external_memory_buffer_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
external_memory_buffer_info.handleTypes = _mem_handle_type;
buffer_create_info.pNext = &external_memory_buffer_info;
}
VK_CHECK_RESULT(vkCreateBuffer(_device, &buffer_create_info, nullptr, &storage.buffer));
VkMemoryRequirements memory_requirements;
vkGetBufferMemoryRequirements(_device, storage.buffer, &memory_requirements);
storage.size = memory_requirements.size;
VkMemoryAllocateInfo allocate_info = {};
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocate_info.allocationSize = memory_requirements.size;
allocate_info.memoryTypeIndex =
FindMemoryType(memory_requirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
REQUIRE(allocate_info.memoryTypeIndex != VK_MAX_MEMORY_TYPES);
VkExportMemoryAllocateInfoKHR vulkan_export_memory_allocate_info = {};
if (external) {
vulkan_export_memory_allocate_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
vulkan_export_memory_allocate_info.handleTypes = _mem_handle_type;
#ifdef _WIN64
WindowsSecurityAttributes winSecurityAttributes;
VkExportMemoryWin32HandleInfoKHR vulkanExportMemoryWin32HandleInfoKHR = {};
vulkanExportMemoryWin32HandleInfoKHR.sType =
VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
vulkanExportMemoryWin32HandleInfoKHR.pNext = NULL;
vulkanExportMemoryWin32HandleInfoKHR.pAttributes = &winSecurityAttributes;
vulkanExportMemoryWin32HandleInfoKHR.dwAccess =
DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE;
vulkanExportMemoryWin32HandleInfoKHR.name = (LPCWSTR)NULL;
vulkan_export_memory_allocate_info.pNext =
_mem_handle_type & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR
? &vulkanExportMemoryWin32HandleInfoKHR
: NULL;
#endif
allocate_info.pNext = &vulkan_export_memory_allocate_info;
}
VK_CHECK_RESULT(vkAllocateMemory(_device, &allocate_info, nullptr, &storage.memory));
VK_CHECK_RESULT(vkBindBufferMemory(_device, storage.buffer, storage.memory, 0));
T* host_ptr = nullptr;
VK_CHECK_RESULT(vkMapMemory(_device, storage.memory, 0, storage.size, 0,
reinterpret_cast<void**>(&host_ptr)));
_stores.push_back(storage);
return MappedBuffer<T>{storage.memory, storage.buffer, storage.size, host_ptr};
}
// Sometimes in CUDA the stream is not immediately ready after a semaphore has been signaled
void PollStream(hipStream_t stream, hipError_t expected, uint32_t num_iterations = 5);
hipExternalSemaphore_t ImportBinarySemaphore(VulkanTest& vkt);