Merge 'develop' into 'amd-staging'
Change-Id: I2dce94151b89065a31619491e88d433d6133273a
Этот коммит содержится в:
@@ -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
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
"Unit_hipInit_Negative",
|
||||
"Unit_BuiltinAtomicsRTC_fmaxCoherentGlobalMem",
|
||||
"Unit_BuiltinAtomicsRTC__fminCoherentGlobalMem",
|
||||
"Unit_BuiltInAtomicAdd_CoherentGlobalMemWithRtc"
|
||||
"Unit_BuiltInAtomicAdd_CoherentGlobalMemWithRtc",
|
||||
"Unit_hipMemGetAddressRange_Negative"
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"Unit_hipDeviceGetPCIBusId_Negative_PartialFill",
|
||||
"Unit_hipInit_Negative",
|
||||
"Unit_hipGraphAddEventRecordNode_Functional_ElapsedTime",
|
||||
"Unit_hipStreamBeginCapture_captureComplexGraph"
|
||||
"Unit_hipStreamBeginCapture_captureComplexGraph",
|
||||
"Unit_hipMemGetAddressRange_Negative"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ set(TEST_SRC
|
||||
hipMemcpyMThreadMSize.cc
|
||||
hipMallocManagedStress.cc
|
||||
hipMemPrftchAsyncStressTst.cc
|
||||
hipHostMalloc.cc
|
||||
hipHostMallocStress.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME memory
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -59,7 +59,6 @@ set(TEST_SRC
|
||||
hipGraphEventWaitNodeGetEvent.cc
|
||||
hipGraphExecMemcpyNodeSetParams.cc
|
||||
hipStreamBeginCapture.cc
|
||||
hipGraphAddMemcpyNode1D.cc
|
||||
hipStreamIsCapturing.cc
|
||||
hipStreamGetCaptureInfo.cc
|
||||
hipStreamEndCapture.cc
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
Ссылка в новой задаче
Block a user