Merge 'develop' into 'amd-staging'
Change-Id: If1de40873add9a0e69513781c1d47e82a3fb2a5d
Αυτή η υποβολή περιλαμβάνεται σε:
@@ -15,6 +15,11 @@
|
||||
"Unit_hipMemset_Negative_OutOfBoundsPtr",
|
||||
"Unit_hipDeviceReset_Positive_Basic",
|
||||
"Unit_hipDeviceReset_Positive_Threaded",
|
||||
"Unit_hipGraphMemcpyNodeSetParamsToSymbol_Positive_Basic",
|
||||
"Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Positive_Basic",
|
||||
"Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Positive_Basic",
|
||||
"Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Positive_Basic",
|
||||
"Unit_hipKernelNameRef_Negative_Parameters",
|
||||
"Unit_hipMemAdvise_AccessedBy_All_Devices",
|
||||
"Unit_hipMemAdvise_No_Flag_Interference",
|
||||
"Unit_hipGraphDestroyNode_Complx_ChkNumOfNodesNDep",
|
||||
@@ -31,6 +36,19 @@
|
||||
"Unit_hipGraphAddMemcpyNode1D_Negative_Basic",
|
||||
"Unit_hipStreamGetCaptureInfo_Nullstream_CaptureInfo",
|
||||
"intermittent issue: corrupted double-linked list",
|
||||
"Unit_hipGraphRetainUserObject_Functional_2"
|
||||
"Unit_hipGraphRetainUserObject_Functional_2",
|
||||
"Note: Following four tests disabled due to defect - EXSWHTEC-203",
|
||||
"Unit_hipGraphAddMemsetNode_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphAddMemsetNode_Positive_Basic - uint32_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint8_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint32_t",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint8_t",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint32_t",
|
||||
"Unit_hipStreamSetCaptureDependencies_Positive_Functional",
|
||||
"Note: Test disabled due to defect - EXSWHTEC-207",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Negative_Updating_Non1D_Node",
|
||||
"Unit_hipIpcGetMemHandle_Positive_Unique_Handles_Separate_Allocations"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"Unit_hipStreamWaitEvent_DifferentStreams",
|
||||
"Unit_hipStreamQuery_WithFinishedWork",
|
||||
"Unit_hipDeviceGetCacheConfig_Positive_Basic",
|
||||
"Unit_hipDeviceGetCacheConfig_Positive_Basic",
|
||||
"Unit_hipDeviceGetCacheConfig_Positive_Basic",
|
||||
"Unit_hipDeviceGetCacheConfig_Positive_Threaded",
|
||||
"Unit_hipStreamValue_Wait32_Blocking_Mask_Gte",
|
||||
"Unit_hipStreamValue_Wait32_Blocking_Mask_Eq_1",
|
||||
@@ -95,6 +95,12 @@
|
||||
"Unit_hipStreamSynchronize_NullStreamAndStreamPerThread",
|
||||
"Note: intermittent Seg fault failure ",
|
||||
"Unit_hipGraphAddEventRecordNode_Functional_WithoutFlags",
|
||||
"Unit_hipGraphMemcpyNodeSetParamsToSymbol_Positive_Basic",
|
||||
"Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Positive_Basic",
|
||||
"Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Positive_Basic",
|
||||
"Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Positive_Basic",
|
||||
"Unit_hipKernelNameRef_Negative_Parameters",
|
||||
"Unit_hipKernelNameRef_Positive_Basic",
|
||||
"Unit_hipMemAdvise_AccessedBy_All_Devices",
|
||||
"Unit_hipMemAdvise_No_Flag_Interference",
|
||||
"Unit_hipGraphAddEventRecordNode_Functional_WithoutFlags",
|
||||
@@ -108,6 +114,18 @@
|
||||
"Unit_hipStreamValue_Wait64_Blocking_NoMask_Nor",
|
||||
"Unit_hipStreamQuery_WithFinishedWork",
|
||||
"Unit_hipLaunchHostFunc_Graph",
|
||||
"Unit_hipLaunchHostFunc_KernelHost"
|
||||
"Unit_hipLaunchHostFunc_KernelHost",
|
||||
"Unit_hipStreamSetCaptureDependencies_Positive_Functional",
|
||||
"Note: Following four tests disabled due to defect - EXSWHTEC-203",
|
||||
"Unit_hipGraphAddMemsetNode_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphAddMemsetNode_Positive_Basic - uint32_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint32_t",
|
||||
"Note: Test disabled due to defect - EXSWHTEC-207",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Negative_Updating_Non1D_Node",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint8_t",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint16_t",
|
||||
"Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic - uint32_t",
|
||||
"Unit_hipGraphMemsetNodeSetParams_Positive_Basic - uint8_t"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ void MemcpySyncBehaviorCheck(F memcpy_func, const bool should_sync,
|
||||
LaunchDelayKernel(std::chrono::milliseconds{100}, kernel_stream);
|
||||
HIP_CHECK(memcpy_func());
|
||||
if (should_sync) {
|
||||
HIP_CHECK(hipStreamSynchronize(kernel_stream));
|
||||
HIP_CHECK(hipStreamQuery(kernel_stream));
|
||||
} else {
|
||||
HIP_CHECK_ERROR(hipStreamQuery(kernel_stream), hipErrorNotReady);
|
||||
|
||||
@@ -3,6 +3,6 @@ set(TEST_SRC
|
||||
Stress_deviceAllocationStress.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME devalloc
|
||||
hip_add_exe_to_target(NAME devalloc_stress
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME stress_test)
|
||||
|
||||
@@ -7,6 +7,6 @@ set(TEST_SRC
|
||||
hipHostMallocStress.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME memory
|
||||
hip_add_exe_to_target(NAME memory_stress
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME stress_test)
|
||||
|
||||
@@ -4,6 +4,6 @@ set(TEST_SRC
|
||||
Stress_printf_SimpleKernels.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME printf
|
||||
hip_add_exe_to_target(NAME printf_stress
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME stress_test)
|
||||
|
||||
@@ -4,7 +4,7 @@ set(TEST_SRC
|
||||
streamEnqueue.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME stream
|
||||
hip_add_exe_to_target(NAME stream_stress
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME stress_test
|
||||
COMPILE_OPTIONS -std=c++14)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2023 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
|
||||
@@ -34,7 +34,9 @@ add_subdirectory(multiThread)
|
||||
add_subdirectory(compiler)
|
||||
add_subdirectory(errorHandling)
|
||||
add_subdirectory(cooperativeGrps)
|
||||
add_subdirectory(context)
|
||||
if(HIP_PLATFORM STREQUAL "amd")
|
||||
add_subdirectory(callback)
|
||||
#add_subdirectory(clock)
|
||||
# Vulkan interop APIs currently undefined for Nvidia
|
||||
add_subdirectory(vulkan_interop)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
# Common Tests - Test independent of all platforms
|
||||
|
||||
set(TEST_SRC
|
||||
hipApiName.cc
|
||||
hipGetStreamDeviceId.cc
|
||||
hipKernelNameRef.cc
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
set(TEST_SRC ${TEST_SRC} hipKernelNameRefByPtr.cc)
|
||||
|
||||
add_custom_target(SimpleKernel.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${OFFLOAD_ARCH_STR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SimpleKernel.cc
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/../../unit/callback/SimpleKernel.code
|
||||
-I${HIP_PATH}/include -I${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
||||
endif()
|
||||
|
||||
hip_add_exe_to_target(NAME CallbackTest
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME build_tests)
|
||||
|
||||
if(UNIX)
|
||||
add_dependencies(CallbackTest SimpleKernel.code)
|
||||
endif()
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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.h"
|
||||
|
||||
extern "C" __global__ void simple_kernel() {
|
||||
printf("Hello World!");
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
/**
|
||||
* @addtogroup hipApiName hipApiName
|
||||
* @{
|
||||
* @ingroup CallbackTest
|
||||
* `hipApiName(uint32_t id)` -
|
||||
* returns the name of API with passed ID
|
||||
*/
|
||||
|
||||
const char* kUnknownApi{"unknown"};
|
||||
const uint32_t kApiNumber{1024};
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Acquires HIP API names and checks that they are valid
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipApiName.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipApiName_Positive_Basic") {
|
||||
std::vector<std::string> hip_api_names;
|
||||
|
||||
for(uint32_t i = 0; i < kApiNumber; ++i) {
|
||||
if(strcmp(hipApiName(i), kUnknownApi)) {
|
||||
hip_api_names.emplace_back(hipApiName(i));
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(!hip_api_names.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Checks that upper and lower limit IDs are mapped to unknown APIs:
|
||||
* -# When the `uint32_t` upper limit is passed
|
||||
* - Expected output: return "unknown"
|
||||
* -# When the `uint32_t` lower limit is passed
|
||||
* - Expected output: return "unknown"
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipApiName.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipApiName_Negative_ReservedIds") {
|
||||
REQUIRE_THAT(hipApiName(std::numeric_limits<uint32_t>::min()), Catch::Equals(kUnknownApi));
|
||||
REQUIRE_THAT(hipApiName(std::numeric_limits<uint32_t>::max()), Catch::Equals(kUnknownApi));
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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 <resource_guards.hh>
|
||||
|
||||
/**
|
||||
* @addtogroup hipGetStreamDeviceId hipGetStreamDeviceId
|
||||
* @{
|
||||
* @ingroup CallbackTest
|
||||
* `hipGetStreamDeviceId(hipStream_t stream)` -
|
||||
* returns the ID of the device on which the stream is active
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Creates a new stream for each available device
|
||||
* - Verifies that the Device Stream ID is equal to the Device ID
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipGetStreamDeviceId.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipGetStreamDeviceId_Positive_Threaded_Basic") {
|
||||
int id = GENERATE(range(0, HipTest::getDeviceCount()));
|
||||
HIP_CHECK(hipSetDevice(id));
|
||||
|
||||
StreamGuard stream_guard{Streams::created};
|
||||
REQUIRE(hipGetStreamDeviceId(stream_guard.stream()) == id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Creates a new stream for each available device, through multiple threads
|
||||
* - Verifies that the Device Stream ID is equal to the Device ID, from each thread
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipGetStreamDeviceId.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
* - Multithreaded GPU
|
||||
*/
|
||||
TEST_CASE("Unit_hipGetStreamDeviceId_Positive_Multithreaded_Basic") {
|
||||
const unsigned int max_threads = std::thread::hardware_concurrency();
|
||||
const int device_count = HipTest::getDeviceCount();
|
||||
|
||||
auto thread_function = [&]() {
|
||||
for(unsigned int id = 0; id < device_count; ++id) {
|
||||
HIP_CHECK_THREAD(hipSetDevice(id));
|
||||
|
||||
StreamGuard stream_guard{Streams::perThread};
|
||||
REQUIRE_THREAD(hipGetStreamDeviceId(stream_guard.stream()) == id);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::thread> thread_pool;
|
||||
for(unsigned int i = 0; i < max_threads; ++i) {
|
||||
thread_pool.emplace_back(thread_function);
|
||||
}
|
||||
|
||||
for(auto& thread: thread_pool)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
|
||||
HIP_CHECK_THREAD_FINALIZE();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Checks that function returns valid ID if the stream is `nullptr`
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipGetStreamDeviceId.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipGetStreamDeviceId_Negative_Parameters") {
|
||||
int id = GENERATE(range(0, HipTest::getDeviceCount()));
|
||||
HIP_CHECK(hipSetDevice(id));
|
||||
|
||||
StreamGuard stream_guard{Streams::nullstream};
|
||||
REQUIRE(hipGetStreamDeviceId(stream_guard.stream()) == id);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
/**
|
||||
* @addtogroup hipKernelNameRef hipKernelNameRef
|
||||
* @{
|
||||
* @ingroup CallbackTest
|
||||
* `hipKernelNameRef(const hipFunction_t f)` -
|
||||
* returns the name of passed function object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Loads the simple kernel function from the matching module
|
||||
* - Checks that the valid name is returned for the loaded kernel function
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipKernelNameRef.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipKernelNameRef_Positive_Basic") {
|
||||
hipModule_t kernel_module{nullptr};
|
||||
hipFunction_t kernel_function{nullptr};
|
||||
|
||||
HIP_CHECK(hipModuleLoad(&kernel_module, "SimpleKernel.code"));
|
||||
HIP_CHECK(hipModuleGetFunction(&kernel_function, kernel_module, "simple_kernel"));
|
||||
REQUIRE(hipKernelNameRef(kernel_function) != nullptr);
|
||||
HIP_CHECK(hipModuleUnload(kernel_module));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Checks that the API returns nullptr if the passed function is not loaded
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipKernelNameRef.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipKernelNameRef_Negative_Parameters") {
|
||||
hipFunction_t kernel_function{nullptr};
|
||||
REQUIRE(hipKernelNameRef(kernel_function) == nullptr);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
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 <resource_guards.hh>
|
||||
|
||||
/**
|
||||
* @addtogroup hipKernelNameRefByPtr hipKernelNameRefByPtr
|
||||
* @{
|
||||
* @ingroup CallbackTest
|
||||
* `hipKernelNameRefByPtr(const void* hostFunction, hipStream_t stream)` -
|
||||
* returns the name of passed function pointer on desired stream
|
||||
*/
|
||||
|
||||
__global__ void test_kernel() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Creates new stream and a function pointer
|
||||
* - Verifies that valid API name is returned
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipKernelNameRefByPtr.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipKernelNameRefByPtr_Positive_Basic") {
|
||||
const void* kernel_ptr{reinterpret_cast<const void*>(&test_kernel)};
|
||||
|
||||
StreamGuard stream_guard{Streams::created};
|
||||
REQUIRE(hipKernelNameRefByPtr(kernel_ptr, stream_guard.stream()) != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Passes `nullptr` stream while function pointer is valid
|
||||
* - Verifies that the returned value is not `nullptr`
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipKernelNameRefByPtr.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipKernelNameRefByPtr_Negative_StreamNullptr") {
|
||||
const void* kernel_ptr{reinterpret_cast<const void*>(&test_kernel)};
|
||||
StreamGuard stream_guard{Streams::nullstream};
|
||||
|
||||
REQUIRE(hipKernelNameRefByPtr(kernel_ptr, stream_guard.stream()) != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Performs validation when the function pointer is `nullptr`
|
||||
* -# When stream is `nullptr`
|
||||
* - Expected output: return `nullptr`
|
||||
* -# When stream is valid
|
||||
* - Expected output: return `nullptr`
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/callback/hipKernelNameRefByPtr.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
* - Platform specific (AMD)
|
||||
*/
|
||||
TEST_CASE("Unit_hipKernelNameRefByPtr_Negative_KernelNullptr") {
|
||||
const void* kernel_ptr{nullptr};
|
||||
|
||||
SECTION("stream is nullptr") {
|
||||
StreamGuard stream_guard{Streams::nullstream};
|
||||
REQUIRE(hipKernelNameRefByPtr(kernel_ptr, stream_guard.stream()) == nullptr);
|
||||
}
|
||||
|
||||
SECTION("stream is created") {
|
||||
StreamGuard stream_guard{Streams::created};
|
||||
REQUIRE(hipKernelNameRefByPtr(kernel_ptr, stream_guard.stream()) == nullptr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2023 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.
|
||||
# Common Tests - Test independent of all platforms
|
||||
set(TEST_SRC
|
||||
hipDrvGetPCIBusId.cc
|
||||
hipDrvMemcpy.cc
|
||||
hipMemsetD8.cc
|
||||
)
|
||||
hip_add_exe_to_target(NAME Context
|
||||
TEST_SRC ${TEST_SRC}
|
||||
TEST_TARGET_NAME build_tests)
|
||||
@@ -0,0 +1,29 @@
|
||||
/*Copyright (c) 2023 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.
|
||||
*/
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
TEST_CASE("Unit_hipDeviceGetPCIBusId_Functional") {
|
||||
HIP_CHECK(hipInit(0));
|
||||
hipDevice_t device;
|
||||
HIP_CHECK(hipDeviceGet(&device, 0));
|
||||
char pciBusId[13];
|
||||
memset(pciBusId, 0, 13);
|
||||
HIP_CHECK(hipDeviceGetPCIBusId(pciBusId, 13, device));
|
||||
REQUIRE(pciBusId[0] != '\0');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright (c) 2023 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.
|
||||
*/
|
||||
#include <hip_test_common.hh>
|
||||
#define LEN 1024
|
||||
#define SIZE (LEN << 2)
|
||||
|
||||
TEST_CASE("Unit_hipDrvMemcpy_Functional") {
|
||||
int *A, *B;
|
||||
hipDeviceptr_t Ad, Bd;
|
||||
A = new int[LEN];
|
||||
B = new int[LEN];
|
||||
|
||||
for (int i = 0; i < LEN; i++) {
|
||||
A[i] = i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Ad), SIZE));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Bd), SIZE));
|
||||
|
||||
HIP_CHECK(hipMemcpyHtoD(Ad, A, SIZE));
|
||||
HIP_CHECK(hipMemcpyDtoD(Bd, Ad, SIZE));
|
||||
HIP_CHECK(hipMemcpyDtoH(B, Bd, SIZE));
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
REQUIRE(A[i] == B[i]);
|
||||
}
|
||||
|
||||
int *Ah, *Bh;
|
||||
HIP_CHECK(hipHostMalloc(&Ah, SIZE, 0));
|
||||
HIP_CHECK(hipHostMalloc(&Bh, SIZE, 0));
|
||||
memcpy(Ah, A, SIZE);
|
||||
hipStream_t stream;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
HIP_CHECK(hipMemcpyHtoDAsync(Ad, Ah, SIZE, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_CHECK(hipMemcpyDtoDAsync(Bd, Ad, SIZE, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_CHECK(hipMemcpyDtoHAsync(Bh, Bd, SIZE, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
REQUIRE(Ah[10] == Bh[10]);
|
||||
delete[] A;
|
||||
delete[] B;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (c) 2023 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.
|
||||
*/
|
||||
#include <hip_test_common.hh>
|
||||
#define N 1024
|
||||
constexpr char memsetval = 'b';
|
||||
|
||||
TEST_CASE("Unit_hipMemsetD8_Functional") {
|
||||
size_t Nbytes = N * sizeof(char);
|
||||
char* A_h = new char[Nbytes];;
|
||||
|
||||
hipDeviceptr_t A_d;
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
|
||||
HIP_CHECK(hipMemsetD8(A_d, memsetval, Nbytes));
|
||||
|
||||
HIP_CHECK(hipMemcpy(A_h, reinterpret_cast<void*>(A_d), Nbytes,
|
||||
hipMemcpyDeviceToHost));
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
REQUIRE(A_h[i] == memsetval);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipFree(reinterpret_cast<void*>(A_d)));
|
||||
delete[] A_h;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,18 @@ set(TEST_SRC
|
||||
syncthreadscount.cc
|
||||
syncthreadsor.cc
|
||||
Atomic_func.cc
|
||||
DoublePrecisionIntrinsics.cc
|
||||
DoublePrecisionMathDevice.cc
|
||||
DoublePrecisionMathHost.cc
|
||||
FloatMathPrecise.cc
|
||||
IntegerIntrinsics.cc
|
||||
SinglePrecisionIntrinsics.cc
|
||||
SinglePrecisionMathDevice.cc
|
||||
SinglePrecisionMathHost.cc
|
||||
SimpleAtomicsTest.cc
|
||||
hipTestAtomicAdd.cc
|
||||
hipStdComplex.cc
|
||||
hipTestClock.cc
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__device__ void double_precision_intrinsics() {
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__dadd_rd(0.0, 1.0);
|
||||
#endif
|
||||
__dadd_rn(0.0, 1.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__dadd_ru(0.0, 1.0);
|
||||
__dadd_rz(0.0, 1.0);
|
||||
__ddiv_rd(0.0, 1.0);
|
||||
#endif
|
||||
__ddiv_rn(0.0, 1.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__ddiv_ru(0.0, 1.0);
|
||||
__ddiv_rz(0.0, 1.0);
|
||||
__dmul_rd(1.0, 2.0);
|
||||
#endif
|
||||
__dmul_rn(1.0, 2.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__dmul_ru(1.0, 2.0);
|
||||
__dmul_rz(1.0, 2.0);
|
||||
__drcp_rd(2.0);
|
||||
#endif
|
||||
__drcp_rn(2.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__drcp_ru(2.0);
|
||||
__drcp_rz(2.0);
|
||||
__dsqrt_rd(4.0);
|
||||
#endif
|
||||
__dsqrt_rn(4.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__dsqrt_ru(4.0);
|
||||
__dsqrt_rz(4.0);
|
||||
__dsub_rd(2.0, 1.0);
|
||||
#endif
|
||||
__dsub_rn(2.0, 1.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__dsub_ru(2.0, 1.0);
|
||||
__dsub_rz(2.0, 1.0);
|
||||
__fma_rd(1.0, 2.0, 3.0);
|
||||
#endif
|
||||
__fma_rn(1.0, 2.0, 3.0);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fma_ru(1.0, 2.0, 3.0);
|
||||
__fma_rz(1.0, 2.0, 3.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
__global__ void compileDoublePrecisionIntrinsics(int) {
|
||||
double_precision_intrinsics();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_DoublePrecisionIntrinsics") {
|
||||
hipLaunchKernelGGL(compileDoublePrecisionIntrinsics, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__device__ void double_precision_math_functions() {
|
||||
int iX;
|
||||
double fX, fY;
|
||||
|
||||
acos(1.0);
|
||||
acosh(1.0);
|
||||
asin(0.0);
|
||||
asinh(0.0);
|
||||
atan(0.0);
|
||||
atan2(0.0, 1.0);
|
||||
atanh(0.0);
|
||||
cbrt(0.0);
|
||||
ceil(0.0);
|
||||
copysign(1.0, -2.0);
|
||||
cos(0.0);
|
||||
cosh(0.0);
|
||||
cospi(0.0);
|
||||
cyl_bessel_i0(0.0);
|
||||
cyl_bessel_i1(0.0);
|
||||
erf(0.0);
|
||||
erfc(0.0);
|
||||
erfcinv(2.0);
|
||||
erfcx(0.0);
|
||||
erfinv(1.0);
|
||||
exp(0.0);
|
||||
exp10(0.0);
|
||||
exp2(0.0);
|
||||
expm1(0.0);
|
||||
fabs(1.0);
|
||||
fdim(1.0, 0.0);
|
||||
floor(0.0);
|
||||
fma(1.0, 2.0, 3.0);
|
||||
fmax(0.0, 0.0);
|
||||
fmin(0.0, 0.0);
|
||||
fmod(0.0, 1.0);
|
||||
frexp(0.0, &iX);
|
||||
hypot(1.0, 0.0);
|
||||
ilogb(1.0);
|
||||
isfinite(0.0);
|
||||
isinf(0.0);
|
||||
isnan(0.0);
|
||||
j0(0.0);
|
||||
j1(0.0);
|
||||
jn(-1.0, 1.0);
|
||||
ldexp(0.0, 0);
|
||||
lgamma(1.0);
|
||||
llrint(0.0);
|
||||
llround(0.0);
|
||||
log(1.0);
|
||||
log10(1.0);
|
||||
log1p(-1.0);
|
||||
log2(1.0);
|
||||
logb(1.0);
|
||||
lrint(0.0);
|
||||
lround(0.0);
|
||||
modf(0.0, &fX);
|
||||
nan("1");
|
||||
nearbyint(0.0);
|
||||
nextafter(0.0, 0.0);
|
||||
fX = 1.0;
|
||||
norm(1, &fX);
|
||||
norm3d(1.0, 0.0, 0.0);
|
||||
norm4d(1.0, 0.0, 0.0, 0.0);
|
||||
normcdf(0.0);
|
||||
normcdfinv(1.0);
|
||||
pow(1.0, 0.0);
|
||||
rcbrt(1.0);
|
||||
remainder(2.0, 1.0);
|
||||
remquo(1.0, 2.0, &iX);
|
||||
rhypot(0.0, 1.0);
|
||||
rint(1.0);
|
||||
fX = 1.0;
|
||||
rnorm(1, &fX);
|
||||
rnorm3d(0.0, 0.0, 1.0);
|
||||
rnorm4d(0.0, 0.0, 0.0, 1.0);
|
||||
round(0.0);
|
||||
rsqrt(1.0);
|
||||
scalbln(0.0, 1);
|
||||
scalbn(0.0, 1);
|
||||
signbit(1.0);
|
||||
sin(0.0);
|
||||
#if HT_AMD
|
||||
// NV A100 has a bug in sincos(), so temporarily disbale it
|
||||
sincos(0.0, &fX, &fY);
|
||||
#endif
|
||||
sincospi(0.0, &fX, &fY);
|
||||
sinh(0.0);
|
||||
sinpi(0.0);
|
||||
sqrt(0.0);
|
||||
tan(0.0);
|
||||
tanh(0.0);
|
||||
tgamma(2.0);
|
||||
trunc(0.0);
|
||||
y0(1.0);
|
||||
y1(1.0);
|
||||
yn(1, 1.0);
|
||||
}
|
||||
|
||||
__global__ void compileDoublePrecisionMathOnDevice(int) {
|
||||
double_precision_math_functions();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_DoublePrecisionMathDevice") {
|
||||
hipLaunchKernelGGL(compileDoublePrecisionMathOnDevice, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (c) 2023 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 <cmath>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__host__ static void double_precision_math_functions() {
|
||||
int iX;
|
||||
double fX, fY;
|
||||
|
||||
acos(1.0);
|
||||
acosh(1.0);
|
||||
asin(0.0);
|
||||
asinh(0.0);
|
||||
atan(0.0);
|
||||
atan2(0.0, 1.0);
|
||||
atanh(0.0);
|
||||
cbrt(0.0);
|
||||
ceil(0.0);
|
||||
copysign(1.0, -2.0);
|
||||
cos(0.0);
|
||||
cosh(0.0);
|
||||
erf(0.0);
|
||||
erfc(0.0);
|
||||
exp(0.0);
|
||||
#ifdef __unix__
|
||||
exp10(0.0);
|
||||
#endif
|
||||
exp2(0.0);
|
||||
expm1(0.0);
|
||||
fabs(1.0);
|
||||
fdim(1.0, 0.0);
|
||||
floor(0.0);
|
||||
fma(1.0, 2.0, 3.0);
|
||||
fmax(0.0, 0.0);
|
||||
fmin(0.0, 0.0);
|
||||
fmod(0.0, 1.0);
|
||||
frexp(0.0, &iX);
|
||||
hypot(1.0, 0.0);
|
||||
ilogb(1.0);
|
||||
std::isfinite(0.0);
|
||||
std::isinf(0.0);
|
||||
std::isnan(0.0);
|
||||
#ifdef __unix__
|
||||
j0(0.0);
|
||||
j1(0.0);
|
||||
jn(-1.0, 1.0);
|
||||
#elif _WIN64
|
||||
_j0(0.0);
|
||||
_j1(0.0);
|
||||
_jn(-1.0, 1.0);
|
||||
#endif
|
||||
ldexp(0.0, 0);
|
||||
llrint(0.0);
|
||||
llround(0.0);
|
||||
log(1.0);
|
||||
log10(1.0);
|
||||
log1p(-1.0);
|
||||
log2(1.0);
|
||||
logb(1.0);
|
||||
lrint(0.0);
|
||||
lround(0.0);
|
||||
modf(0.0, &fX);
|
||||
nan("1");
|
||||
nearbyint(0.0);
|
||||
fX = 1.0;
|
||||
pow(1.0, 0.0);
|
||||
remainder(2.0, 1.0);
|
||||
remquo(1.0, 2.0, &iX);
|
||||
rint(1.0);
|
||||
round(0.0);
|
||||
scalbln(0.0, 1);
|
||||
scalbn(0.0, 1);
|
||||
std::signbit(1.0);
|
||||
sin(0.0);
|
||||
#ifdef _unix__
|
||||
sincos(0.0, &fX, &fY);
|
||||
#endif
|
||||
sinh(0.0);
|
||||
sqrt(0.0);
|
||||
tan(0.0);
|
||||
tanh(0.0);
|
||||
tgamma(2.0);
|
||||
trunc(0.0);
|
||||
#ifdef __unix__
|
||||
y0(1.0);
|
||||
y1(1.0);
|
||||
yn(1, 1.0);
|
||||
#elif _WIN64
|
||||
_y0(1.0);
|
||||
_y1(1.0);
|
||||
_yn(1, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_DoublePrecisionMathHost") {
|
||||
double_precision_math_functions();
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip/math_functions.h>
|
||||
|
||||
__device__ void FloatMathPrecise() {
|
||||
int iX;
|
||||
float fX, fY;
|
||||
|
||||
acosf(1.0f);
|
||||
acoshf(1.0f);
|
||||
asinf(0.0f);
|
||||
asinhf(0.0f);
|
||||
atan2f(0.0f, 1.0f);
|
||||
atanf(0.0f);
|
||||
atanhf(0.0f);
|
||||
cbrtf(0.0f);
|
||||
fX = ceilf(0.0f);
|
||||
fX = copysignf(1.0f, -2.0f);
|
||||
cosf(0.0f);
|
||||
coshf(0.0f);
|
||||
cospif(0.0f);
|
||||
cyl_bessel_i0f(0.0f);
|
||||
cyl_bessel_i1f(0.0f);
|
||||
erfcf(0.0f);
|
||||
erfcinvf(2.0f);
|
||||
erfcxf(0.0f);
|
||||
erff(0.0f);
|
||||
erfinvf(1.0f);
|
||||
exp10f(0.0f);
|
||||
exp2f(0.0f);
|
||||
expf(0.0f);
|
||||
expm1f(0.0f);
|
||||
fX = fabsf(1.0f);
|
||||
fdimf(1.0f, 0.0f);
|
||||
fdividef(0.0f, 1.0f);
|
||||
fX = floorf(0.0f);
|
||||
fmaf(1.0f, 2.0f, 3.0f);
|
||||
fX = fmaxf(0.0f, 0.0f);
|
||||
fX = fminf(0.0f, 0.0f);
|
||||
fmodf(0.0f, 1.0f);
|
||||
frexpf(0.0f, &iX);
|
||||
hypotf(1.0f, 0.0f);
|
||||
ilogbf(1.0f);
|
||||
isfinite(0.0f);
|
||||
fX = isinf(0.0f);
|
||||
fX = isnan(0.0f);
|
||||
j0f(0.0f);
|
||||
j1f(0.0f);
|
||||
jnf(-1.0f, 1.0f);
|
||||
ldexpf(0.0f, 0);
|
||||
lgammaf(1.0f);
|
||||
llrintf(0.0f);
|
||||
llroundf(0.0f);
|
||||
log10f(1.0f);
|
||||
log1pf(-1.0f);
|
||||
log2f(1.0f);
|
||||
logbf(1.0f);
|
||||
logf(1.0f);
|
||||
lrintf(0.0f);
|
||||
lroundf(0.0f);
|
||||
modff(0.0f, &fX);
|
||||
fX = nanf("1");
|
||||
fX = nearbyintf(0.0f);
|
||||
nextafterf(0.0f, 0.0f);
|
||||
norm3df(1.0f, 0.0f, 0.0f);
|
||||
norm4df(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
normcdff(0.0f);
|
||||
normcdfinvf(1.0f);
|
||||
fX = 1.0f;
|
||||
normf(1, &fX);
|
||||
powf(1.0f, 0.0f);
|
||||
rcbrtf(1.0f);
|
||||
remainderf(2.0f, 1.0f);
|
||||
remquof(1.0f, 2.0f, &iX);
|
||||
rhypotf(0.0f, 1.0f);
|
||||
fY = rintf(1.0f);
|
||||
rnorm3df(0.0f, 0.0f, 1.0f);
|
||||
rnorm4df(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
fX = 1.0f;
|
||||
rnormf(1, &fX);
|
||||
fY = roundf(0.0f);
|
||||
rsqrtf(1.0f);
|
||||
scalblnf(0.0f, 1);
|
||||
scalbnf(0.0f, 1);
|
||||
signbit(1.0f);
|
||||
sincosf(0.0f, &fX, &fY);
|
||||
sincospif(0.0f, &fX, &fY);
|
||||
sinf(0.0f);
|
||||
sinhf(0.0f);
|
||||
sinpif(0.0f);
|
||||
sqrtf(0.0f);
|
||||
tanf(0.0f);
|
||||
tanhf(0.0f);
|
||||
tgammaf(2.0f);
|
||||
fY = truncf(0.0f);
|
||||
y0f(1.0f);
|
||||
y1f(1.0f);
|
||||
ynf(1, 1.0f);
|
||||
}
|
||||
|
||||
__global__ void CompileFloatMathPrecise(int) {
|
||||
FloatMathPrecise();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_FloatMathPrecise") {
|
||||
hipLaunchKernelGGL(CompileFloatMathPrecise, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip/device_functions.h>
|
||||
#include <algorithm>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__device__ void integer_intrinsics() {
|
||||
__brev((unsigned int)10);
|
||||
__brevll((uint64_t)10);
|
||||
__byte_perm((unsigned int)0, (unsigned int)0, 0);
|
||||
__clz(static_cast<int>(10));
|
||||
__clzll((int64_t)10);
|
||||
__ffs(static_cast<int>(10));
|
||||
__ffsll((long long)(10)); // NOLINT
|
||||
__funnelshift_l((unsigned int)0xfacefeed, (unsigned int)0xdeadbeef, 0);
|
||||
__funnelshift_lc((unsigned int)0xfacefeed, (unsigned int)0xdeadbeef, 0);
|
||||
__funnelshift_r((unsigned int)0xfacefeed, (unsigned int)0xdeadbeef, 0);
|
||||
__funnelshift_rc((unsigned int)0xfacefeed, (unsigned int)0xdeadbeef, 0);
|
||||
__hadd(static_cast<int>(1), static_cast<int>(3));
|
||||
__mul24(static_cast<int>(1), static_cast<int>(2));
|
||||
__mul64hi((int64_t)1, (int64_t)2);
|
||||
__mulhi(static_cast<int>(1), static_cast<int>(2));
|
||||
__popc((unsigned int)4);
|
||||
__popcll((uint64_t)4);
|
||||
int a = min(static_cast<int>(4), static_cast<int>(5));
|
||||
int b = max(static_cast<int>(4), static_cast<int>(5));
|
||||
__rhadd(static_cast<int>(1), static_cast<int>(2));
|
||||
__sad(static_cast<int>(1), static_cast<int>(2), 0);
|
||||
__uhadd((unsigned int)1, (unsigned int)3);
|
||||
__umul24((unsigned int)1, (unsigned int)2);
|
||||
__umul64hi((uint64_t)1, (uint64_t)2);
|
||||
__umulhi((unsigned int)1, (unsigned int)2);
|
||||
__urhadd((unsigned int)1, (unsigned int)2);
|
||||
__usad((unsigned int)1, (unsigned int)2, 0);
|
||||
|
||||
assert(1);
|
||||
}
|
||||
|
||||
__global__ void compileIntegerIntrinsics(int) {
|
||||
integer_intrinsics();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_IntegerIntrinsics") {
|
||||
hipLaunchKernelGGL(compileIntegerIntrinsics, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
Copyright (c) 2023 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 <string.h>
|
||||
#include <math.h>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace std;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Auto-Verification Code
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool verifyBitwise(...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename enable_if<is_integral<T>{}>::type* = nullptr>
|
||||
bool verifyBitwise(T* gpuData, int len) {
|
||||
// Atomic and
|
||||
T val = 0xff;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
// 9th element should be 1
|
||||
val &= (2 * i + 7);
|
||||
}
|
||||
REQUIRE(val == gpuData[8]);
|
||||
|
||||
// atomic Or
|
||||
val = 0;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
// 10th element should be 0xff
|
||||
val |= (1 << i);
|
||||
}
|
||||
REQUIRE(val == gpuData[9]);
|
||||
|
||||
// atomic Xor
|
||||
val = 0xff;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
// 11th element should be 0xff
|
||||
val ^= i;
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[10]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool verifySub(...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<
|
||||
typename T,
|
||||
typename enable_if<
|
||||
is_same<T, int>{} || is_same<T, unsigned int>{}>::type* = nullptr>
|
||||
bool verifySub(T* gpuData, int len) {
|
||||
T val = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
val -= 10;
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool verifyExch(...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename enable_if<!is_same<T, double> {}>::type* = nullptr> // NOLINT
|
||||
bool computeExchExch(T* gpuData, int len) {
|
||||
T val = 0;
|
||||
|
||||
for (T i = 0; i < len; ++i) {
|
||||
if (i == gpuData[2]) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VerifyIntegral(...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename enable_if<is_integral<T>{}>::type* = nullptr>
|
||||
bool VerifyIntegral(T* gpuData, int len) {
|
||||
// atomic Max
|
||||
T val = 0;
|
||||
for (T i = 0; i < len; ++i) {
|
||||
// fourth element should be len-1
|
||||
val = max(val, i);
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[3]);
|
||||
|
||||
// atomic Min
|
||||
val = 1 << 8;
|
||||
|
||||
for (T i = 0; i < len; ++i) {
|
||||
val = min(val, i);
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[4]);
|
||||
|
||||
// atomic Inc
|
||||
int limit = 17;
|
||||
val = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
val = (val >= limit) ? 0 : val + 1;
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[5]);
|
||||
|
||||
// atomic Dec
|
||||
limit = 137;
|
||||
val = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
val = ((val == 0) || (val > limit)) ? limit : val - 1;
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[6]);
|
||||
|
||||
// atomic CAS
|
||||
for (T i = 0; i < len; ++i) {
|
||||
// eighth element should be a member of [0, len)
|
||||
if (i == gpuData[7]) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return verifyBitwise(gpuData, len) && verifySub(gpuData, len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool verifyData(T* gpuData, int len) {
|
||||
T val = 0;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
val += 10;
|
||||
}
|
||||
|
||||
REQUIRE(val == gpuData[0]);
|
||||
return VerifyIntegral(gpuData, len) && verifyExch(gpuData, len);
|
||||
}
|
||||
|
||||
__device__
|
||||
void testKernelExch(...) {}
|
||||
|
||||
template<typename T, typename enable_if<!is_same<T, double>{}>::type* = nullptr>
|
||||
__device__
|
||||
void testKernelExch(T* g_odata) {
|
||||
// access thread id
|
||||
const T tid = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
|
||||
// Atomic exchange
|
||||
atomicExch(&g_odata[2], tid);
|
||||
}
|
||||
|
||||
__device__
|
||||
void testKernelSub(...) {}
|
||||
|
||||
template<
|
||||
typename T,
|
||||
typename enable_if<
|
||||
is_same<T, int>{} || is_same<T, unsigned int>{}>::type* = nullptr>
|
||||
__device__
|
||||
void testKernelSub(T* g_odata) {
|
||||
// Atomic subtraction (final should be 0)
|
||||
atomicSub(&g_odata[1], 10);
|
||||
}
|
||||
|
||||
__device__
|
||||
void testKernelIntegral(...) {}
|
||||
|
||||
template<typename T, typename enable_if<is_integral<T>{}>::type* = nullptr>
|
||||
__device__
|
||||
void testKernelIntegral(T* g_odata) {
|
||||
// access thread id
|
||||
const T tid = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
|
||||
// Atomic maximum
|
||||
atomicMax(&g_odata[3], tid);
|
||||
|
||||
// Atomic minimum
|
||||
atomicMin(&g_odata[4], tid);
|
||||
|
||||
// Atomic increment (modulo 17+1)
|
||||
atomicInc((unsigned int*)&g_odata[5], 17);
|
||||
|
||||
// Atomic decrement
|
||||
atomicDec((unsigned int*)&g_odata[6], 137);
|
||||
|
||||
// Atomic compare-and-swap
|
||||
atomicCAS(&g_odata[7], tid - 1, tid);
|
||||
|
||||
// Bitwise atomic instructions
|
||||
|
||||
// Atomic AND
|
||||
atomicAnd(&g_odata[8], 2 * tid + 7);
|
||||
|
||||
// Atomic OR
|
||||
atomicOr(&g_odata[9], 1 << tid);
|
||||
|
||||
// Atomic XOR
|
||||
atomicXor(&g_odata[10], tid);
|
||||
|
||||
testKernelSub(g_odata);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__global__ void testKernel(T* g_odata) {
|
||||
// Atomic addition
|
||||
atomicAdd(&g_odata[0], 10);
|
||||
testKernelIntegral(g_odata);
|
||||
testKernelExch(g_odata);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void runTest() {
|
||||
bool testResult = true;
|
||||
unsigned int numThreads = 256;
|
||||
unsigned int numBlocks = 64;
|
||||
unsigned int numData = 11;
|
||||
unsigned int memSize = sizeof(T) * numData;
|
||||
|
||||
// allocate mem for the result on host side
|
||||
T* hOData = reinterpret_cast<T*>(malloc(memSize));
|
||||
|
||||
// initialize the memory
|
||||
for (unsigned int i = 0; i < numData; i++) {
|
||||
hOData[i] = 0;
|
||||
}
|
||||
// To make the AND and XOR tests generate something other than 0...
|
||||
hOData[8] = hOData[10] = 0xff;
|
||||
|
||||
// allocate device memory for result
|
||||
T* dOData;
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&dOData), memSize));
|
||||
// copy host memory to device to initialize to zero
|
||||
HIP_CHECK(hipMemcpy(dOData, hOData, memSize, hipMemcpyHostToDevice));
|
||||
|
||||
// execute the kernel
|
||||
hipLaunchKernelGGL(
|
||||
testKernel, dim3(numBlocks), dim3(numThreads), 0, 0, dOData);
|
||||
|
||||
// Copy result from device to host
|
||||
HIP_CHECK(hipMemcpy(hOData, dOData, memSize, hipMemcpyDeviceToHost));
|
||||
|
||||
// Compute reference solution
|
||||
REQUIRE(testResult == verifyData(hOData, numThreads * numBlocks));
|
||||
|
||||
// Cleanup memory
|
||||
free(hOData);
|
||||
HIP_CHECK(hipFree(dOData));
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_SimpleAtomicsTest") {
|
||||
SECTION("test for int") {
|
||||
runTest<int>();
|
||||
}
|
||||
SECTION("test for unsigned int") {
|
||||
runTest<unsigned int>();
|
||||
}
|
||||
SECTION("test for float") {
|
||||
runTest<float>();
|
||||
}
|
||||
#if HT_AMD
|
||||
SECTION("test for unsigned long long") {
|
||||
runTest<uint64_t>();
|
||||
}
|
||||
SECTION("test for double") {
|
||||
runTest<double>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip/device_functions.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__device__ void single_precision_intrinsics() {
|
||||
float fX, fY;
|
||||
|
||||
__cosf(0.0f);
|
||||
__exp10f(0.0f);
|
||||
__expf(0.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fadd_rd(0.0f, 1.0f);
|
||||
#endif
|
||||
__fadd_rn(0.0f, 1.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fadd_ru(0.0f, 1.0f);
|
||||
__fadd_rz(0.0f, 1.0f);
|
||||
__fdiv_rd(4.0f, 2.0f);
|
||||
#endif
|
||||
__fdiv_rn(4.0f, 2.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fdiv_ru(4.0f, 2.0f);
|
||||
__fdiv_rz(4.0f, 2.0f);
|
||||
#endif
|
||||
__fdividef(4.0f, 2.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fmaf_rd(1.0f, 2.0f, 3.0f);
|
||||
#endif
|
||||
__fmaf_rn(1.0f, 2.0f, 3.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fmaf_ru(1.0f, 2.0f, 3.0f);
|
||||
__fmaf_rz(1.0f, 2.0f, 3.0f);
|
||||
__fmul_rd(1.0f, 2.0f);
|
||||
#endif
|
||||
__fmul_rn(1.0f, 2.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fmul_ru(1.0f, 2.0f);
|
||||
__fmul_rz(1.0f, 2.0f);
|
||||
__frcp_rd(2.0f);
|
||||
#endif
|
||||
__frcp_rn(2.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__frcp_ru(2.0f);
|
||||
__frcp_rz(2.0f);
|
||||
#endif
|
||||
__frsqrt_rn(4.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fsqrt_rd(4.0f);
|
||||
#endif
|
||||
__fsqrt_rn(4.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fsqrt_ru(4.0f);
|
||||
__fsqrt_rz(4.0f);
|
||||
__fsub_rd(2.0f, 1.0f);
|
||||
#endif
|
||||
__fsub_rn(2.0f, 1.0f);
|
||||
#if defined OCML_BASIC_ROUNDED_OPERATIONS
|
||||
__fsub_ru(2.0f, 1.0f);
|
||||
__fsub_rz(2.0f, 1.0f);
|
||||
#endif
|
||||
__log10f(1.0f);
|
||||
__log2f(1.0f);
|
||||
__logf(1.0f);
|
||||
__powf(1.0f, 0.0f);
|
||||
__saturatef(0.1f);
|
||||
__sincosf(0.0f, &fX, &fY);
|
||||
__sinf(0.0f);
|
||||
__tanf(0.0f);
|
||||
}
|
||||
|
||||
__global__ void compileSinglePrecisionIntrinsics(int) {
|
||||
single_precision_intrinsics();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_SinglePrecisionIntrinsics") {
|
||||
hipLaunchKernelGGL(compileSinglePrecisionIntrinsics, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip/math_functions.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__device__ void single_precision_math_functions() {
|
||||
int iX;
|
||||
float fX, fY;
|
||||
|
||||
acosf(1.0f);
|
||||
acoshf(1.0f);
|
||||
asinf(0.0f);
|
||||
asinhf(0.0f);
|
||||
atan2f(0.0f, 1.0f);
|
||||
atanf(0.0f);
|
||||
atanhf(0.0f);
|
||||
cbrtf(0.0f);
|
||||
ceilf(0.0f);
|
||||
copysignf(1.0f, -2.0f);
|
||||
cosf(0.0f);
|
||||
coshf(0.0f);
|
||||
cospif(0.0f);
|
||||
erfcf(0.0f);
|
||||
erfcinvf(2.0f);
|
||||
erfcxf(0.0f);
|
||||
erff(0.0f);
|
||||
erfinvf(1.0f);
|
||||
exp10f(0.0f);
|
||||
exp2f(0.0f);
|
||||
expf(0.0f);
|
||||
expm1f(0.0f);
|
||||
fabsf(1.0f);
|
||||
fdimf(1.0f, 0.0f);
|
||||
fdividef(0.0f, 1.0f);
|
||||
floorf(0.0f);
|
||||
fmaf(1.0f, 2.0f, 3.0f);
|
||||
fmaxf(0.0f, 0.0f);
|
||||
fminf(0.0f, 0.0f);
|
||||
fmodf(0.0f, 1.0f);
|
||||
frexpf(0.0f, &iX);
|
||||
hypotf(1.0f, 0.0f);
|
||||
ilogbf(1.0f);
|
||||
isfinite(0.0f);
|
||||
isinf(0.0f);
|
||||
isnan(0.0f);
|
||||
j0f(0.0f);
|
||||
j1f(0.0f);
|
||||
jnf(-1.0f, 1.0f);
|
||||
ldexpf(0.0f, 0);
|
||||
llrintf(0.0f);
|
||||
llroundf(0.0f);
|
||||
log10f(1.0f);
|
||||
log1pf(-1.0f);
|
||||
log2f(1.0f);
|
||||
logbf(1.0f);
|
||||
logf(1.0f);
|
||||
lrintf(0.0f);
|
||||
lroundf(0.0f);
|
||||
nanf("1");
|
||||
nearbyintf(0.0f);
|
||||
norm3df(1.0f, 0.0f, 0.0f);
|
||||
norm4df(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
normcdff(0.0f);
|
||||
normcdfinvf(1.0f);
|
||||
fX = 1.0f;
|
||||
normf(1, &fX);
|
||||
powf(1.0f, 0.0f);
|
||||
remainderf(2.0f, 1.0f);
|
||||
rhypotf(0.0f, 1.0f);
|
||||
rintf(1.0f);
|
||||
rnorm3df(0.0f, 0.0f, 1.0f);
|
||||
rnorm4df(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
fX = 1.0f;
|
||||
rnormf(1, &fX);
|
||||
roundf(0.0f);
|
||||
rsqrtf(1.0f);
|
||||
signbit(1.0f);
|
||||
sincosf(0.0f, &fX, &fY);
|
||||
sincospif(0.0f, &fX, &fY);
|
||||
sinf(0.0f);
|
||||
sinhf(0.0f);
|
||||
sinpif(0.0f);
|
||||
sqrtf(0.0f);
|
||||
tanf(0.0f);
|
||||
tanhf(0.0f);
|
||||
tgammaf(2.0f);
|
||||
truncf(0.0f);
|
||||
y0f(1.0f);
|
||||
y1f(1.0f);
|
||||
ynf(1, 1.0f);
|
||||
}
|
||||
|
||||
__global__ void compileSinglePrecisionMathOnDevice(int) {
|
||||
single_precision_math_functions();
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_SinglePrecisionMathDevice") {
|
||||
hipLaunchKernelGGL(compileSinglePrecisionMathOnDevice, dim3(1, 1, 1),
|
||||
dim3(1, 1, 1), 0, 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2023 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 <cmath>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
__host__ static void single_precision_math_functions() {
|
||||
int iX;
|
||||
float fX, fY;
|
||||
|
||||
acosf(1.0f);
|
||||
acoshf(1.0f);
|
||||
asinf(0.0f);
|
||||
asinhf(0.0f);
|
||||
atan2f(0.0f, 1.0f);
|
||||
atanf(0.0f);
|
||||
atanhf(0.0f);
|
||||
cbrtf(0.0f);
|
||||
ceilf(0.0f);
|
||||
copysignf(1.0f, -2.0f);
|
||||
cosf(0.0f);
|
||||
coshf(0.0f);
|
||||
erfcf(0.0f);
|
||||
erff(0.0f);
|
||||
#ifdef __unix__
|
||||
exp10f(0.0f);
|
||||
#endif
|
||||
exp2f(0.0f);
|
||||
expf(0.0f);
|
||||
expm1f(0.0f);
|
||||
fabsf(1.0f);
|
||||
fdimf(1.0f, 0.0f);
|
||||
floorf(0.0f);
|
||||
fmaf(1.0f, 2.0f, 3.0f);
|
||||
fmaxf(0.0f, 0.0f);
|
||||
fminf(0.0f, 0.0f);
|
||||
fmodf(0.0f, 1.0f);
|
||||
frexpf(0.0f, &iX);
|
||||
hypotf(1.0f, 0.0f);
|
||||
ilogbf(1.0f);
|
||||
std::isfinite(0.0f);
|
||||
std::isinf(0.0f);
|
||||
std::isnan(0.0f);
|
||||
#ifdef __unix__
|
||||
j0f(0.0f);
|
||||
j1f(0.0f);
|
||||
jnf(-1.0f, 1.0f);
|
||||
#endif
|
||||
ldexpf(0.0f, 0);
|
||||
lgammaf(1.0f);
|
||||
llrintf(0.0f);
|
||||
llroundf(0.0f);
|
||||
log10f(1.0f);
|
||||
log1pf(-1.0f);
|
||||
log2f(1.0f);
|
||||
logbf(1.0f);
|
||||
logf(1.0f);
|
||||
lrintf(0.0f);
|
||||
lroundf(0.0f);
|
||||
modff(0.0f, &fX);
|
||||
nanf("1");
|
||||
nearbyintf(0.0f);
|
||||
powf(1.0f, 0.0f);
|
||||
remainderf(2.0f, 1.0f);
|
||||
remquof(1.0f, 2.0f, &iX);
|
||||
rintf(1.0f);
|
||||
#if HT_AMD
|
||||
fX = 1.0f;
|
||||
#endif
|
||||
roundf(0.0f);
|
||||
/// rsqrtf(1.0f);
|
||||
scalblnf(0.0f, 1);
|
||||
scalbnf(0.0f, 1);
|
||||
std::signbit(1.0f);
|
||||
#ifdef __unix__
|
||||
sincosf(0.0f, &fX, &fY);
|
||||
#endif
|
||||
sinf(0.0f);
|
||||
sinhf(0.0f);
|
||||
sqrtf(0.0f);
|
||||
tanf(0.0f);
|
||||
tanhf(0.0f);
|
||||
tgammaf(2.0f);
|
||||
truncf(0.0f);
|
||||
#ifdef __unix__
|
||||
y0f(1.0f);
|
||||
y1f(1.0f);
|
||||
ynf(1, 1.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_SinglePrecisionMathHost") {
|
||||
single_precision_math_functions();
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright (c) 2023 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, INNCLUDING 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 ANNY 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.
|
||||
*/
|
||||
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <complex>
|
||||
|
||||
// Tolerance for error
|
||||
const double tolerance = 1e-6;
|
||||
const bool verbose = false;
|
||||
|
||||
#define LEN 64
|
||||
|
||||
#define ALL_FUN \
|
||||
OP(add) \
|
||||
OP(sub) \
|
||||
OP(mul) \
|
||||
OP(div) \
|
||||
OP(abs) \
|
||||
OP(arg) \
|
||||
OP(sin) \
|
||||
OP(cos)
|
||||
|
||||
#define OP(x) CK_##x,
|
||||
enum CalcKind {
|
||||
ALL_FUN
|
||||
};
|
||||
#undef OP
|
||||
|
||||
#define OP(x) case CK_##x: return #x;
|
||||
std::string getName(enum CalcKind CK) {
|
||||
switch (CK) {
|
||||
ALL_FUN
|
||||
}
|
||||
return ""; // To prevent compile warning
|
||||
}
|
||||
#undef OP
|
||||
|
||||
// Calculates function.
|
||||
// If the function has one argument, B is ignored.
|
||||
// If the function returns real number, converts it to a complex number.
|
||||
#define ONE_ARG(func) \
|
||||
case CK_##func: \
|
||||
return std::complex<FloatT>(func(A));
|
||||
|
||||
template<typename FloatT>
|
||||
__device__ __host__ std::complex<FloatT> calc(std::complex<FloatT> A,
|
||||
std::complex<FloatT> B,
|
||||
enum CalcKind CK) {
|
||||
switch (CK) {
|
||||
case CK_add:
|
||||
return A + B;
|
||||
case CK_sub:
|
||||
return A - B;
|
||||
case CK_mul:
|
||||
return A * B;
|
||||
case CK_div:
|
||||
return A / B;
|
||||
|
||||
ONE_ARG(abs)
|
||||
ONE_ARG(arg)
|
||||
ONE_ARG(sin)
|
||||
ONE_ARG(cos)
|
||||
}
|
||||
return A; // To prevent compile warning
|
||||
}
|
||||
|
||||
template<typename FloatT>
|
||||
__global__ void kernel(std::complex<FloatT>* A,
|
||||
std::complex<FloatT>* B, std::complex<FloatT>* C,
|
||||
enum CalcKind CK) {
|
||||
int tx = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
C[tx] = calc<FloatT>(A[tx], B[tx], CK);
|
||||
}
|
||||
|
||||
template<typename FloatT>
|
||||
void test() {
|
||||
typedef std::complex<FloatT> ComplexT;
|
||||
|
||||
ComplexT *A, *Ad, *B, *Bd, *C, *Cd, *D;
|
||||
A = new ComplexT[LEN];
|
||||
B = new ComplexT[LEN];
|
||||
C = new ComplexT[LEN];
|
||||
D = new ComplexT[LEN];
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Ad), sizeof(ComplexT)*LEN));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Bd), sizeof(ComplexT)*LEN));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Cd), sizeof(ComplexT)*LEN));
|
||||
|
||||
for (uint32_t i = 0; i < LEN; i++) {
|
||||
A[i] = ComplexT((i + 1) * 1.0f, (i + 2) * 1.0f);
|
||||
B[i] = A[i];
|
||||
C[i] = A[i];
|
||||
}
|
||||
HIP_CHECK(hipMemcpy(Ad, A, sizeof(ComplexT)*LEN, hipMemcpyHostToDevice));
|
||||
HIP_CHECK(hipMemcpy(Bd, B, sizeof(ComplexT)*LEN, hipMemcpyHostToDevice));
|
||||
|
||||
// Run kernel for a calculation kind and verify by comparing with host
|
||||
// calculation result. Returns false if fails.
|
||||
auto test_fun = [&](enum CalcKind CK) {
|
||||
hipLaunchKernelGGL(kernel<FloatT>, dim3(1), dim3(LEN), 0, 0,
|
||||
Ad, Bd, Cd, CK);
|
||||
HIP_CHECK(hipMemcpy(C, Cd, sizeof(ComplexT)*LEN, hipMemcpyDeviceToHost));
|
||||
for (int i = 0; i < LEN; i++) {
|
||||
ComplexT Expected = calc(A[i], B[i], CK);
|
||||
FloatT error = abs(C[i] - Expected);
|
||||
if (abs(Expected) > tolerance)
|
||||
error /= abs(Expected);
|
||||
bool pass = error < tolerance;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
#define OP(x) assert(test_fun(CK_##x));
|
||||
ALL_FUN
|
||||
#undef OP
|
||||
|
||||
HIP_CHECK(hipFree(Ad));
|
||||
HIP_CHECK(hipFree(Bd));
|
||||
HIP_CHECK(hipFree(Cd));
|
||||
delete[] A;
|
||||
delete[] B;
|
||||
delete[] C;
|
||||
delete[] D;
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_StdComplex") {
|
||||
SECTION("Test run with float") {
|
||||
test<float>();
|
||||
}
|
||||
SECTION("Test run with double") {
|
||||
test<double>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
(TestCase 1)::
|
||||
1) Execute atomicAdd in multi threaded scenario by diverging the data across
|
||||
multiple threads and validate the output at the end of all operations.
|
||||
2) Execute atomicAddNoRet in multi threaded scenario by diverging the data
|
||||
across multiple threads and validate the output at the end of all operations.
|
||||
(TestCase 2)::
|
||||
3) Execute atomicAdd API and validate the result.
|
||||
4) Execute atomicAddNoRet API and validate the result.
|
||||
(TestCase 3)::
|
||||
5) atomicadd/NoRet negative scenarios (TBD).
|
||||
*/
|
||||
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
/*
|
||||
* Defines initial and increment values
|
||||
*/
|
||||
#define INCREMENT_VALUE 10
|
||||
#define INT_INITIAL_VALUE 10
|
||||
#define FLOAT_INITIAL_VALUE 10.50
|
||||
#define DOUBLE_INITIAL_VALUE 200.12
|
||||
#define LONG_INITIAL_VALUE 10000
|
||||
#define UNSIGNED_INITIAL_VALUE 20
|
||||
|
||||
#if HT_NVIDIA
|
||||
// atomicAddNoRet is unavailable in cuda
|
||||
template <typename T>
|
||||
__device__ void atomicAddNoRet(T* x, int y) {
|
||||
atomicAdd(x, static_cast<T>(y));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool p_atomicNoRet = false;
|
||||
|
||||
template <typename T>
|
||||
__global__ void atomicnoret_manywaves(T* C_d) {
|
||||
size_t tid = (blockIdx.x * blockDim.x + threadIdx.x);
|
||||
atomicAddNoRet(C_d, INCREMENT_VALUE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void atomic_manywaves(T* C_d) {
|
||||
size_t tid = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x);
|
||||
atomicAdd(C_d, INCREMENT_VALUE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void atomicnoret_simple(T* C_d) {
|
||||
atomicAddNoRet(C_d, INCREMENT_VALUE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void atomic_simple(T* C_d) {
|
||||
atomicAdd(C_d, INCREMENT_VALUE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool atomictest_manywaves(const T& initial_val) {
|
||||
unsigned int ThreadsperBlock = 10;
|
||||
unsigned int numBlocks = 1;
|
||||
T memSize = sizeof(T);
|
||||
T* hOData = reinterpret_cast<T*>(malloc(memSize));
|
||||
*hOData = initial_val;
|
||||
T* dOData;
|
||||
HIP_CHECK(hipMalloc(&dOData, memSize));
|
||||
// copy host memory to device to initialize to zero
|
||||
HIP_CHECK(hipMemcpy(dOData, hOData, memSize, hipMemcpyHostToDevice));
|
||||
|
||||
// execute the kernel
|
||||
hipLaunchKernelGGL(atomic_manywaves, dim3(numBlocks),
|
||||
dim3(ThreadsperBlock), 0, 0, dOData);
|
||||
|
||||
// Copy result from device to host
|
||||
HIP_CHECK(hipMemcpy(hOData, dOData, memSize, hipMemcpyDeviceToHost));
|
||||
REQUIRE(hOData[0] == initial_val+
|
||||
(INCREMENT_VALUE*(ThreadsperBlock*numBlocks)));
|
||||
|
||||
// Cleanup memory
|
||||
free(hOData);
|
||||
HIP_CHECK(hipFree(dOData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool atomictestnoret_manywaves(const T& initial_val) {
|
||||
unsigned int ThreadsperBlock = 10;
|
||||
unsigned int numBlocks = 1;
|
||||
T memSize = sizeof(T);
|
||||
T* hOData = reinterpret_cast<T*>(malloc(memSize));
|
||||
*hOData = initial_val;
|
||||
T* dOData;
|
||||
HIP_CHECK(hipMalloc(&dOData, memSize));
|
||||
// copy host memory to device to initialize to zero
|
||||
HIP_CHECK(hipMemcpy(dOData, hOData, memSize, hipMemcpyHostToDevice));
|
||||
|
||||
// execute the kernel
|
||||
hipLaunchKernelGGL(atomicnoret_manywaves, dim3(numBlocks),
|
||||
dim3(ThreadsperBlock), 0, 0, dOData);
|
||||
|
||||
// Copy result from device to host
|
||||
HIP_CHECK(hipMemcpy(hOData, dOData, memSize, hipMemcpyDeviceToHost));
|
||||
REQUIRE(hOData[0] == initial_val+
|
||||
(INCREMENT_VALUE*(ThreadsperBlock*numBlocks)));
|
||||
|
||||
// Cleanup memory
|
||||
free(hOData);
|
||||
HIP_CHECK(hipFree(dOData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool atomictest_simple(const T& initial_val) {
|
||||
unsigned int ThreadsperBlock = 1;
|
||||
unsigned int numBlocks = 1;
|
||||
T memSize = sizeof(T);
|
||||
T* hOData = reinterpret_cast<T*>(malloc(memSize));
|
||||
*hOData = initial_val;
|
||||
T* dOData;
|
||||
HIP_CHECK(hipMalloc(&dOData, memSize));
|
||||
// copy host memory to device to initialize to zero
|
||||
HIP_CHECK(hipMemcpy(dOData, hOData, memSize, hipMemcpyHostToDevice));
|
||||
|
||||
// execute the kernel
|
||||
hipLaunchKernelGGL(atomic_simple, dim3(numBlocks),
|
||||
dim3(ThreadsperBlock), 0, 0, dOData);
|
||||
|
||||
// Copy result from device to host
|
||||
HIP_CHECK(hipMemcpy(hOData, dOData, memSize, hipMemcpyDeviceToHost));
|
||||
REQUIRE(hOData[0] == initial_val+INCREMENT_VALUE);
|
||||
|
||||
// Cleanup memory
|
||||
free(hOData);
|
||||
HIP_CHECK(hipFree(dOData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool atomictestnoret_simple(const T& initial_val) {
|
||||
unsigned int ThreadsperBlock = 1;
|
||||
unsigned int numBlocks = 1;
|
||||
T memSize = sizeof(T);
|
||||
T* hOData = reinterpret_cast<T*>(malloc(memSize));
|
||||
*hOData = initial_val;
|
||||
T* dOData;
|
||||
HIP_CHECK(hipMalloc(&dOData, memSize));
|
||||
// copy host memory to device to initialize to zero
|
||||
HIP_CHECK(hipMemcpy(dOData, hOData, memSize, hipMemcpyHostToDevice));
|
||||
|
||||
// execute the kernel
|
||||
hipLaunchKernelGGL(atomicnoret_simple, dim3(numBlocks),
|
||||
dim3(ThreadsperBlock), 0, 0, dOData);
|
||||
|
||||
// Copy result from device to host
|
||||
HIP_CHECK(hipMemcpy(hOData, dOData, memSize, hipMemcpyDeviceToHost));
|
||||
REQUIRE(hOData[0] == initial_val+INCREMENT_VALUE);
|
||||
|
||||
// Cleanup memory
|
||||
free(hOData);
|
||||
HIP_CHECK(hipFree(dOData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipTestAtomicAdd") {
|
||||
bool TestPassed = true;
|
||||
|
||||
SECTION("atomic tests with many waves") {
|
||||
REQUIRE(TestPassed == atomictest_manywaves<int>(INT_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed ==
|
||||
atomictest_manywaves<unsigned int>(UNSIGNED_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed == atomictest_manywaves<float>(FLOAT_INITIAL_VALUE));
|
||||
#if HT_AMD
|
||||
REQUIRE(TestPassed ==
|
||||
atomictest_manywaves<uint64_t>(LONG_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed ==
|
||||
atomictest_manywaves<double>(DOUBLE_INITIAL_VALUE));
|
||||
#endif
|
||||
}
|
||||
SECTION("atomic tests with many waves and no return") {
|
||||
REQUIRE(TestPassed ==
|
||||
atomictestnoret_manywaves<float>(FLOAT_INITIAL_VALUE));
|
||||
}
|
||||
SECTION("simple atomic tests") {
|
||||
REQUIRE(TestPassed == atomictest_simple<int>(INT_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed ==
|
||||
atomictest_simple<unsigned int>(UNSIGNED_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed == atomictest_simple<float>(FLOAT_INITIAL_VALUE));
|
||||
#if HT_AMD
|
||||
REQUIRE(TestPassed ==
|
||||
atomictest_simple<uint64_t>(LONG_INITIAL_VALUE));
|
||||
REQUIRE(TestPassed == atomictest_simple<double>(DOUBLE_INITIAL_VALUE));
|
||||
#endif
|
||||
}
|
||||
SECTION("Simple atomic test with no return") {
|
||||
REQUIRE(TestPassed == atomictestnoret_simple<float>(FLOAT_INITIAL_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (c) 2023 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_kernels.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
#define LEN 512
|
||||
#define SIZE (LEN * sizeof(int64_t))
|
||||
|
||||
static __global__ void kernel1(int64_t* Ad) {
|
||||
int tid = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
Ad[tid] = clock() + clock64() + __clock() + __clock64();
|
||||
}
|
||||
|
||||
static __global__ void kernel2(int64_t* Ad) {
|
||||
int tid = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
Ad[tid] = clock() + clock64() + __clock() + __clock64() - Ad[tid];
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipTestClock") {
|
||||
int64_t *A, *Ad;
|
||||
A = new int64_t[LEN];
|
||||
for (unsigned i = 0; i < LEN; i++) {
|
||||
A[i] = 0;
|
||||
}
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&Ad), SIZE));
|
||||
HIP_CHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice));
|
||||
hipLaunchKernelGGL(kernel1, dim3(1, 1, 1), dim3(LEN, 1, 1), 0, 0, Ad);
|
||||
hipLaunchKernelGGL(kernel2, dim3(1, 1, 1), dim3(LEN, 1, 1), 0, 0, Ad);
|
||||
HIP_CHECK(hipMemcpy(A, Ad, SIZE, hipMemcpyDeviceToHost));
|
||||
for (unsigned i = 0; i < LEN; i++) {
|
||||
assert(0 != A[i]);
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,15 @@ set(TEST_SRC
|
||||
hipGraphClone.cc
|
||||
hipGraphInstantiateWithFlags.cc
|
||||
hipGraphAddHostNode.cc
|
||||
hipGraphAddMemcpyNodeFromSymbol_old.cc
|
||||
hipGraphAddMemcpyNodeFromSymbol.cc
|
||||
hipGraphChildGraphNodeGetGraph.cc
|
||||
hipGraphNodeFindInClone.cc
|
||||
hipGraphExecHostNodeSetParams.cc
|
||||
hipGraphAddMemcpyNodeToSymbol_old.cc
|
||||
hipGraphAddMemcpyNodeToSymbol.cc
|
||||
hipGraphExecMemsetNodeSetParams.cc
|
||||
hipGraphMemcpyNodeSetParamsToSymbol_old.cc
|
||||
hipGraphMemcpyNodeSetParamsToSymbol.cc
|
||||
hipGraphDestroyNode.cc
|
||||
hipGraphGetNodes.cc
|
||||
@@ -53,15 +56,21 @@ set(TEST_SRC
|
||||
hipGraphEventWaitNodeSetEvent.cc
|
||||
hipGraphMemsetNodeGetParams.cc
|
||||
hipGraphMemsetNodeSetParams.cc
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol_old.cc
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol.cc
|
||||
hipGraphEventRecordNodeGetEvent.cc
|
||||
hipGraphEventRecordNodeSetEvent.cc
|
||||
hipGraphEventWaitNodeGetEvent.cc
|
||||
hipGraphExecMemcpyNodeSetParams.cc
|
||||
hipStreamBeginCapture.cc
|
||||
hipStreamBeginCapture_old.cc
|
||||
hipStreamIsCapturing.cc
|
||||
hipStreamIsCapturing_old.cc
|
||||
hipStreamGetCaptureInfo.cc
|
||||
hipStreamGetCaptureInfo_old.cc
|
||||
hipStreamEndCapture.cc
|
||||
hipStreamEndCapture_old.cc
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol_old.cc
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol.cc
|
||||
hipGraphExecEventWaitNodeSetEvent.cc
|
||||
hipGraphAddMemsetNode.cc
|
||||
@@ -73,12 +82,19 @@ set(TEST_SRC
|
||||
hipGraphExecKernelNodeSetParams.cc
|
||||
hipGraphLaunch.cc
|
||||
hipGraphMemcpyNodeSetParams1D.cc
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol_old.cc
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol.cc
|
||||
hipGraphNodeGetDependentNodes.cc
|
||||
hipGraphNodeGetDependencies.cc
|
||||
hipGraphHostNodeGetParams.cc
|
||||
hipGraphExecChildGraphNodeSetParams.cc
|
||||
hipStreamGetCaptureInfo_v2.cc
|
||||
hipGraphCreate.cc
|
||||
hipGraphDestroy.cc
|
||||
hipStreamUpdateCaptureDependencies.cc
|
||||
hipThreadExchangeStreamCaptureMode.cc
|
||||
hipLaunchHostFunc.cc
|
||||
hipStreamGetCaptureInfo_v2_old.cc
|
||||
hipUserObjectCreate.cc
|
||||
hipGraphDebugDotPrint.cc
|
||||
hipGraphCloneComplx.cc
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
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 <stddef.h>
|
||||
#include <numeric>
|
||||
|
||||
#include <hip/hip_runtime_api.h>
|
||||
#include <resource_guards.hh>
|
||||
|
||||
namespace {
|
||||
constexpr size_t kArraySize = 5;
|
||||
}
|
||||
|
||||
#define HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(type) \
|
||||
__device__ type type##_device_var = 1; \
|
||||
__constant__ __device__ type type##_const_device_var = 1; \
|
||||
__device__ type type##_device_arr[kArraySize] = {1, 2, 3, 4, 5}; \
|
||||
__constant__ __device__ type type##_const_device_arr[kArraySize] = {1, 2, 3, 4, 5};
|
||||
|
||||
#define HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(type) \
|
||||
__device__ type type##_alt_device_var = 0; \
|
||||
__constant__ __device__ type type##_alt_const_device_var = 0; \
|
||||
__device__ type type##_alt_device_arr[kArraySize] = {0, 0, 0, 0, 0}; \
|
||||
__constant__ __device__ type type##_alt_const_device_arr[kArraySize] = {0, 0, 0, 0, 0};
|
||||
|
||||
template <typename T, typename F>
|
||||
void MemcpyFromSymbolShell(F f, const void* symbol, size_t offset, const std::vector<T> expected) {
|
||||
const auto alloc_type = GENERATE(LinearAllocs::hipMalloc, LinearAllocs::hipHostMalloc);
|
||||
const auto size = expected.size() * sizeof(T);
|
||||
LinearAllocGuard<T> dst_alloc(alloc_type, size);
|
||||
|
||||
hipMemcpyKind direction;
|
||||
if (alloc_type == LinearAllocs::hipMalloc) {
|
||||
direction = GENERATE(hipMemcpyDeviceToDevice, hipMemcpyDefault);
|
||||
} else {
|
||||
direction = GENERATE(hipMemcpyDeviceToHost, hipMemcpyDefault);
|
||||
}
|
||||
INFO("Memcpy direction: " << direction);
|
||||
HIP_CHECK(f(dst_alloc.ptr(), symbol, size, offset * sizeof(T), direction));
|
||||
|
||||
std::vector<T> symbol_values(expected.size());
|
||||
HIP_CHECK(hipMemcpy(symbol_values.data(), dst_alloc.ptr(), size, hipMemcpyDefault));
|
||||
REQUIRE_THAT(expected, Catch::Equals(symbol_values));
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void MemcpyToSymbolShell(F f, const void* symbol, size_t offset, const std::vector<T> set_values) {
|
||||
const auto alloc_type = GENERATE(LinearAllocs::hipMalloc, LinearAllocs::hipHostMalloc);
|
||||
const auto size = set_values.size() * sizeof(T);
|
||||
LinearAllocGuard<T> src_alloc(alloc_type, size);
|
||||
HIP_CHECK(hipMemcpy(src_alloc.ptr(), set_values.data(), size, hipMemcpyDefault));
|
||||
|
||||
hipMemcpyKind direction;
|
||||
if (alloc_type == LinearAllocs::hipMalloc) {
|
||||
direction = GENERATE(hipMemcpyDeviceToDevice, hipMemcpyDefault);
|
||||
} else {
|
||||
direction = GENERATE(hipMemcpyHostToDevice, hipMemcpyDefault);
|
||||
}
|
||||
INFO("Memcpy direction: " << direction);
|
||||
HIP_CHECK(f(symbol, src_alloc.ptr(), size, offset * sizeof(T), direction));
|
||||
|
||||
std::vector<T> symbol_values(set_values.size());
|
||||
HIP_CHECK(hipMemcpyFromSymbol(symbol_values.data(), symbol, size, offset * sizeof(T)));
|
||||
REQUIRE_THAT(set_values, Catch::Equals(symbol_values));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void MemcpyFromSymbolCommonNegative(F f, void* dst, const void* symbol, size_t count) {
|
||||
SECTION("dst == nullptr") {
|
||||
HIP_CHECK_ERROR(f(nullptr, symbol, count, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("symbol == nullptr") {
|
||||
HIP_CHECK_ERROR(f(dst, nullptr, count, 0, hipMemcpyDefault), hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-215
|
||||
#if HT_NVIDIA
|
||||
SECTION("count == 0") {
|
||||
HIP_CHECK_ERROR(f(dst, symbol, 0, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("count > symbol size") {
|
||||
HIP_CHECK_ERROR(f(dst, symbol, count + 1, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("count + offset > symbol size") {
|
||||
HIP_CHECK_ERROR(f(dst, symbol, count, 1, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect
|
||||
#if HT_NVIDIA
|
||||
SECTION("Illogical memcpy direction") {
|
||||
HIP_CHECK_ERROR(f(dst, symbol, count, 0, hipMemcpyHostToDevice),
|
||||
hipErrorInvalidMemcpyDirection);
|
||||
}
|
||||
|
||||
SECTION("Invalid memcpy direction") {
|
||||
HIP_CHECK_ERROR(f(dst, symbol, count, 0, static_cast<hipMemcpyKind>(-1)),
|
||||
hipErrorInvalidMemcpyDirection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void MemcpyToSymbolCommonNegative(F f, const void* symbol, void* src, size_t count) {
|
||||
SECTION("src == nullptr") {
|
||||
HIP_CHECK_ERROR(f(symbol, nullptr, count, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("symbol == nullptr") {
|
||||
HIP_CHECK_ERROR(f(nullptr, src, count, 0, hipMemcpyDefault), hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-215
|
||||
#if HT_NVIDIA
|
||||
SECTION("count == 0") {
|
||||
HIP_CHECK_ERROR(f(symbol, src, 0, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("count > symbol size") {
|
||||
HIP_CHECK_ERROR(f(symbol, src, count + 1, 0, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("count + offset > symbol size") {
|
||||
HIP_CHECK_ERROR(f(symbol, src, count, 1, hipMemcpyDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect
|
||||
#if HT_NVIDIA
|
||||
SECTION("Illogical memcpy direction") {
|
||||
HIP_CHECK_ERROR(f(symbol, src, count, 0, hipMemcpyDeviceToHost),
|
||||
hipErrorInvalidMemcpyDirection);
|
||||
}
|
||||
|
||||
SECTION("Invalid memcpy direction") {
|
||||
HIP_CHECK_ERROR(f(symbol, src, count, 0, static_cast<hipMemcpyKind>(-1)),
|
||||
hipErrorInvalidMemcpyDirection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HT_AMD
|
||||
#define SYMBOL(expr) &HIP_SYMBOL(expr)
|
||||
#else
|
||||
#define SYMBOL(expr) HIP_SYMBOL(expr)
|
||||
#endif
|
||||
|
||||
#define HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(f, init_val, type) \
|
||||
SECTION("Scalar variable") { f(SYMBOL(type##_device_var), 0, std::vector<type>{init_val}); } \
|
||||
\
|
||||
SECTION("Constant scalar variable") { \
|
||||
f(SYMBOL(type##_const_device_var), 0, std::vector<type>{init_val}); \
|
||||
} \
|
||||
\
|
||||
SECTION("Array") { \
|
||||
const auto offset = GENERATE(0, kArraySize / 2); \
|
||||
INFO("Array offset: " << offset); \
|
||||
std::vector<type> expected(kArraySize - offset); \
|
||||
std::iota(expected.begin(), expected.end(), offset + init_val); \
|
||||
f(SYMBOL(type##_device_arr), offset, std::move(expected)); \
|
||||
} \
|
||||
\
|
||||
SECTION("Constant array") { \
|
||||
const auto offset = GENERATE(0, kArraySize / 2); \
|
||||
INFO("Array offset: " << offset); \
|
||||
std::vector<type> expected(kArraySize - offset); \
|
||||
std::iota(expected.begin(), expected.end(), offset + init_val); \
|
||||
f(SYMBOL(type##_const_device_arr), offset, std::move(expected)); \
|
||||
}
|
||||
|
||||
#define HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(f, init_val, type) \
|
||||
SECTION("Scalar variable") { \
|
||||
f(SYMBOL(type##_device_var), SYMBOL(type##_alt_device_var), 0, std::vector<type>{init_val}); \
|
||||
} \
|
||||
\
|
||||
SECTION("Constant scalar variable") { \
|
||||
f(SYMBOL(type##_const_device_var), SYMBOL(type##_alt_const_device_var), 0, \
|
||||
std::vector<type>{init_val}); \
|
||||
} \
|
||||
\
|
||||
SECTION("Array") { \
|
||||
const auto offset = GENERATE(0, kArraySize / 2); \
|
||||
INFO("Array offset: " << offset); \
|
||||
std::vector<type> expected(kArraySize - offset); \
|
||||
std::iota(expected.begin(), expected.end(), offset + init_val); \
|
||||
f(SYMBOL(type##_device_arr), SYMBOL(type##_alt_device_arr), offset, std::move(expected)); \
|
||||
} \
|
||||
\
|
||||
SECTION("Constant array") { \
|
||||
const auto offset = GENERATE(0, kArraySize / 2); \
|
||||
INFO("Array offset: " << offset); \
|
||||
std::vector<type> expected(kArraySize - offset); \
|
||||
std::iota(expected.begin(), expected.end(), offset + init_val); \
|
||||
f(SYMBOL(type##_const_device_arr), SYMBOL(type##_alt_const_device_arr), offset, \
|
||||
std::move(expected)); \
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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 <hip/hip_runtime_api.h>
|
||||
#include <resource_guards.hh>
|
||||
#include <utils.hh>
|
||||
|
||||
template <typename T, typename F> void GraphMemsetNodeCommonPositive(F f) {
|
||||
const size_t width = GENERATE(1, 64, kPageSize / sizeof(T) + 1);
|
||||
const size_t height = GENERATE(1, 2, 1024);
|
||||
DYNAMIC_SECTION("Width: " << width << " Height: " << height) {
|
||||
LinearAllocGuard2D<T> alloc(width, height);
|
||||
|
||||
constexpr T set_value = 42;
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(T);
|
||||
params.width = width;
|
||||
params.height = height;
|
||||
params.pitch = alloc.pitch();
|
||||
params.value = set_value;
|
||||
|
||||
HIP_CHECK(f(¶ms));
|
||||
|
||||
LinearAllocGuard<T> buffer(LinearAllocs::hipHostMalloc, width * sizeof(T) * height);
|
||||
HIP_CHECK(hipMemcpy2D(buffer.ptr(), width * sizeof(T), alloc.ptr(), alloc.pitch(),
|
||||
width * sizeof(T), height, hipMemcpyDeviceToHost));
|
||||
ArrayFindIfNot(buffer.ptr(), set_value, width * height);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F> void MemsetCommonNegative(F f, hipMemsetParams params) {
|
||||
SECTION("pMemsetParams == nullptr") { HIP_CHECK_ERROR(f(nullptr), hipErrorInvalidValue); }
|
||||
|
||||
SECTION("pMemsetParams.dst == nullptr") {
|
||||
params.dst = nullptr;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("pMemsetParams.elementSize != 1, 2, 4") {
|
||||
params.elementSize = GENERATE(0, 3, 5);
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-204
|
||||
#if HT_NVIDIA
|
||||
SECTION("pMemsetParams.width == 0") {
|
||||
params.width = 0;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("pMemsetParams.width > allocation size") {
|
||||
params.width = params.width + 1000;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("pMemsetParams.height == 0") {
|
||||
params.height = 0;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-205
|
||||
#if HT_NVIDIA
|
||||
SECTION("pMemsetParams.pitch < width when height > 1") {
|
||||
params.width = 2;
|
||||
params.height = 2;
|
||||
params.pitch = params.elementSize;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-206
|
||||
#if HT_NVIDIA
|
||||
SECTION("pMemsetParams.pitch * height > allocation size") {
|
||||
params.width = 2;
|
||||
params.height = 2;
|
||||
params.pitch = 3 * params.elementSize;
|
||||
HIP_CHECK_ERROR(f(¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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 <stddef.h>
|
||||
|
||||
#include <hip/hip_runtime_api.h>
|
||||
#include <resource_guards.hh>
|
||||
|
||||
template <typename F> void GraphAddNodeCommonNegativeTests(F f, hipGraph_t graph) {
|
||||
hipGraphNode_t node = nullptr;
|
||||
SECTION("graph == nullptr") {
|
||||
HIP_CHECK_ERROR(f(&node, nullptr, nullptr, 0), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(f(nullptr, graph, nullptr, 0), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("dependencies == nullptr with size != 0") {
|
||||
HIP_CHECK_ERROR(f(&node, graph, nullptr, 1), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-202
|
||||
#if HT_NVIDIA
|
||||
SECTION("Node in dependency is from different graph") {
|
||||
hipGraph_t other_graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&other_graph, 0));
|
||||
hipGraphNode_t other_node = nullptr;
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&other_node, other_graph, nullptr, 0));
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&node, graph, nullptr, 0));
|
||||
HIP_CHECK_ERROR(f(&node, graph, &other_node, 1), hipErrorInvalidValue);
|
||||
HIP_CHECK(hipGraphDestroy(other_graph));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Invalid numNodes") {
|
||||
hipGraphNode_t dep_node = nullptr;
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&dep_node, graph, nullptr, 0));
|
||||
HIP_CHECK_ERROR(f(&node, graph, &dep_node, 2), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-201
|
||||
#if HT_NVIDIA
|
||||
SECTION("Duplicate node in dependencies") {
|
||||
hipGraphNode_t dep_node = nullptr;
|
||||
// Need to create two nodes to avoid overlap with Invalid numNodes case
|
||||
// First one is left dangling as the graph will be destroyed after the section anyway
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&dep_node, graph, nullptr, 0));
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&dep_node, graph, nullptr, 0));
|
||||
hipGraphNode_t deps[] = {dep_node, dep_node};
|
||||
HIP_CHECK_ERROR(f(&node, graph, deps, 2), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -136,6 +136,8 @@ TEST_CASE("Unit_hipGraphAddHostNode_ClonedGraphwithHostNode") {
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
hipGraphNode_t memcpyH2D_A, memcpyH2D_C,
|
||||
memcpyD2H_AC;
|
||||
hipGraphNode_t cloned_memcpyH2D_A, cloned_memcpyH2D_C,
|
||||
cloned_memcpyD2H_AC;
|
||||
hipStream_t streamForGraph;
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
|
||||
@@ -151,6 +153,13 @@ TEST_CASE("Unit_hipGraphAddHostNode_ClonedGraphwithHostNode") {
|
||||
hipGraph_t clonedgraph;
|
||||
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
|
||||
|
||||
HIP_CHECK(hipGraphNodeFindInClone(&cloned_memcpyH2D_A, memcpyH2D_A,
|
||||
clonedgraph));
|
||||
HIP_CHECK(hipGraphNodeFindInClone(&cloned_memcpyH2D_C, memcpyH2D_C,
|
||||
clonedgraph));
|
||||
HIP_CHECK(hipGraphNodeFindInClone(&cloned_memcpyD2H_AC, memcpyD2H_AC,
|
||||
clonedgraph));
|
||||
|
||||
hipGraphNode_t hostNode;
|
||||
hipHostNodeParams hostParams = {0, 0};
|
||||
hostParams.fn = callbackfunc;
|
||||
@@ -159,10 +168,12 @@ TEST_CASE("Unit_hipGraphAddHostNode_ClonedGraphwithHostNode") {
|
||||
nullptr,
|
||||
0, &hostParams));
|
||||
|
||||
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
|
||||
&memcpyD2H_AC, 1));
|
||||
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
|
||||
&memcpyD2H_AC, 1));
|
||||
HIP_CHECK(hipGraphAddDependencies(clonedgraph, &cloned_memcpyH2D_A,
|
||||
&cloned_memcpyD2H_AC, 1));
|
||||
HIP_CHECK(hipGraphAddDependencies(clonedgraph, &cloned_memcpyH2D_C,
|
||||
&cloned_memcpyD2H_AC, 1));
|
||||
HIP_CHECK(hipGraphAddDependencies(clonedgraph, &cloned_memcpyD2H_AC,
|
||||
&hostNode, 1));
|
||||
|
||||
// Instantiate and launch the cloned graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr, nullptr, 0));
|
||||
|
||||
@@ -6,432 +6,144 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphAddMemcpyNodeFromSymbol API:
|
||||
|
||||
Functional :
|
||||
|
||||
1. Allocate global symbol memory, add the MemcpyNodeFromSymbol
|
||||
node to the graph and verify for different memory kinds
|
||||
2. Allocate const memory add the MemcpyNodeFromSymbol node to
|
||||
the graph and verify for different memory kinds
|
||||
3. Allocate global symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
4. Allocate const symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
5. Allocate global memory, Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
|
||||
Negative :
|
||||
|
||||
1) Pass nullptr to graph node
|
||||
2) Pass nullptr to graph
|
||||
3) Pass nullptr to dependencies
|
||||
4) Pass invalid numDependencies
|
||||
5) Pass nullptr to dst
|
||||
6) Pass nullptr to symbol
|
||||
7) Pass invalid count
|
||||
8) Pass offset+count greater than allocated size
|
||||
9) Pass unintialized graph
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
#include "graph_tests_common.hh"
|
||||
|
||||
__global__ void MemcpyFromSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
globalIn[i] = B_d[i];
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
template <typename T>
|
||||
void GraphMemcpyFromSymbolShell(void* symbol, size_t offset, const std::vector<T> expected) {
|
||||
const auto f = [](void* dst, const void* symbol, size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&node, graph, nullptr, 0, dst, symbol, count, offset,
|
||||
direction));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyFromSymbolShell(f, symbol, offset, std::move(expected));
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup hipGraphAddMemcpyNodeFromSymbol hipGraphAddMemcpyNodeFromSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphAddMemcpyNodeFromSymbol(hipGraphNode_t *pGraphNode, hipGraph_t graph, const
|
||||
* hipGraphNode_t *pDependencies, size_t numDependencies, void *dst, const void *symbol, size_t
|
||||
* count, size_t offset, hipMemcpyKind kind)` -
|
||||
* Creates a memcpy node to copy from a symbol on the device and adds it to a graph
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied from a symbol. A graph is constructed to which a
|
||||
* MemcpyFromSymbol node is added. After graph execution, values in destination memory are compared
|
||||
* against values known to be in symbol memory.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for destination memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemcpyNodeFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolShell, 1, char);
|
||||
}
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolShell, 1, int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolShell, 1, float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolShell, 1, double);
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphAddMemcpyNodeFromSymbol API */
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# pGraphNodes is nullptr
|
||||
* -# graph is nullptr
|
||||
* -# pDependencies is nullptr when numDependencies is non-zero
|
||||
* -# A node in pDependencies belongs to a different graph
|
||||
* -# numDependencies in invalid
|
||||
* -# A node appears twice in pDependencies
|
||||
* -# dst is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyHostToDevice)
|
||||
* -# kind is an invalid enum value
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemcpyNodeFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
int var = 0;
|
||||
hipGraphNode_t node = nullptr;
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
GraphAddNodeCommonNegativeTests(
|
||||
std::bind(hipGraphAddMemcpyNodeFromSymbol, _1, _2, _3, _4, &var, SYMBOL(int_device_var),
|
||||
sizeof(var), 0, hipMemcpyDefault),
|
||||
graph);
|
||||
|
||||
#if HT_NVIDIA
|
||||
hipGraphNode_t memcpyFromSymbolNode;
|
||||
SECTION("Passing nullptr to graph") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, nullptr,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
MemcpyFromSymbolCommonNegative(
|
||||
std::bind(hipGraphAddMemcpyNodeFromSymbol, &node, graph, nullptr, 0, _1, _2, _3, _4, _5),
|
||||
&var, SYMBOL(int_device_var), sizeof(var));
|
||||
|
||||
SECTION("Passing nullptr to graph node") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(nullptr, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing size > 1 and dependencies as nullptr") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
nullptr,
|
||||
1,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing invalid dependencies size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
10,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to dst") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
nullptr,
|
||||
HIP_SYMBOL(globalIn), Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to source") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
SECTION("Passing offset+size > max size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing Max count") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
std::numeric_limits<int>::max(), 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Pass Unintialized graph") {
|
||||
hipGraph_t unint_graph;
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, unint_graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This function is used to verify the following scenarios
|
||||
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
|
||||
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
|
||||
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
|
||||
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
|
||||
*/
|
||||
|
||||
void hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(bool device_ctxchg = false,
|
||||
bool const_device_var =
|
||||
false) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
if (device_ctxchg) {
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
|
||||
}
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
|
||||
// Adding MemcpyNodeFromSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
}
|
||||
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory,
|
||||
add the MemcpyNodeFromSymbol node to the graph and
|
||||
erifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemory") {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory,
|
||||
add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemory") {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
#if HT_NVIDIA
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
if (numDevices > 1) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, false);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
if (numDevices > 1) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, true);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
This testcaser verifies allocating global memory,
|
||||
Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryWithKernel") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpyfromsymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyFromSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpyfromsymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyfromsymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphAddMemcpyNodeFromSymbol API:
|
||||
|
||||
Functional :
|
||||
|
||||
1. Allocate global symbol memory, add the MemcpyNodeFromSymbol
|
||||
node to the graph and verify for different memory kinds
|
||||
2. Allocate const memory add the MemcpyNodeFromSymbol node to
|
||||
the graph and verify for different memory kinds
|
||||
3. Allocate global symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
4. Allocate const symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
5. Allocate global memory, Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
|
||||
Negative :
|
||||
|
||||
1) Pass nullptr to graph node
|
||||
2) Pass nullptr to graph
|
||||
3) Pass nullptr to dependencies
|
||||
4) Pass invalid numDependencies
|
||||
5) Pass nullptr to dst
|
||||
6) Pass nullptr to symbol
|
||||
7) Pass invalid count
|
||||
8) Pass offset+count greater than allocated size
|
||||
9) Pass unintialized graph
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
__global__ void MemcpyFromSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
globalIn[i] = B_d[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphAddMemcpyNodeFromSymbol API */
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
#if HT_NVIDIA
|
||||
hipGraphNode_t memcpyFromSymbolNode;
|
||||
SECTION("Passing nullptr to graph") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, nullptr,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to graph node") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(nullptr, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing size > 1 and dependencies as nullptr") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
nullptr,
|
||||
1,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing invalid dependencies size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
10,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to dst") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
nullptr,
|
||||
HIP_SYMBOL(globalIn), Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to source") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
SECTION("Passing offset+size > max size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing Max count") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
std::numeric_limits<int>::max(), 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Pass Unintialized graph") {
|
||||
hipGraph_t unint_graph;
|
||||
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, unint_graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This function is used to verify the following scenarios
|
||||
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
|
||||
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
|
||||
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
|
||||
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
|
||||
*/
|
||||
|
||||
void hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(bool device_ctxchg = false,
|
||||
bool const_device_var =
|
||||
false) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
if (device_ctxchg) {
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
|
||||
}
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
|
||||
// Adding MemcpyNodeFromSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
}
|
||||
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory,
|
||||
add the MemcpyNodeFromSymbol node to the graph and
|
||||
erifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemory") {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory,
|
||||
add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemory") {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
#if HT_NVIDIA
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
if (numDevices > 1) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, false);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
if (numDevices > 1) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, true);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
This testcaser verifies allocating global memory,
|
||||
Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryWithKernel") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpyfromsymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyFromSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpyfromsymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyfromsymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
@@ -1,402 +1,152 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphAddMemcpyNodeToSymbol API:
|
||||
|
||||
Functional :
|
||||
|
||||
1. Allocate global symbol memory, add the MemcpyNodeToSymbol
|
||||
node to the graph and verify for different memory kinds
|
||||
2. Allocate const memory add the MemcpyNodeToSymbol node to
|
||||
the graph and verify for different memory kinds
|
||||
3. Allocate global symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
4. Allocate const symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
5. Allocate global memory, Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
|
||||
Negative :
|
||||
|
||||
1) Pass nullptr to graph node
|
||||
2) Pass nullptr to graph
|
||||
3) Pass nullptr to dependencies
|
||||
4) Pass invalid numDependencies
|
||||
5) Pass nullptr to dst
|
||||
6) Pass nullptr to symbol
|
||||
7) Pass invalid count
|
||||
8) Pass offset+count greater than allocated size
|
||||
9) Pass unintialized graph
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
#include "graph_tests_common.hh"
|
||||
|
||||
__global__ void MemcpyToSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
template <typename T>
|
||||
void GraphMemcpyToSymbolShell(const void* symbol, size_t offset, const std::vector<T> set_values) {
|
||||
const auto f = [](const void* symbol, void* src, size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&node, graph, nullptr, 0, symbol, src, count, offset,
|
||||
direction));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyToSymbolShell(f, symbol, offset, std::move(set_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup hipGraphAddMemcpyNodeToSymbol hipGraphAddMemcpyNodeToSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphAddMemcpyNodeToSymbol(hipGraphNode_t *pGraphNode, hipGraph_t graph, const hipGraphNode_t
|
||||
* *pDependencies, size_t numDependencies, const void *symbol, const void *src, size_t count, size_t
|
||||
* offset, hipMemcpyKind kind)` -
|
||||
* Creates a memcpy node to copy to a symbol on the device and adds it to a graph
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied to a symbol. A graph is constructed to which a
|
||||
* MemcpyToSymbol node is added. After graph execution, a MemcpyFromSymbol is performed and
|
||||
* the copied values are compared against values known to have been copied to symbol memory
|
||||
* previously.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for source memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemcpyNodeToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolShell, 10, char);
|
||||
}
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolShell, 10, int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolShell, 10, float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_ADD_MEMCPY_NODE_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolShell, 10, double);
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphAddMemcpyNodeToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# pGraphNodes is nullptr
|
||||
* -# graph is nullptr
|
||||
* -# pDependencies is nullptr when numDependencies is non-zero
|
||||
* -# A node in pDependencies belongs to a different graph
|
||||
* -# numDependencies in invalid
|
||||
* -# A node appears twice in pDependencies
|
||||
* -# src is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyDeviceToHost)
|
||||
* -# kind is an invalid enum value
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemcpyNodeToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
#if HT_NVIDIA
|
||||
hipGraphNode_t memcpyToSymbolNode;
|
||||
SECTION("Passing nullptr to graph") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, nullptr,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_h, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
int var = 0;
|
||||
hipGraphNode_t node = nullptr;
|
||||
|
||||
SECTION("Passing nullptr to graph node") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(nullptr, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
GraphAddNodeCommonNegativeTests(
|
||||
std::bind(hipGraphAddMemcpyNodeToSymbol, _1, _2, _3, _4, SYMBOL(int_device_var), &var,
|
||||
sizeof(var), 0, hipMemcpyDefault),
|
||||
graph);
|
||||
|
||||
SECTION("Passing size > 1 and dependencies as nullptr") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
nullptr,
|
||||
1,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
MemcpyToSymbolCommonNegative(
|
||||
std::bind(hipGraphAddMemcpyNodeToSymbol, &node, graph, nullptr, 0, _1, _2, _3, _4, _5),
|
||||
SYMBOL(int_device_var), &var, sizeof(var));
|
||||
|
||||
SECTION("Passing invalid dependencies size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
10,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to dst") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
nullptr,
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to source") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing offset+size > max size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing Max count") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d,
|
||||
std::numeric_limits<int>::max(), 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Pass Unintialized graph") {
|
||||
hipGraph_t unint_graph;
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, unint_graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This function is used to verify the following scenarios
|
||||
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
|
||||
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
|
||||
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
|
||||
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
|
||||
*/
|
||||
void hipGraphAddMemcpyNodeToSymbol_GlobalMemory(bool device_ctxchg = false,
|
||||
bool const_device_var = false) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
if (device_ctxchg) {
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
|
||||
}
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding MemcpyNodeFromSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0, hipMemcpyDeviceToHost));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0, hipMemcpyDeviceToHost));
|
||||
}
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory,
|
||||
add the MemcpyNodeToSymbol node to the graph and
|
||||
erifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemory") {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory,
|
||||
add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemory") {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, true);
|
||||
}
|
||||
|
||||
#if HT_NVIDIA
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
HIP_CHECK(hipGetDeviceCount(&numDevices));
|
||||
if (numDevices > 1) {
|
||||
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, false);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
HIP_CHECK(hipGetDeviceCount(&numDevices));
|
||||
if (numDevices > 1) {
|
||||
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, true);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
This testcaser verifies allocating global memory,
|
||||
Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_MemcpyToSymbolNodeWithKernel") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyToSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphAddMemcpyNodeToSymbol API:
|
||||
|
||||
Functional :
|
||||
|
||||
1. Allocate global symbol memory, add the MemcpyNodeToSymbol
|
||||
node to the graph and verify for different memory kinds
|
||||
2. Allocate const memory add the MemcpyNodeToSymbol node to
|
||||
the graph and verify for different memory kinds
|
||||
3. Allocate global symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
4. Allocate const symbol memory and device memory in GPU-0
|
||||
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
|
||||
5. Allocate global memory, Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
|
||||
Negative :
|
||||
|
||||
1) Pass nullptr to graph node
|
||||
2) Pass nullptr to graph
|
||||
3) Pass nullptr to dependencies
|
||||
4) Pass invalid numDependencies
|
||||
5) Pass nullptr to dst
|
||||
6) Pass nullptr to symbol
|
||||
7) Pass invalid count
|
||||
8) Pass offset+count greater than allocated size
|
||||
9) Pass unintialized graph
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
__global__ void MemcpyToSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphAddMemcpyNodeToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
#if HT_NVIDIA
|
||||
hipGraphNode_t memcpyToSymbolNode;
|
||||
SECTION("Passing nullptr to graph") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, nullptr,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_h, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to graph node") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(nullptr, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing size > 1 and dependencies as nullptr") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
nullptr,
|
||||
1,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing invalid dependencies size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
10,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to dst") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
nullptr,
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidSymbol);
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr to source") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing offset+size > max size") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Passing Max count") {
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d,
|
||||
std::numeric_limits<int>::max(), 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Pass Unintialized graph") {
|
||||
hipGraph_t unint_graph;
|
||||
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, unint_graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice)
|
||||
== hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This function is used to verify the following scenarios
|
||||
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
|
||||
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
|
||||
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
|
||||
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
|
||||
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
|
||||
*/
|
||||
void hipGraphAddMemcpyNodeToSymbol_GlobalMemory(bool device_ctxchg = false,
|
||||
bool const_device_var = false) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
if (device_ctxchg) {
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
|
||||
}
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding MemcpyNodeFromSymbol
|
||||
if (const_device_var) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0, hipMemcpyDeviceToHost));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0, hipMemcpyDeviceToHost));
|
||||
}
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory,
|
||||
add the MemcpyNodeToSymbol node to the graph and
|
||||
erifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemory") {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory,
|
||||
add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemory") {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, true);
|
||||
}
|
||||
|
||||
#if HT_NVIDIA
|
||||
/*
|
||||
This testcase verifies allocating global symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
HIP_CHECK(hipGetDeviceCount(&numDevices));
|
||||
if (numDevices > 1) {
|
||||
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, false);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
/*
|
||||
This testcase verifies allocating global const symbol memory and device variables
|
||||
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
|
||||
verifying the result in GPU-1
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemoryPeerDevice") {
|
||||
int numDevices = 0;
|
||||
int canAccessPeer = 0;
|
||||
HIP_CHECK(hipGetDeviceCount(&numDevices));
|
||||
if (numDevices > 1) {
|
||||
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
|
||||
if (canAccessPeer) {
|
||||
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, true);
|
||||
} else {
|
||||
SUCCEED("Machine does not seem to have P2P");
|
||||
}
|
||||
} else {
|
||||
SUCCEED("skipped the testcase as no of devices is less than 2");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
This testcaser verifies allocating global memory,
|
||||
Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
|
||||
the behaviour
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_MemcpyToSymbolNodeWithKernel") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyToSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
@@ -6,132 +6,121 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Negative Testcase Scenarios for api hipGraphAddMemsetNode :
|
||||
1) Pass pGraphNode as nullptr and check if api returns error.
|
||||
2) Pass pGraphNode as un-initialize object and check.
|
||||
3) Pass Graph as nullptr and check if api returns error.
|
||||
4) Pass Graph as empty object(skipping graph creation), api should return error code.
|
||||
5) Pass pDependencies as nullptr, api should return success.
|
||||
6) Pass numDependencies is max(size_t) and pDependencies is not valid ptr, api expected to return error code.
|
||||
7) Pass pDependencies is nullptr, but numDependencies is non-zero, api expected to return error.
|
||||
8) Pass pMemsetParams as nullptr and check if api returns error code.
|
||||
9) Pass pMemsetParams as un-initialize object and check if api returns error code.
|
||||
10) Pass hipMemsetParams::dst as nullptr should return error code.
|
||||
11) Pass hipMemsetParams::element size other than 1, 2, or 4 and check api should return error code.
|
||||
12) Pass hipMemsetParams::height as zero and check api should return error code.
|
||||
Functional Scenarios for api hipGraphAddMemsetNode :
|
||||
1. Allocate a 2D array using hipMallocPitch. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results
|
||||
2. Allocate a 1D array using hipMallocPitch. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results..
|
||||
3. Allocate a 2D array using hipMalloc3D. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results.
|
||||
4. Allocate a 1D array using hipMalloc3D. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results.
|
||||
5. Allocate a 1D array using hipMalloc. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results.
|
||||
6. Allocate memory using hipMallocManaged. Initialize the allocated memory using hipGraphAddMemsetNode.
|
||||
Copy the values in device memory to host using hipGraphAddMemcpyNode. Verify the results.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
/**
|
||||
* Negative Test for API hipGraphAddMemsetNode
|
||||
*/
|
||||
#include <resource_guards.hh>
|
||||
#include <utils.hh>
|
||||
|
||||
#include "graph_memset_node_test_common.hh"
|
||||
#include "graph_tests_common.hh"
|
||||
|
||||
#define SIZE 1024
|
||||
static char memSetVal = 'a';
|
||||
TEST_CASE("Unit_hipGraphAddMemsetNode_Negative") {
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memsetNode;
|
||||
char *devData;
|
||||
|
||||
HIP_CHECK(hipMalloc(&devData, 1024));
|
||||
/**
|
||||
* @addtogroup hipGraphAddMemsetNode hipGraphAddMemsetNode
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphAddMemsetNode(hipGraphNode_t *pGraphNode, hipGraph_t graph, const hipGraphNode_t
|
||||
* *pDependencies, size_t numDependencies, const hipMemsetParams *pMemsetParams)` -
|
||||
* Creates a memset node and adds it to a graph
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that all elements of destination memory are set to the correct value.
|
||||
* The test is repeated for all valid element sizes(1, 2, 4), and several allocations of different
|
||||
* height and width, both on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemsetNode.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEMPLATE_TEST_CASE("Unit_hipGraphAddMemsetNode_Positive_Basic", "", uint8_t, uint16_t, uint32_t) {
|
||||
const auto f = [](hipMemsetParams* params) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, params));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
GraphMemsetNodeCommonPositive<TestType>(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behaviour with invalid arguments:
|
||||
* -# pGraphNode is nullptr
|
||||
* -# graph is nullptr
|
||||
* -# pDependencies is nullptr when numDependencies is not zero
|
||||
* -# A node in pDependencies originates from a different graph
|
||||
* -# numDependencies is invalid
|
||||
* -# A node is duplicated in pDependencies
|
||||
* -# pMemsetParams is nullptr
|
||||
* -# pMemsetParams::dst is nullptr
|
||||
* -# pMemsetParams::elementSize is different from 1, 2, and 4
|
||||
* -# pMemsetParams::width is zero
|
||||
* -# pMemsetParams::width is larger than the allocated memory region
|
||||
* -# pMemsetParams::height is zero
|
||||
* -# pMemsetParams::pitch is less than width when height is more than 1
|
||||
* -# pMemsetParams::pitch * pMemsetParams::height is larger than the allocated memory region
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphAddMemsetNode.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemsetNode_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = 0;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = 1024;
|
||||
memsetParams.height = 1;
|
||||
LinearAllocGuard<int> alloc(LinearAllocs::hipMalloc, 4 * sizeof(int));
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(*alloc.ptr());
|
||||
params.width = 1;
|
||||
params.height = 1;
|
||||
params.value = 42;
|
||||
|
||||
GraphAddNodeCommonNegativeTests(std::bind(hipGraphAddMemsetNode, _1, _2, _3, _4, ¶ms), graph);
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
MemsetCommonNegative(std::bind(hipGraphAddMemsetNode, &node, graph, nullptr, 0, _1), params);
|
||||
|
||||
SECTION("Pass pGraphNode as nullptr") {
|
||||
ret = hipGraphAddMemsetNode(nullptr, graph, nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass pGraphNode as un-initialize object") {
|
||||
hipGraphNode_t memsetNode_1;
|
||||
ret = hipGraphAddMemsetNode(&memsetNode_1, graph,
|
||||
nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipSuccess == ret);
|
||||
}
|
||||
SECTION("Pass graph as nullptr") {
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, nullptr,
|
||||
nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass Graph as empty object") {
|
||||
hipGraph_t graph_1{};
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph_1,
|
||||
nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass pDependencies as nullptr") {
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipSuccess == ret);
|
||||
}
|
||||
SECTION("Pass numDependencies is max and pDependencies is not valid ptr") {
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph,
|
||||
nullptr, INT_MAX, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass pDependencies as nullptr, but numDependencies is non-zero") {
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 9, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass pMemsetParams as nullptr") {
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass pMemsetParams as un-initialize object") {
|
||||
hipMemsetParams memsetParams1;
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams1);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass hipMemsetParams::dst as nullptr") {
|
||||
memsetParams.dst = nullptr;
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass hipMemsetParams::element size other than 1, 2, or 4") {
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.elementSize = 9;
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass hipMemsetParams::height as zero") {
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.height = 0;
|
||||
ret = hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -20,25 +20,53 @@ THE SOFTWARE.
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
/**
|
||||
Negative Testcase Scenarios :
|
||||
1) Creating HipGraph with nullptr.
|
||||
2) Creating hipGraph with non-zero mode.
|
||||
*/
|
||||
* @addtogroup hipGraphCreate hipGraphCreate
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphCreate(hipGraph_t *pGraph, unsigned int flags)` -
|
||||
* creates a graph
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphCreate_Negative") {
|
||||
hipError_t ret;
|
||||
SECTION("Creating HipGraph with nullptr") {
|
||||
ret = hipGraphCreate(nullptr, 0);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Negative parameter test for hipGraphCreate:
|
||||
* -# Expected hipErrorInvalidValue when pGraph is null
|
||||
* -# Expected hipErrorInvalidValue when flags is not 0
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphCreate.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphCreate_Negative_Parameters") {
|
||||
hipGraph_t graph = nullptr;
|
||||
|
||||
SECTION("pGraph is nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphCreate(nullptr, 0), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Creating hipGraph with non-zero mode") {
|
||||
hipGraph_t graph{};
|
||||
ret = hipGraphCreate(&graph, -1);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
|
||||
ret = hipGraphCreate(nullptr, -1);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("flags is not 0") { HIP_CHECK_ERROR(hipGraphCreate(&graph, 1), hipErrorInvalidValue); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Basic positive test for hipGraphCreate
|
||||
* - Create an emtpy graph
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphCreate.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphCreate_Positive_Basic") {
|
||||
hipGraph_t graph = nullptr;
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
REQUIRE(nullptr != graph);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -20,62 +20,46 @@ THE SOFTWARE.
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
/**
|
||||
Negative Testcase Scenarios :
|
||||
1) Pass graph as nullptr and verify.
|
||||
2) Destroy already destroyed graph and check api returns error code.
|
||||
3) Destroy graph when is in use and make sure api handles it gracefully.
|
||||
*/
|
||||
* @addtogroup hipGraphDestroy hipGraphDestroy
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphDestroy(hipGraph_t graph)` -
|
||||
* Destroys a graph
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipGraphDestroy_Negative") {
|
||||
hipError_t ret;
|
||||
SECTION("Deleting HipGraph with nullptr") {
|
||||
ret = hipGraphDestroy(nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#if HT_AMD
|
||||
SECTION("Destroy already destroyed graph and check api returns error code") {
|
||||
hipGraph_t graph;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Basic positive test for hipGraphDestroy
|
||||
* - Create an emtpy graph and then destroy it
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphDestroy.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphDestroy_Positive_Basic") {
|
||||
hipGraph_t graph = nullptr;
|
||||
|
||||
ret = hipGraphDestroy(graph);
|
||||
REQUIRE(hipErrorIllegalState == ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("Destroy graph when is in use and make sure api handles"
|
||||
" it gracefully.") {
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphNode_t memsetNode;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
REQUIRE(nullptr != graph);
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
|
||||
char *devData;
|
||||
HIP_CHECK(hipMalloc(&devData, 1024));
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = 0;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = 1024;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
}
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Basic negative parameter test for hipGraphDestroy
|
||||
* -# Expected hipErrorInvalidValue when graph is invalid
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphDestroy.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphDestroy_Negative_Parameters") {
|
||||
HIP_CHECK_ERROR(hipGraphDestroy(static_cast<hipGraph_t>(nullptr)), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
@@ -6,298 +6,197 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphExecMemcpyNodeSetParamsFromSymbol API:
|
||||
Functional
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
Negative
|
||||
1) Pass hGraphExec as nullptr and check if api returns error.
|
||||
2) Pass GraphNode as nullptr and check if api returns error.
|
||||
3) Pass destination ptr as nullptr, api expected to return error code.
|
||||
4) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
5) Pass count as zero, api expected to return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as source ptr and destination ptr, api expected to return error code.
|
||||
8) Pass Pass both dstn ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from device ptr to host ptr but pass kind as different, api expected to return error code.
|
||||
10) Check with other graph node but pass same graphExec, api expected to return error code.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
#include <resource_guards.hh>
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsFromSymbol API Negative scenarios.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(double)
|
||||
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
template <typename T>
|
||||
void GraphExecMemcpyFromSymbolSetParamsShell(const void* symbol, const void* alt_symbol,
|
||||
size_t offset, const std::vector<T> expected) {
|
||||
const auto f = [alt_symbol, is_arr = expected.size() > 1](void* dst, const void* symbol,
|
||||
size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
hipGraphNode_t node = nullptr;
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(
|
||||
&node, graph, nullptr, 0, reinterpret_cast<T*>(dst) + is_arr, alt_symbol,
|
||||
count - is_arr * sizeof(T), offset + is_arr * sizeof(T), direction));
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(nullptr,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
nullptr, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass destination ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, nullptr,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
nullptr,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source and destination ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from device ptr to host ptr but pass kind as different") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_h,
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipSuccess != ret);
|
||||
}
|
||||
SECTION("Check with other graph node") {
|
||||
hipGraphNode_t memcpyFromSymbolNode1{};
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode1,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsFromSymbol(graph_exec, node, dst, symbol, count,
|
||||
offset, direction));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyFromSymbolShell(f, symbol, offset, std::move(expected));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(bool useConstVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
hipGraphNode_t memcpyD2H_B;
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
/**
|
||||
* @addtogroup hipGraphExecMemcpyNodeSetParamsFromSymbol hipGraphExecMemcpyNodeSetParamsFromSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphExecMemcpyNodeSetParamsFromSymbol(hipGraphExec_t hGraphExec, hipGraphNode_t node, void
|
||||
* *dst, const void *symbol, size_t count, size_t offset, hipMemcpyKind kind)` -
|
||||
* Sets the parameters for a memcpy node in the given graphExec to copy from a symbol on the
|
||||
*/
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied from a symbol after node parameters are set following
|
||||
* node addition. A graph is constructed to which a MemcpyFromSymbol node is added with valid but
|
||||
* incorrect parameters. After the graph is instantiated the parameters are updated to correct
|
||||
* values and the graph executed. Values in destination memory are compared against values known to
|
||||
* be in symbol memory.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for destination memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemcpyNodeSetParamsFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyFromSymbolSetParamsShell, 1,
|
||||
char);
|
||||
}
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyFromSymbolSetParamsShell, 1,
|
||||
int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyFromSymbolSetParamsShell, 1,
|
||||
float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyFromSymbolSetParamsShell, 1,
|
||||
double);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# gGraphExec is nullptr
|
||||
* -# node is nullptr
|
||||
* -# dst is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyHostToDevice)
|
||||
* -# kind is an invalid enum value
|
||||
* -# Changing memcpy direction
|
||||
* -# Changing dst to memory allocated on a different device than the original dst
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemcpyNodeSetParamsFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
LinearAllocGuard<int> var(LinearAllocs::hipMalloc, sizeof(int));
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&node, graph, nullptr, 0, var.ptr(),
|
||||
SYMBOL(int_device_var), sizeof(*var.ptr()), 0,
|
||||
hipMemcpyDefault));
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Update the node with B_d destination pointer from C_d
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
SECTION("hGraphExec == nullptr") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol(nullptr, node, var.ptr(), SYMBOL(int_device_var),
|
||||
sizeof(*var.ptr()), 0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphExecMemcpyNodeSetParamsFromSymbol(
|
||||
graph_exec, nullptr, var.ptr(), SYMBOL(int_device_var), sizeof(*var.ptr()),
|
||||
0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
MemcpyFromSymbolCommonNegative(
|
||||
std::bind(hipGraphExecMemcpyNodeSetParamsFromSymbol, graph_exec, node, _1, _2, _3, _4, _5),
|
||||
var.ptr(), SYMBOL(int_device_var), sizeof(*var.ptr()));
|
||||
|
||||
// Disabled on AMD due to defect
|
||||
#if HT_NVIDIA
|
||||
SECTION("Changing memcpy direction") {
|
||||
HIP_CHECK_ERROR(hipGraphExecMemcpyNodeSetParamsFromSymbol(
|
||||
graph_exec, node, var.ptr(), SYMBOL(int_device_var), sizeof(*var.ptr()), 0,
|
||||
hipMemcpyDeviceToHost),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Changing dst allocation device") {
|
||||
if (HipTest::getDeviceCount() < 2) {
|
||||
HipTest::HIP_SKIP_TEST("Test requires two connected GPUs");
|
||||
return;
|
||||
}
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
LinearAllocGuard<int> new_var(LinearAllocs::hipMalloc, sizeof(int));
|
||||
HIP_CHECK_ERROR(hipGraphExecMemcpyNodeSetParamsFromSymbol(
|
||||
graph_exec, node, new_var.ptr(), SYMBOL(int_device_var),
|
||||
sizeof(*new_var.ptr()), 0, static_cast<hipMemcpyKind>(-1)),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsFromSymbol Functional scenario.
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphExecMemcpyNodeSetParamsFromSymbol API:
|
||||
Functional
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
Negative
|
||||
1) Pass hGraphExec as nullptr and check if api returns error.
|
||||
2) Pass GraphNode as nullptr and check if api returns error.
|
||||
3) Pass destination ptr as nullptr, api expected to return error code.
|
||||
4) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
5) Pass count as zero, api expected to return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as source ptr and destination ptr, api expected to return error code.
|
||||
8) Pass Pass both dstn ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from device ptr to host ptr but pass kind as different, api expected to return error code.
|
||||
10) Check with other graph node but pass same graphExec, api expected to return error code.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsFromSymbol API Negative scenarios.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(nullptr,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
nullptr, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass destination ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, nullptr,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
nullptr,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source and destination ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from device ptr to host ptr but pass kind as different") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_h,
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipSuccess != ret);
|
||||
}
|
||||
SECTION("Check with other graph node") {
|
||||
hipGraphNode_t memcpyFromSymbolNode1{};
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode1,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(bool useConstVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
hipGraphNode_t memcpyD2H_B;
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Update the node with B_d destination pointer from C_d
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsFromSymbol Functional scenario.
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsFromSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
@@ -6,312 +6,192 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphExecMemcpyNodeSetParamsToSymbol API:
|
||||
Functional :
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
Negative :
|
||||
1) Pass hGraphExec as nullptr and check if api returns error.
|
||||
2) Pass GraphNode as nullptr and check if api returns error.
|
||||
3) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
4) Pass source ptr as nullptr, api expected to return error code.
|
||||
5) Pass count as zero, api expected to return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as source ptr and destination ptr, api expected to return error code.
|
||||
8) Pass Pass both dstn ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from device ptr to host ptr but pass kind as different, api expected to return error code.
|
||||
10) Check with other graph node but pass same graphExec, api expected to return error code.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE], globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
|
||||
__global__ void MemcpyToSymbolExecKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
}
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(double)
|
||||
|
||||
template <typename T>
|
||||
void GraphExecMemcpyToSymbolSetParamsShell(const void* symbol, const void* alt_symbol,
|
||||
size_t offset, const std::vector<T> set_values) {
|
||||
const auto f = [alt_symbol, is_arr = set_values.size() > 1](const void* symbol, void* src,
|
||||
size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(
|
||||
&node, graph, nullptr, 0, alt_symbol, reinterpret_cast<T*>(src) + is_arr,
|
||||
count - is_arr * sizeof(T), offset + is_arr * sizeof(T), direction));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsToSymbol(graph_exec, node, symbol, src, count, offset,
|
||||
direction));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyToSymbolShell(f, symbol, offset, std::move(set_values));
|
||||
}
|
||||
|
||||
__global__ void MemcpyToConstSymbolExecKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalConst[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipError_t ret;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(nullptr,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
nullptr,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
nullptr,
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass source ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, 0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source ptr and destination ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from device ptr to host ptr but pass kind as different") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_h,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipSuccess != ret);
|
||||
}
|
||||
SECTION("Check with other graph node but pass same graphExec") {
|
||||
hipGraph_t graph1;
|
||||
hipGraphNode_t memcpyToSymbolNode1{};
|
||||
HIP_CHECK(hipGraphCreate(&graph1, 0));
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode1, graph1,
|
||||
nullptr,
|
||||
0,
|
||||
HIP_SYMBOL(globalOut),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode1,
|
||||
HIP_SYMBOL(globalOut),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(bool useConstVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
if (useConstVar) {
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyToConstSymbolExecKernel);
|
||||
} else {
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(MemcpyToSymbolExecKernel);
|
||||
}
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Update the node with source pointer from C_d to A_d
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalConst), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsToSymbol Functional scenario.
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
/**
|
||||
* @addtogroup hipGraphExecMemcpyNodeSetParamsToSymbol hipGraphExecMemcpyNodeSetParamsToSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphExecMemcpyNodeSetParamsToSymbol(hipGraphExec_t hGraphExec, hipGraphNode_t node,
|
||||
* const void *symbol, void *src, size_t count, size_t offset, hipMemcpyKind kind)` -
|
||||
* Sets the parameters for a memcpy node in the given graphExec to copy to a symbol on the device
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(false);
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied to a symbol after node parameters are set following
|
||||
* node addition. A graph is constructed to which a MemcpyToSymbol node is added with valid but
|
||||
* incorrect parameters. After the graph is instantiated the parameters are updated to correct
|
||||
* values and the graph executed. After graph execution, a MemcpyFromSymbol is performed and the
|
||||
* copied values are compared against values known to have been copied to symbol memory previously.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for destination memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemcpyNodeSetParamsToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyToSymbolSetParamsShell, 10,
|
||||
char);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(true);
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyToSymbolSetParamsShell, 10,
|
||||
int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyToSymbolSetParamsShell, 10,
|
||||
float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphExecMemcpyToSymbolSetParamsShell, 10,
|
||||
double);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# gGraphExec is nullptr
|
||||
* -# node is nullptr
|
||||
* -# src is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyDeviceToHost)
|
||||
* -# kind is an invalid enum value
|
||||
* -# Changing memcpy direction
|
||||
* -# Changing src to memory allocated on a different device than the original src
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemcpyNodeSetParamsToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
LinearAllocGuard<int> var(LinearAllocs::hipMalloc, sizeof(int));
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&node, graph, nullptr, 0, SYMBOL(int_device_var),
|
||||
var.ptr(), sizeof(*var.ptr()), 0, hipMemcpyDefault));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("hGraphExec == nullptr") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol(nullptr, node, SYMBOL(int_device_var), var.ptr(),
|
||||
sizeof(*var.ptr()), 0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol(graph_exec, nullptr, SYMBOL(int_device_var),
|
||||
var.ptr(), sizeof(*var.ptr()), 0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
MemcpyToSymbolCommonNegative(
|
||||
std::bind(hipGraphExecMemcpyNodeSetParamsToSymbol, graph_exec, node, _1, _2, _3, _4, _5),
|
||||
SYMBOL(int_device_var), var.ptr(), sizeof(*var.ptr()));
|
||||
|
||||
SECTION("Changing memcpy direction") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol(graph_exec, node, SYMBOL(int_device_var), var.ptr(),
|
||||
sizeof(*var.ptr()), 0, hipMemcpyHostToDevice),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Changing src allocation device") {
|
||||
if (HipTest::getDeviceCount() < 2) {
|
||||
HipTest::HIP_SKIP_TEST("Test requires two connected GPUs");
|
||||
return;
|
||||
}
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
LinearAllocGuard<int> new_var(LinearAllocs::hipMalloc, sizeof(int));
|
||||
HIP_CHECK_ERROR(hipGraphExecMemcpyNodeSetParamsFromSymbol(
|
||||
graph_exec, node, SYMBOL(int_device_var), new_var.ptr(),
|
||||
sizeof(*new_var.ptr()), 0, static_cast<hipMemcpyKind>(-1)),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphExecMemcpyNodeSetParamsToSymbol API:
|
||||
Functional :
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
Negative :
|
||||
1) Pass hGraphExec as nullptr and check if api returns error.
|
||||
2) Pass GraphNode as nullptr and check if api returns error.
|
||||
3) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
4) Pass source ptr as nullptr, api expected to return error code.
|
||||
5) Pass count as zero, api expected to return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as source ptr and destination ptr, api expected to return error code.
|
||||
8) Pass Pass both dstn ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from device ptr to host ptr but pass kind as different, api expected to return error code.
|
||||
10) Check with other graph node but pass same graphExec, api expected to return error code.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE], globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
__global__ void MemcpyToSymbolExecKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void MemcpyToConstSymbolExecKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalConst[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipError_t ret;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(nullptr,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
nullptr,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
nullptr,
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass source ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, 0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source ptr and destination ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from device ptr to host ptr but pass kind as different") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_h,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipSuccess != ret);
|
||||
}
|
||||
SECTION("Check with other graph node but pass same graphExec") {
|
||||
hipGraph_t graph1;
|
||||
hipGraphNode_t memcpyToSymbolNode1{};
|
||||
HIP_CHECK(hipGraphCreate(&graph1, 0));
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode1, graph1,
|
||||
nullptr,
|
||||
0,
|
||||
HIP_SYMBOL(globalOut),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
ret = hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode1,
|
||||
HIP_SYMBOL(globalOut),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(bool useConstVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
if (useConstVar) {
|
||||
kernelNodeParams.func =
|
||||
reinterpret_cast<void *>(MemcpyToConstSymbolExecKernel);
|
||||
} else {
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(MemcpyToSymbolExecKernel);
|
||||
}
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Update the node with source pointer from C_d to A_d
|
||||
if (useConstVar) {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalConst), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphExecMemcpyNodeSetParamsToSymbol(graphExec,
|
||||
memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphExecMemcpyNodeSetParamsToSymbol Functional scenario.
|
||||
1) Allocate global symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, Instantiate a graph with memcpy node,
|
||||
obtain executable graph and update the node params with set exec api call.
|
||||
Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsToSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphExecMemcpyNodeSetParamsToSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,196 +6,208 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
Functional-
|
||||
1) Instantiate a graph with memset node, obtain executable graph and update the
|
||||
hipMemsetParams node params with set. Make sure they are taking effect.
|
||||
Negative-
|
||||
1) Pass hGraphExec as nullptr and verify api returns error code.
|
||||
2) Pass graph node as nullptr and verify api returns error code.
|
||||
3) Pass different hipGraphNode_t which was not used in graphExec and verify api returns error code.
|
||||
4) Pass Pass different Graph which was not used in graphExec and verify api returns error code.
|
||||
5) Pass pNodeParams as nullptr and verify api returns error code.
|
||||
6) Pass pNodeParams as empty structure object and verify api returns error code.
|
||||
7) Pass hipMemsetParams::dst as nullptr, api should return error code.
|
||||
8) Pass hipMemsetParams::element size other than 1, 2, or 4 and check api should return error code.
|
||||
9) Pass hipMemsetParams::height as zero and check api should return error code.
|
||||
*/
|
||||
#include <functional>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
/* Test verifies hipGraphExecMemsetNodeSetParams API Negative scenarios.
|
||||
#include "graph_memset_node_test_common.hh"
|
||||
#include "graph_tests_common.hh"
|
||||
|
||||
/**
|
||||
* @addtogroup hipGraphExecMemsetNodeSetParams hipGraphExecMemsetNodeSetParams
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphExecMemsetNodeSetParams(hipGraphExec_t hGraphExec, hipGraphNode_t node, const
|
||||
* hipMemsetParams *pNodeParams)` -
|
||||
* Sets the parameters for a memset node in the given graphExec
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Negative") {
|
||||
constexpr size_t N = 1024;
|
||||
constexpr size_t Nbytes = N * sizeof(char);
|
||||
constexpr size_t val = 0;
|
||||
char *devData, *hOutputData;
|
||||
|
||||
HIP_CHECK(hipMalloc(&devData, Nbytes));
|
||||
hOutputData = reinterpret_cast<char *>(malloc(Nbytes));
|
||||
REQUIRE(hOutputData != nullptr);
|
||||
memset(hOutputData, 0, Nbytes);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipError_t ret;
|
||||
hipGraphExec_t graphExec;
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphNode_t memsetNode;
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that node parameters get updated correctly by creating a node with valid but
|
||||
* incorrect parameters, and then setting them to the correct values in the executable graph.
|
||||
* The executable graph is run and the results of the memset is verified.
|
||||
* hipGraphMemsetNodeGetParams is used to verify that node parameters in the graph were not updated,
|
||||
* which also constitutes a test for said API.
|
||||
* The test is repeated for all valid element sizes(1,
|
||||
* 2, 4), and several allocations of different width(height is always 1 because only 1D memset nodes
|
||||
* can be updated), both on host and device
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemsetNodeSetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEMPLATE_TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic", "", uint8_t, uint16_t,
|
||||
uint32_t) {
|
||||
const size_t width = GENERATE(1, 64, kPageSize / sizeof(TestType) + 1);
|
||||
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
|
||||
hipMemsetParams mParams{};
|
||||
memset(&mParams, 0, sizeof(mParams));
|
||||
mParams.dst = reinterpret_cast<void*>(devData);
|
||||
mParams.value = val;
|
||||
mParams.pitch = 0;
|
||||
mParams.elementSize = sizeof(char);
|
||||
mParams.width = Nbytes;
|
||||
mParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &mParams));
|
||||
hipGraphNode_t node = nullptr;
|
||||
LinearAllocGuard<TestType> initial_alloc(LinearAllocs::hipMalloc, 2 * sizeof(TestType));
|
||||
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
dependencies.push_back(memsetNode);
|
||||
hipMemsetParams initial_params = {};
|
||||
initial_params.dst = initial_alloc.ptr();
|
||||
initial_params.elementSize = sizeof(TestType);
|
||||
initial_params.width = 2;
|
||||
initial_params.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, &initial_params));
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemsetNodeSetParams(nullptr, memsetNode, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass hGraphNode as nullptr") {
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, nullptr, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass different hGraphNode which was not used in graphExec") {
|
||||
hipGraphNode_t memsetNode1{};
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode1, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass different Graph which was not used in graphExec") {
|
||||
hipGraph_t graph1;
|
||||
HIP_CHECK(hipGraphCreate(&graph1, 0));
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph1, nullptr, 0, &mParams));
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
HIP_CHECK(hipGraphDestroy(graph1));
|
||||
}
|
||||
SECTION("Pass pNodeParams as nullptr") {
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass pNodeParams as empty structure object") {
|
||||
hipMemsetParams mParmTemp{};
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParmTemp);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("Pass hipMemsetParams::dst as nullptr") {
|
||||
mParams.dst = nullptr;
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass hipMemsetParams::element size other than 1, 2, or 4") {
|
||||
mParams.dst = reinterpret_cast<void*>(devData);
|
||||
mParams.elementSize = 9;
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass hipMemsetParams::height as zero") {
|
||||
mParams.elementSize = sizeof(char);
|
||||
mParams.height = 0;
|
||||
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
LinearAllocGuard2D<TestType> alloc(width, 1);
|
||||
constexpr TestType set_value = 42;
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(TestType);
|
||||
params.width = width;
|
||||
params.height = 1;
|
||||
params.value = set_value;
|
||||
HIP_CHECK(hipGraphExecMemsetNodeSetParams(graph_exec, node, ¶ms));
|
||||
|
||||
free(hOutputData);
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
hipMemsetParams retrieved_params = {};
|
||||
HIP_CHECK(hipGraphMemsetNodeGetParams(node, &retrieved_params));
|
||||
REQUIRE(initial_params.dst == retrieved_params.dst);
|
||||
REQUIRE(initial_params.elementSize == retrieved_params.elementSize);
|
||||
REQUIRE(initial_params.width == retrieved_params.width);
|
||||
REQUIRE(initial_params.height == retrieved_params.height);
|
||||
REQUIRE(initial_params.pitch == retrieved_params.pitch);
|
||||
REQUIRE(initial_params.value == retrieved_params.value);
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
LinearAllocGuard<TestType> buffer(LinearAllocs::hipHostMalloc, width * sizeof(TestType));
|
||||
HIP_CHECK(hipMemcpy2D(buffer.ptr(), width * sizeof(TestType), alloc.ptr(), alloc.pitch(),
|
||||
width * sizeof(TestType), 1, hipMemcpyDeviceToHost));
|
||||
ArrayFindIfNot(buffer.ptr(), set_value, width);
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphExecMemsetNodeSetParams API Functional scenarios.
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behaviour with invalid arguments:
|
||||
* -# pGraphExec is nullptr
|
||||
* -# node is nullptr
|
||||
* -# pNodeParams is nullptr
|
||||
* -# pNodeParams::dst is nullptr
|
||||
* -# pNodeParams::elementSize is different from 1, 2, and 4
|
||||
* -# pNodeParams::width is zero
|
||||
* -# pNodeParams::width is larger than the allocated memory region
|
||||
* -# pNodeParams::height is zero
|
||||
* -# pNodeParams::pitch is less than width when height is more than 1
|
||||
* -# pNodeParams::pitch * pMemsetParams::height is larger than the allocated memory region
|
||||
* -# pNodeParams::dst holds a pointer to memory allocated on a device different from the one
|
||||
* the original dst was allocated on
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemsetNodeSetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Functional") {
|
||||
constexpr size_t N = 1024;
|
||||
constexpr size_t Nbytes = N * sizeof(char);
|
||||
constexpr size_t val = 0;
|
||||
constexpr size_t updateVal = 2;
|
||||
char *devData, *devData1, *hOutputData, *hOutputData1;
|
||||
|
||||
HIP_CHECK(hipMalloc(&devData, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&devData1, Nbytes));
|
||||
hOutputData = reinterpret_cast<char *>(malloc(Nbytes));
|
||||
REQUIRE(hOutputData != nullptr);
|
||||
memset(hOutputData, updateVal, Nbytes);
|
||||
hOutputData1 = reinterpret_cast<char *>(malloc(Nbytes));
|
||||
REQUIRE(hOutputData1 != nullptr);
|
||||
memset(hOutputData1, 0, Nbytes);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphNode_t memsetNode;
|
||||
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = val;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
LinearAllocGuard<int> alloc(LinearAllocs::hipMalloc, 4 * sizeof(int));
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(*alloc.ptr());
|
||||
params.width = 1;
|
||||
params.height = 1;
|
||||
params.value = 42;
|
||||
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
dependencies.push_back(memsetNode);
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, ¶ms))
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData1);
|
||||
memsetParams.value = updateVal;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
SECTION("pGraphExec == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphExecMemsetNodeSetParams(nullptr, node, ¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
REQUIRE(hipSuccess == hipGraphExecMemsetNodeSetParams(graphExec, memsetNode,
|
||||
&memsetParams));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphExecMemsetNodeSetParams(graph_exec, nullptr, ¶ms),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpy(hOutputData1, devData1, Nbytes, hipMemcpyDeviceToHost));
|
||||
HipTest::checkArray(hOutputData, hOutputData1, Nbytes, 1);
|
||||
MemsetCommonNegative(std::bind(hipGraphExecMemsetNodeSetParams, graph_exec, node, _1), params);
|
||||
|
||||
free(hOutputData);
|
||||
free(hOutputData1);
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipFree(devData1));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
SECTION("Changing dst allocation device") {
|
||||
if (HipTest::getDeviceCount() < 2) {
|
||||
HipTest::HIP_SKIP_TEST("Test requires two connected GPUs");
|
||||
return;
|
||||
}
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
LinearAllocGuard<int> new_alloc(LinearAllocs::hipMalloc, 4 * sizeof(int));
|
||||
params.dst = new_alloc.ptr();
|
||||
HIP_CHECK_ERROR(hipGraphExecMemsetNodeSetParams(graph_exec, node, ¶ms),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that a 2D node cannot be updated
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphExecMemsetNodeSetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Negative_Updating_Non1D_Node") {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
LinearAllocGuard2D<int> alloc(2, 2);
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(*alloc.ptr());
|
||||
params.width = 1;
|
||||
params.height = 2;
|
||||
params.pitch = alloc.pitch();
|
||||
params.value = 42;
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, ¶ms))
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
params.width = 2;
|
||||
HIP_CHECK_ERROR(hipGraphExecMemsetNodeSetParams(graph_exec, node, ¶ms), hipErrorInvalidValue);
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
}
|
||||
|
||||
@@ -6,255 +6,156 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphMemcpyNodeSetParamsFromSymbol API:
|
||||
|
||||
Functional :
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
|
||||
Negative :
|
||||
1) Pass GraphNode as nullptr and check if api returns error.
|
||||
2) Pass destination ptr as nullptr, api expected to return error code.
|
||||
3) Pass source/symbol ptr as nullptr, api expected to return error code.
|
||||
4) Pass count as zero, api expected to return error code.
|
||||
5) Pass count more than allocated size for source and destination ptr, api should return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as destination ptr and source ptr, api expected to return error code.
|
||||
8) Pass both destination ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsFromSymbol API Negative scenarios.
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(double)
|
||||
|
||||
template <typename T>
|
||||
void GraphMemcpyFromSymbolSetParamsShell(const void* symbol, const void* alt_symbol, size_t offset,
|
||||
const std::vector<T> expected) {
|
||||
const auto f = [alt_symbol, is_arr = expected.size() > 1](void* dst, const void* symbol,
|
||||
size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(
|
||||
&node, graph, nullptr, 0, reinterpret_cast<T*>(dst) + is_arr, alt_symbol,
|
||||
count - is_arr * sizeof(T), offset + is_arr * sizeof(T), hipMemcpyDefault));
|
||||
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(node, dst, symbol, count, offset, direction));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyFromSymbolShell(f, symbol, offset, std::move(expected));
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup hipGraphMemcpyNodeSetParamsFromSymbol hipGraphMemcpyNodeSetParamsFromSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphMemcpyNodeSetParamsFromSymbol(hipGraphNode_t node, void *dst, const void *symbol, size_t
|
||||
* count, size_t offset, hipMemcpyKind kind)` -
|
||||
* Sets a memcpy node's parameters to copy from a symbol on the device
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied from a symbol after node parameters are set following
|
||||
* node addition. A graph is constructed to which a MemcpyFromSymbol node is added with valid but
|
||||
* incorrect parameters. The parameters are then updated to correct values and the graph executed.
|
||||
* Values in destination memory are compared against values known to be in symbol memory.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for destination memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemcpyNodeSetParamsFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolSetParamsShell, 1,
|
||||
char);
|
||||
}
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolSetParamsShell, 1,
|
||||
int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolSetParamsShell, 1,
|
||||
float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyFromSymbolSetParamsShell, 1,
|
||||
double);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# node is nullptr
|
||||
* -# dst is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyHostToDevice)
|
||||
* -# kind is an invalid enum value
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemcpyNodeSetParamsFromSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
int var = 0;
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&node, graph, nullptr, 0, &var, SYMBOL(int_device_var),
|
||||
sizeof(var), 0, hipMemcpyDefault));
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphMemcpyNodeSetParamsFromSymbol(nullptr, &var, SYMBOL(int_device_var),
|
||||
sizeof(var), 0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
MemcpyFromSymbolCommonNegative(
|
||||
std::bind(hipGraphMemcpyNodeSetParamsFromSymbol, node, _1, _2, _3, _4, _5), &var,
|
||||
SYMBOL(int_device_var), sizeof(var));
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(nullptr, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass destination ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, nullptr,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass source/symbol ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
nullptr,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
0, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count more than allocated size for source and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes+10, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset non zero so that offset+count > allocated size") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as dstn ptr and source ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalConst),
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalOut),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(bool useConstDeviceVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
hipGraphNode_t memcpyD2H_B;
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Update the node with B_d destination pointer from C_d
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsFromSymbol API Functional scenario.
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphMemcpyNodeSetParamsFromSymbol API:
|
||||
|
||||
Functional :
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
|
||||
Negative :
|
||||
1) Pass GraphNode as nullptr and check if api returns error.
|
||||
2) Pass destination ptr as nullptr, api expected to return error code.
|
||||
3) Pass source/symbol ptr as nullptr, api expected to return error code.
|
||||
4) Pass count as zero, api expected to return error code.
|
||||
5) Pass count more than allocated size for source and destination ptr, api should return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same symbol pointer as destination ptr and source ptr, api expected to return error code.
|
||||
8) Pass both destination ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE];
|
||||
__device__ int globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsFromSymbol API Negative scenarios.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
// Adding MemcpyNodeToSymbol
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(nullptr, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass destination ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, nullptr,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass source/symbol ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
nullptr,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
0, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count more than allocated size for source and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes+10, 0,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset non zero so that offset+count > allocated size") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode, B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 10,
|
||||
hipMemcpyDeviceToHost);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as dstn ptr and source ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalConst),
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass both dstn ptr and source ptr as 2 different symbol ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
HIP_SYMBOL(globalOut),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(bool useConstDeviceVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
hipGraphNode_t memcpyD2H_B;
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
C_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyFromSymbolNode);
|
||||
|
||||
// Update the node with B_d destination pointer from C_d
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsFromSymbol(memcpyFromSymbolNode,
|
||||
B_d,
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsFromSymbol API Functional scenario.
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsFromSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsFromSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
@@ -6,260 +6,157 @@ 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphMemcpyNodeSetParamsToSymbol API:
|
||||
Functional :
|
||||
1) Allocate global symbol memory, add the node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add the node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
Negative :
|
||||
1) Pass GraphNode as nullptr and check if api returns error.
|
||||
2) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
3) Pass src ptr as nullptr, api expected to return error code.
|
||||
4) Pass count as zero, api expected to return error code.
|
||||
5) Pass count more than allocated size for source and destination ptr, api should return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same pointer as source ptr and symbol ptr, api expected to return error code.
|
||||
8) Pass both destination ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from host ptr to device ptr but pass kind as different, api expected to return error code.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE], globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
#include "graph_memcpy_to_from_symbol_common.hh"
|
||||
|
||||
__global__ void CpyToSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
}
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_GLOBALS(double)
|
||||
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(char)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(int)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(float)
|
||||
HIP_GRAPH_MEMCPY_FROM_SYMBOL_NODE_DEFINE_ALTERNATE_GLOBALS(double)
|
||||
|
||||
template <typename T>
|
||||
void GraphMemcpyToSymbolSetParamsShell(const void* symbol, const void* alt_symbol, size_t offset,
|
||||
const std::vector<T> set_values) {
|
||||
const auto f = [alt_symbol, is_arr = set_values.size() > 1](const void* symbol, void* src,
|
||||
size_t count, size_t offset,
|
||||
hipMemcpyKind direction) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(
|
||||
&node, graph, nullptr, 0, alt_symbol, reinterpret_cast<T*>(src) + is_arr,
|
||||
count - is_arr * sizeof(T), offset + is_arr * sizeof(T), direction));
|
||||
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(node, symbol, src, count, offset, direction));
|
||||
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
MemcpyToSymbolShell(f, symbol, offset, std::move(set_values));
|
||||
}
|
||||
|
||||
__global__ void CpyToConstSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalConst[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphMemcpyNodeSetParamsToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipError_t ret;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(nullptr,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
nullptr,
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass src ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, 0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count more than allocated size for source and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes+8, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source ptr and destination ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass 2 different symbol pointer as source ptr and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from host ptr to device ptr but pass kind as different") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_h,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(bool useConstDeviceVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Update the node with source pointer from C_d to A_d
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalConst), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
if (useConstDeviceVar)
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(CpyToConstSymbolKernel);
|
||||
else
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(CpyToSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
HIP_CHECK(hipStreamSynchronize(0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsToSymbol API Functional scenario.
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
/**
|
||||
* @addtogroup hipGraphMemcpyNodeSetParamsToSymbol hipGraphMemcpyNodeSetParamsToSymbol
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphMemcpyNodeSetParamsToSymbol(hipGraphNode_t node, const void *symbol, const void *src,
|
||||
* size_t count, size_t offset, hipMemcpyKind kind)` -
|
||||
* Sets a memcpy node's parameters to copy to a symbol on the device
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(false);
|
||||
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that data is correctly copied to a symbol after node parameters are set following
|
||||
* node addition. A graph is constructed to which a MemcpyToSymbol node is added with valid but
|
||||
* incorrect parameters. The parameters are then updated to correct values and the graph executed.
|
||||
* After graph execution, a MemcpyFromSymbol is performed and the copied values are compared against
|
||||
* values known to have been copied to symbol memory previously.
|
||||
* The test is run for scalar, const scalar, array, and const array symbols of types char, int,
|
||||
* float and double. For array symbols, the test is repeated for zero and non-zero offset values.
|
||||
* Verification is performed for destination memory allocated on host and device.
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemcpyNodeSetParamsToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Positive_Basic") {
|
||||
SECTION("char") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolSetParamsShell, 10,
|
||||
char);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(true);
|
||||
|
||||
SECTION("int") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolSetParamsShell, 10,
|
||||
int);
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolSetParamsShell, 10,
|
||||
float);
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
HIP_GRAPH_MEMCPY_NODE_SET_PARAMS_TO_FROM_SYMBOL_TEST(GraphMemcpyToSymbolSetParamsShell, 10,
|
||||
double);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behavior with invalid arguments:
|
||||
* -# node is nullptr
|
||||
* -# src is nullptr
|
||||
* -# symbol is nullptr
|
||||
* -# count is zero
|
||||
* -# count is larger than symbol size
|
||||
* -# count + offset is larger than symbol size
|
||||
* -# kind is illogical (hipMemcpyDeviceToHost)
|
||||
* -# kind is an invalid enum value
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemcpyNodeSetParamsToSymbol.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
int var = 0;
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&node, graph, nullptr, 0, SYMBOL(int_device_var), &var,
|
||||
sizeof(var), 0, hipMemcpyDefault));
|
||||
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphMemcpyNodeSetParamsToSymbol(nullptr, SYMBOL(int_device_var), &var,
|
||||
sizeof(var), 0, hipMemcpyDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
MemcpyToSymbolCommonNegative(
|
||||
std::bind(hipGraphMemcpyNodeSetParamsToSymbol, node, _1, _2, _3, _4, _5),
|
||||
SYMBOL(int_device_var), &var, sizeof(var));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios of hipGraphMemcpyNodeSetParamsToSymbol API:
|
||||
Functional :
|
||||
1) Allocate global symbol memory, add the node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add the node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
Negative :
|
||||
1) Pass GraphNode as nullptr and check if api returns error.
|
||||
2) Pass symbol ptr as nullptr, api expected to return error code.
|
||||
3) Pass src ptr as nullptr, api expected to return error code.
|
||||
4) Pass count as zero, api expected to return error code.
|
||||
5) Pass count more than allocated size for source and destination ptr, api should return error code.
|
||||
6) Pass offset+count greater than allocated size, api expected to return error code.
|
||||
7) Pass same pointer as source ptr and symbol ptr, api expected to return error code.
|
||||
8) Pass both destination ptr and source ptr as 2 different symbol ptr, api expected to return error code.
|
||||
9) Copy from host ptr to device ptr but pass kind as different, api expected to return error code.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <limits>
|
||||
#define SIZE 256
|
||||
|
||||
__device__ int globalIn[SIZE], globalOut[SIZE];
|
||||
__device__ __constant__ int globalConst[SIZE];
|
||||
|
||||
__global__ void CpyToSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalIn[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void CpyToConstSymbolKernel(int* B_d) {
|
||||
for (int i = 0 ; i < SIZE; i++) {
|
||||
B_d[i] = globalConst[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* This testcase verifies negative scenarios of
|
||||
hipGraphMemcpyNodeSetParamsToSymbol API */
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Negative") {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
int *A_d{nullptr}, *B_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipError_t ret;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(nullptr,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
nullptr,
|
||||
B_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
SECTION("Pass src ptr as nullptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
nullptr, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, 0, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass count more than allocated size for source and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes+8, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass offset+count greater than allocated size") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
B_d, Nbytes, 10,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass same symbol pointer as source ptr and destination ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalIn),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass 2 different symbol pointer as source ptr and dstn ptr") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Copy from host ptr to device ptr but pass kind as different") {
|
||||
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn),
|
||||
A_h,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static
|
||||
void hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(bool useConstDeviceVar) {
|
||||
constexpr size_t Nbytes = SIZE * sizeof(int);
|
||||
constexpr auto blocksPerCU = 6; // to hide latency
|
||||
constexpr auto threadsPerBlock = 256;
|
||||
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
|
||||
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
int *A_h{nullptr}, *B_h{nullptr};
|
||||
HipTest::initArrays<int>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, SIZE, false);
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
dependencies.push_back(memcpyH2D_A);
|
||||
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalConst),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
|
||||
dependencies.data(),
|
||||
dependencies.size(),
|
||||
HIP_SYMBOL(globalIn),
|
||||
C_d, Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpyToSymbolNode);
|
||||
|
||||
// Update the node with source pointer from C_d to A_d
|
||||
if (useConstDeviceVar) {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalConst), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
} else {
|
||||
HIP_CHECK(hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
|
||||
HIP_SYMBOL(globalIn), A_d,
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice));
|
||||
}
|
||||
|
||||
// Adding Kernel node
|
||||
void* kernelArgs1[] = {&B_d};
|
||||
if (useConstDeviceVar)
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(CpyToConstSymbolKernel);
|
||||
else
|
||||
kernelNodeParams.func = reinterpret_cast<void *>(CpyToSymbolKernel);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
|
||||
dependencies.data(), dependencies.size(),
|
||||
&kernelNodeParams));
|
||||
dependencies.clear();
|
||||
dependencies.push_back(memcpytosymbolkernel);
|
||||
|
||||
// Adding MemcpyNode
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
|
||||
dependencies.size(), B_h, B_d,
|
||||
Nbytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, 0));
|
||||
|
||||
// Validating the result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (B_h[i] != A_h[i]) {
|
||||
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HipTest::freeArrays<int>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemcpyNodeSetParamsToSymbol API Functional scenario.
|
||||
1) Allocate global symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
2) Allocate const symbol memory, add node to the graph.
|
||||
Set/Update the new values to the node. Make sure they are taking effect.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Functional") {
|
||||
SECTION("Check and update with Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(false);
|
||||
}
|
||||
SECTION("Check and update with Constant Global Device Symbol Memory") {
|
||||
hipGraphMemcpyNodeSetParamsToSymbol_GlobalMem(true);
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ 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,125 +19,65 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
Negative -
|
||||
1) Pass node as nullptr and verify api returns error code.
|
||||
2) Pass pNodeParams as nullptr and verify api returns error code.
|
||||
Functional -
|
||||
1) Create a graph, add Memset node to graph with desired node params.
|
||||
Verify api fetches the node params mentioned while adding Memset node.
|
||||
2) Set Memset node params with hipGraphMemsetNodeSetParams,
|
||||
now get the params and verify both are same.
|
||||
*/
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <resource_guards.hh>
|
||||
|
||||
/* Test verifies hipGraphMemsetNodeGetParams API Negative scenarios.
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeGetParams_Negative") {
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memsetNode;
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
char *devData;
|
||||
HIP_CHECK(hipMalloc(&devData, 1024));
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = 0;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = 1024;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
SECTION("Pass node as nullptr") {
|
||||
ret = hipGraphMemsetNodeGetParams(nullptr, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GetNodeParams as nullptr") {
|
||||
ret = hipGraphMemsetNodeGetParams(memsetNode, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemsetNodeGetParams API Functional scenarios.
|
||||
/**
|
||||
* @addtogroup hipGraphMemsetNodeGetParams hipGraphMemsetNodeGetParams
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphMemsetNodeGetParams(hipGraphNode_t node, hipMemsetParams *pNodeParams)` -
|
||||
* Gets a memset node's parameters
|
||||
* ________________________
|
||||
* Test cases from other APIs:
|
||||
* - @ref Unit_hipGraphMemsetNodeSetParams_Positive_Basic
|
||||
* - @ref Unit_hipGraphExecMemsetNodeSetParams_Positive_Basic
|
||||
*/
|
||||
|
||||
bool memsetNodeCompare(hipMemsetParams *mNode1, hipMemsetParams *mNode2) {
|
||||
if (mNode1->dst != mNode2->dst)
|
||||
return false;
|
||||
if (mNode1->elementSize != mNode2->elementSize)
|
||||
return false;
|
||||
if (mNode1->height != mNode2->height)
|
||||
return false;
|
||||
if (mNode1->pitch != mNode2->pitch)
|
||||
return false;
|
||||
if (mNode1->value != mNode2->value)
|
||||
return false;
|
||||
if (mNode1->width != mNode2->width)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behaviour with invalid arguments:
|
||||
* -# node is nullptr
|
||||
* -# pNodeParams is nullptr
|
||||
* -# node is destroyed
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemsetNodeGetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeGetParams_Negative_Parameters") {
|
||||
LinearAllocGuard2D<int> alloc(1, 1);
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(int);
|
||||
params.width = 1;
|
||||
params.height = 1;
|
||||
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeGetParams_Functional") {
|
||||
constexpr size_t N = 1024;
|
||||
constexpr size_t Nbytes = N * sizeof(char);
|
||||
constexpr size_t val = 0;
|
||||
hipGraph_t graph = nullptr;
|
||||
hipGraphNode_t node = nullptr;
|
||||
|
||||
char *devData;
|
||||
HIP_CHECK(hipMalloc(&devData, Nbytes));
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphNode_t memsetNode;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
hipStream_t streamForGraph;
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = val;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
SECTION("Get Memset Param and verify.") {
|
||||
hipMemsetParams memsetGetParams;
|
||||
REQUIRE(hipSuccess == hipGraphMemsetNodeGetParams(memsetNode,
|
||||
&memsetGetParams));
|
||||
// Validating the result
|
||||
REQUIRE(true == memsetNodeCompare(&memsetParams, &memsetGetParams));
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphMemsetNodeGetParams(nullptr, ¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Set memset node params then Get and verify.") {
|
||||
constexpr size_t updateVal = 2;
|
||||
char *devData1;
|
||||
HIP_CHECK(hipMalloc(&devData1, Nbytes));
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData1);
|
||||
memsetParams.value = updateVal;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
|
||||
hipMemsetParams memsetGetParams;
|
||||
REQUIRE(hipSuccess == hipGraphMemsetNodeSetParams(memsetNode,
|
||||
&memsetParams));
|
||||
REQUIRE(hipSuccess == hipGraphMemsetNodeGetParams(memsetNode,
|
||||
&memsetGetParams));
|
||||
// Validating the result
|
||||
REQUIRE(true == memsetNodeCompare(&memsetParams, &memsetGetParams));
|
||||
HIP_CHECK(hipFree(devData1));
|
||||
SECTION("pNodeParams == nullptr") {
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, ¶ms));
|
||||
HIP_CHECK_ERROR(hipGraphMemsetNodeGetParams(node, nullptr), hipErrorInvalidValue);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
// Disabled on AMD due to defect - EXSWHTEC-208
|
||||
#if 0
|
||||
SECTION("Node is destroyed") {
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, ¶ms));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK_ERROR(hipGraphMemsetNodeGetParams(node, ¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ 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,169 +19,130 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
Negative -
|
||||
1) Pass node as nullptr and verify api returns error code.
|
||||
2) Pass pNodeParams as nullptr and verify api returns error code.
|
||||
3) Passing hipMemsetParams::dst as nullptr should return error code.
|
||||
4) Passing hipMemsetParams::element size other than 1, 2, or 4 and check.
|
||||
5) Passing hipMemsetParams::height as zero and check api should return error code.
|
||||
Functional -
|
||||
1) Add Memset node to graph, update the node params with set and
|
||||
launch the graph and check the set params are executing properly.
|
||||
2) Add Memset node to graph, launch graph, then update the Memset node params
|
||||
with set and launch the graph and check updated params are taking effect.
|
||||
*/
|
||||
#include <functional>
|
||||
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
/* Test verifies hipGraphMemsetNodeSetParams API invalid params scenarios.
|
||||
#include "graph_memset_node_test_common.hh"
|
||||
#include "graph_tests_common.hh"
|
||||
|
||||
/**
|
||||
* @addtogroup hipGraphMemsetNodeSetParams hipGraphMemsetNodeSetParams
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipGraphMemsetNodeSetParams(hipGraphNode_t node, const hipMemsetParams *pNodeParams)` -
|
||||
* Sets a memset node's parameters
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeSetParams_InvalidParams") {
|
||||
hipError_t ret;
|
||||
hipGraph_t graph;
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphNode_t memsetNode;
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
|
||||
char *devData;
|
||||
HIP_CHECK(hipMalloc(&devData, 1024));
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.value = 0;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = 1024;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
SECTION("Pass node as nullptr") {
|
||||
ret = hipGraphMemsetNodeSetParams(nullptr, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass GetNodeParams as nullptr") {
|
||||
ret = hipGraphMemsetNodeSetParams(memsetNode, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass dest as nullptr") {
|
||||
memsetParams.dst = nullptr;
|
||||
ret = hipGraphMemsetNodeSetParams(memsetNode, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass element size other than 1, 2, or 4") {
|
||||
memsetParams.dst = reinterpret_cast<void*>(devData);
|
||||
memsetParams.elementSize = 9;
|
||||
ret = hipGraphMemsetNodeSetParams(memsetNode, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Pass height as zero or negative") {
|
||||
memsetParams.elementSize = 2;
|
||||
memsetParams.height = 0;
|
||||
ret = hipGraphMemsetNodeSetParams(memsetNode, &memsetParams);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
HIP_CHECK(hipFree(devData));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
}
|
||||
|
||||
static void validate_result(char *hData, size_t size, char val) {
|
||||
// Validating the result
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (hData[i] != val) {
|
||||
WARN("Validation failed at- " << i << " hData[i] " << hData[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Test verifies hipGraphMemsetNodeSetParams API Functional scenarios.
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify that node parameters get updated correctly by creating a node with valid but
|
||||
* incorrect parameters, and then setting them to the correct values after which the graph is
|
||||
* executed and the results verified.
|
||||
* The parameters are also verified via hipGraphMemsetNodeGetParams, which also constitutes a test
|
||||
* for said API.
|
||||
* The test is repeated for all valid element sizes(1, 2, 4), and several allocations of different
|
||||
* height and width both on host and device
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemsetNodeSetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeSetParams_Functional") {
|
||||
constexpr size_t N = 1024;
|
||||
constexpr size_t Nbytes = N * sizeof(char);
|
||||
constexpr size_t val = 0;
|
||||
constexpr size_t updateVal = 1;
|
||||
constexpr size_t updateVal2 = 2;
|
||||
char *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
|
||||
char *A_h{nullptr}, *B_h{nullptr};
|
||||
TEMPLATE_TEST_CASE("Unit_hipGraphMemsetNodeSetParams_Positive_Basic", "", uint8_t, uint16_t,
|
||||
uint32_t) {
|
||||
const auto f = [](hipMemsetParams* params) {
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
HipTest::initArrays<char>(&A_d, &B_d, &C_d,
|
||||
&A_h, &B_h, nullptr, N, false);
|
||||
hipGraphNode_t node = nullptr;
|
||||
LinearAllocGuard<TestType> initial_alloc(LinearAllocs::hipMalloc, 2 * sizeof(TestType));
|
||||
|
||||
hipGraph_t graph;
|
||||
hipGraphExec_t graphExec;
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphNode_t memsetNode;
|
||||
hipMemsetParams initial_params = {};
|
||||
initial_params.dst = initial_alloc.ptr();
|
||||
initial_params.elementSize = sizeof(TestType);
|
||||
initial_params.width = 2;
|
||||
initial_params.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, &initial_params));
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
hipMemsetParams retrieved_params = {};
|
||||
HIP_CHECK(hipGraphMemsetNodeGetParams(node, &retrieved_params));
|
||||
REQUIRE(initial_params.dst == retrieved_params.dst);
|
||||
REQUIRE(initial_params.elementSize == retrieved_params.elementSize);
|
||||
REQUIRE(initial_params.width == retrieved_params.width);
|
||||
REQUIRE(initial_params.height == retrieved_params.height);
|
||||
REQUIRE(initial_params.pitch == retrieved_params.pitch);
|
||||
REQUIRE(initial_params.value == retrieved_params.value);
|
||||
|
||||
hipMemsetParams memsetParams{};
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(C_d);
|
||||
memsetParams.value = val;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
|
||||
&memsetParams));
|
||||
HIP_CHECK(hipGraphMemsetNodeSetParams(node, params));
|
||||
HIP_CHECK(hipGraphMemsetNodeGetParams(node, &retrieved_params));
|
||||
REQUIRE(params->dst == retrieved_params.dst);
|
||||
REQUIRE(params->elementSize == retrieved_params.elementSize);
|
||||
REQUIRE(params->width == retrieved_params.width);
|
||||
REQUIRE(params->height == retrieved_params.height);
|
||||
REQUIRE(params->pitch == retrieved_params.pitch);
|
||||
REQUIRE(params->value == retrieved_params.value);
|
||||
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
dependencies.push_back(memsetNode);
|
||||
hipGraphExec_t graph_exec = nullptr;
|
||||
HIP_CHECK(hipGraphInstantiate(&graph_exec, graph, nullptr, nullptr, 0));
|
||||
|
||||
SECTION("Update the memsetNode and check") {
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(A_d);
|
||||
memsetParams.value = updateVal;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, dependencies.data(),
|
||||
dependencies.size(), &memsetParams));
|
||||
HIP_CHECK(hipGraphMemsetNodeSetParams(memsetNode, &memsetParams));
|
||||
dependencies.push_back(memsetNode);
|
||||
HIP_CHECK(hipGraphLaunch(graph_exec, hipStreamPerThread));
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
HIP_CHECK(hipGraphExecDestroy(graph_exec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
HIP_CHECK(hipMemcpy(A_h, A_d, Nbytes, hipMemcpyDeviceToHost));
|
||||
validate_result(A_h, Nbytes, updateVal);
|
||||
}
|
||||
SECTION("Update the memsetNode again and check") {
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = reinterpret_cast<void*>(B_d);
|
||||
memsetParams.value = updateVal2;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, dependencies.data(),
|
||||
dependencies.size(), &memsetParams));
|
||||
HIP_CHECK(hipGraphMemsetNodeSetParams(memsetNode, &memsetParams));
|
||||
dependencies.push_back(memsetNode);
|
||||
return hipSuccess;
|
||||
};
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
HIP_CHECK(hipMemcpy(B_h, B_d, Nbytes, hipMemcpyDeviceToHost));
|
||||
validate_result(B_h, Nbytes, updateVal2);
|
||||
}
|
||||
|
||||
HipTest::freeArrays<char>(A_d, B_d, C_d,
|
||||
A_h, B_h, nullptr, false);
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
GraphMemsetNodeCommonPositive<TestType>(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Verify API behaviour with invalid arguments:
|
||||
* -# node is nullptr
|
||||
* -# pNodeParams is nullptr
|
||||
* -# pNodeParams::dst is nullptr
|
||||
* -# pNodeParams::elementSize is different from 1, 2, and 4
|
||||
* -# pNodeParams::width is zero
|
||||
* -# pNodeParams::width is larger than the allocated memory region
|
||||
* -# pNodeParams::height is zero
|
||||
* -# pNodeParams::pitch is less than width when height is more than 1
|
||||
* -# pNodeParams::pitch * pMemsetParams::height is larger than the allocated memory region
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - unit/graph/hipGraphMemsetNodeSetParams.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphMemsetNodeSetParams_Negative_Parameters") {
|
||||
using namespace std::placeholders;
|
||||
|
||||
hipGraph_t graph = nullptr;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
LinearAllocGuard<int> alloc(LinearAllocs::hipMalloc, 4 * sizeof(int));
|
||||
hipMemsetParams params = {};
|
||||
params.dst = alloc.ptr();
|
||||
params.elementSize = sizeof(*alloc.ptr());
|
||||
params.width = 1;
|
||||
params.height = 1;
|
||||
params.value = 42;
|
||||
|
||||
hipGraphNode_t node = nullptr;
|
||||
HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, ¶ms))
|
||||
|
||||
SECTION("node == nullptr") {
|
||||
HIP_CHECK_ERROR(hipGraphMemsetNodeSetParams(nullptr, ¶ms), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
MemsetCommonNegative(std::bind(hipGraphMemsetNodeSetParams, node, _1), params);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
* @addtogroup hipLaunchHostFunc hipLaunchHostFunc
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipLaunchHostFunc(hipStream_t stream, hipHostFn_t fn, void *userData)` -
|
||||
* enqueues a host function call in a stream
|
||||
*/
|
||||
|
||||
static void hostNodeCallbackDummy(void* data) { REQUIRE(data == nullptr); }
|
||||
|
||||
static void hostNodeCallback(void* data) {
|
||||
float** userData = static_cast<float**>(data);
|
||||
|
||||
float input_data = *(userData[0]);
|
||||
float output_data = *(userData[1]);
|
||||
REQUIRE(input_data == output_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Stream is legacy/nullptr stream
|
||||
* -# Function is nullptr
|
||||
* -# Stream is uninitialized
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipLaunchHostFunc.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipLaunchHostFunc_Negative_Parameters") {
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
#if HT_NVIDIA // EXSWHTEC-228
|
||||
SECTION("Pass stream as nullptr") {
|
||||
hipHostFn_t fn = hostNodeCallbackDummy;
|
||||
HIP_CHECK_ERROR(hipLaunchHostFunc(nullptr, fn, nullptr), hipErrorStreamCaptureImplicit);
|
||||
}
|
||||
#endif
|
||||
SECTION("Pass functions as nullptr") {
|
||||
HIP_CHECK_ERROR(hipLaunchHostFunc(stream, nullptr, nullptr), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Pass uninitialized stream") {
|
||||
hipHostFn_t fn = hostNodeCallbackDummy;
|
||||
constexpr auto InvalidStream = [] {
|
||||
StreamGuard sg(Streams::created);
|
||||
return sg.stream();
|
||||
};
|
||||
HIP_CHECK_ERROR(hipLaunchHostFunc(InvalidStream(), fn, nullptr), hipErrorContextIsDestroyed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify enquing a host function into a stream, which checks if
|
||||
* the captured computation result is correct
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipLaunchHostFunc.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipLaunchHostFunc_Positive_Functional") {
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, sizeof(float));
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, sizeof(float));
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, sizeof(float));
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeGlobal;
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), 1, stream);
|
||||
|
||||
hipHostFn_t fn = hostNodeCallback;
|
||||
float* data[2] = {A_h.host_ptr(), B_h.host_ptr()};
|
||||
HIP_CHECK(hipLaunchHostFunc(stream, fn, static_cast<void*>(data)));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
// Validate end capture is successful
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), 1, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i), 1);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
static void thread_func_pos(hipStream_t* stream, hipHostFn_t fn, float** data){
|
||||
|
||||
HIP_CHECK(hipLaunchHostFunc(*stream, fn, static_cast<void*>(data)))}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify enquing a host function into a stream on a different
|
||||
* thread, which checks if the captured computation result is correct
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipLaunchHostFunc.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipLaunchHostFunc_Positive_Thread") {
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, sizeof(float));
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, sizeof(float));
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, sizeof(float));
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeGlobal;
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), 1, stream);
|
||||
|
||||
hipHostFn_t fn = hostNodeCallback;
|
||||
float* data[2] = {A_h.host_ptr(), B_h.host_ptr()};
|
||||
std::thread t(thread_func_pos, &stream, fn, data);
|
||||
t.join();
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
// Validate end capture is successful
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), 1, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i), 1);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
Το diff αρχείου καταστέλλεται επειδή είναι πολύ μεγάλο
Φόρτωση Διαφορών
Το diff αρχείου καταστέλλεται επειδή είναι πολύ μεγάλο
Φόρτωση Διαφορών
@@ -17,421 +17,190 @@ OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
Negative Testcase Scenarios :
|
||||
1) Pass stream as nullptr and verify there is no crash, api returns error code.
|
||||
2) Pass graph as nullptr and verify there is no crash, api returns error code.
|
||||
3) Pass graph as nullptr and and stream as hipStreamPerThread verify there
|
||||
is no crash, api returns error code.
|
||||
4) End capture on stream where capture has not yet started and verify
|
||||
error code is returned.
|
||||
5) Destroy stream and try to end capture.
|
||||
6) Destroy Graph and try to end capture.
|
||||
7) Begin capture on a thread with mode other than hipStreamCaptureModeRelaxed
|
||||
and try to end capture from different thread. Expect to return
|
||||
hipErrorStreamCaptureWrongThread.
|
||||
8) Start stream capture on stream1 using mode hipStreamCaptureModeRelaxed.
|
||||
In stream1 queue a memcpy operation, queue a kernel square of a number operation.
|
||||
Launch a thread. In the thread, queue a memcpy operation. End the capture on
|
||||
stream1 and return the captured graph. Wait for the thread in main function.
|
||||
Create an executable graph and launch the graph on input data and validate the
|
||||
output.
|
||||
9) Create 2 streams s1 and s2. Begin stream capture in s1, spawn a
|
||||
captured fork stream on s2. Queue some operations
|
||||
(like increment kernel) on both s1 and s2. End the stream capture
|
||||
on s2 and verify the error returned by the End capture.
|
||||
10)Create 2 streams s1 and s2. Begin stream capture in s1 and spawn a captured
|
||||
fork stream s2. In main thread, queue a memcpy operation on s1.
|
||||
Launch a thread, queue a memcpy operation on s2. Perform hipEventRecord on
|
||||
s2 and wait Event on S1. Wait for the thread to complete. Queue operations
|
||||
kernel addition(Cd = Ad + Bd) operation and memcpy(Ch <- Cd) in s1. End the
|
||||
stream capture in s1. Create an executable graph and launch the graph on input
|
||||
data and validate the output.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
* @addtogroup hipStreamEndCapture hipStreamEndCapture
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipStreamEndCapture(hipStream_t stream, hipGraph_t *pGraph)` -
|
||||
* ends capture on a stream, returning the captured graph
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# End capture on legacy/null stream
|
||||
* -# End capture when graph is nullptr
|
||||
* -# End capture on stream where capture has not yet started
|
||||
* -# Destroy stream and try to end capture
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamEndCapture.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Negative_Parameters") {
|
||||
hipGraph_t graph{nullptr};
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Negative") {
|
||||
hipError_t ret;
|
||||
SECTION("Pass stream as nullptr") {
|
||||
hipGraph_t graph;
|
||||
ret = hipStreamEndCapture(nullptr, &graph);
|
||||
REQUIRE(hipErrorIllegalState == ret);
|
||||
HIP_CHECK_ERROR(hipStreamEndCapture(nullptr, &graph), hipErrorIllegalState);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass graph as nullptr") {
|
||||
hipStream_t stream;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
ret = hipStreamEndCapture(stream, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
SECTION("Pass graph as nullptr and stream as hipStreamPerThread") {
|
||||
ret = hipStreamEndCapture(hipStreamPerThread, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
HIP_CHECK_ERROR(hipStreamEndCapture(stream, nullptr), hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
SECTION("End capture on stream where capture has not yet started") {
|
||||
hipStream_t stream;
|
||||
hipGraph_t graph;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipErrorIllegalState == ret);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK_ERROR(hipStreamEndCapture(stream, &graph), hipErrorIllegalState);
|
||||
}
|
||||
SECTION("Destroy stream and try to end capture") {
|
||||
hipStream_t stream;
|
||||
hipGraph_t graph;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipErrorContextIsDestroyed == ret);
|
||||
}
|
||||
SECTION("Destroy graph and try to end capture in between") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipSuccess == ret);
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
hipStream_t destroyed_stream;
|
||||
HIP_CHECK(hipStreamCreate(&destroyed_stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(destroyed_stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamDestroy(destroyed_stream));
|
||||
HIP_CHECK_ERROR(hipStreamEndCapture(destroyed_stream, &graph), hipErrorContextIsDestroyed);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_func(hipStream_t stream, hipGraph_t graph) {
|
||||
HIP_ASSERT(hipErrorStreamCaptureWrongThread ==
|
||||
hipStreamEndCapture(stream, &graph));
|
||||
}
|
||||
static void StreamEndCaptureThreadNegative(float* A_d, float* A_h,
|
||||
float* C_d, float* C_h, hipStreamCaptureMode mode) {
|
||||
hipStream_t stream{nullptr};
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify no error occurs when graph is destroyed before capture
|
||||
* ends
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamEndCapture.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Positive_GraphDestroy") {
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeGlobal;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
std::thread t(thread_func, stream, graph);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
}
|
||||
|
||||
static void thread_func_neg(hipStream_t stream, hipGraph_t graph) {
|
||||
HIP_ASSERT(hipErrorStreamCaptureWrongThread == hipStreamEndCapture(stream, &graph));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify that when capture is initiated on a thread with mode
|
||||
* other than hipStreamCaptureModeRelaxed and try to end capture from different
|
||||
* thread, it is expected to return hipErrorStreamCaptureWrongThread
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamEndCapture.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Negative_Thread") {
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeGlobal;
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
std::thread t(thread_func_neg, stream, graph);
|
||||
t.join();
|
||||
|
||||
#if HT_AMD
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
#endif
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Thread_Negative") {
|
||||
constexpr size_t N = 100000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
SECTION("Capture Mode:hipStreamCaptureModeGlobal") {
|
||||
StreamEndCaptureThreadNegative(A_d, A_h, C_d, C_h,
|
||||
hipStreamCaptureModeGlobal);
|
||||
}
|
||||
SECTION("Capture Mode:hipStreamCaptureModeThreadLocal") {
|
||||
StreamEndCaptureThreadNegative(A_d, A_h, C_d, C_h,
|
||||
hipStreamCaptureModeThreadLocal);
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
// Thread function
|
||||
static void thread_func1(hipStream_t stream, hipGraph_t *graph,
|
||||
size_t Nbytes, float* A_d, float* B_h) {
|
||||
HIP_CHECK(hipMemcpyAsync(B_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
static void thread_func_pos(hipStream_t stream, hipGraph_t* graph) {
|
||||
HIP_CHECK(hipStreamEndCapture(stream, graph));
|
||||
}
|
||||
/*
|
||||
* Start stream capture on stream1 using mode hipStreamCaptureModeRelaxed.
|
||||
* In stream1 queue a memcpy operation, queue a kernel square of a number operation.
|
||||
* Launch a thread. In the thread, queue a memcpy operation. End the capture on
|
||||
* stream1 and return the captured graph. Wait for the thread in main function.
|
||||
* Create an executable graph and launch the graph on input data and validate the output.
|
||||
* */
|
||||
TEST_CASE("Unit_hipStreamEndCapture_mode_hipStreamCaptureModeRelaxed") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 10;
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify that when capture is initiated on a thread with
|
||||
* hipStreamCaptureModeRelaxed mode, end capture in a different thread is
|
||||
* successful
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamEndCapture.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Positive_Thread") {
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
// Device Pointers
|
||||
float *A_d;
|
||||
// Host Pointers
|
||||
float *A_h, *B_h, *C_h;
|
||||
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
// Initialize the Host data
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.0f + i;
|
||||
C_h[i] = A_h[i];
|
||||
}
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeRelaxed));
|
||||
// Copy data from Host to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, A_d, N);
|
||||
// Thread Launch
|
||||
std::thread t(thread_func1, stream, &graph, Nbytes, A_d, B_h);
|
||||
t.join();
|
||||
|
||||
// Launch the graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Output verification
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
C_h[i] = C_h[i] * C_h[i];
|
||||
REQUIRE(B_h[i] == C_h[i]);
|
||||
}
|
||||
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
}
|
||||
|
||||
static __global__ void increment(int* A_d) {
|
||||
atomicAdd(A_d, 1);
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Begin stream capture in s1, spawn a
|
||||
* captured fork stream on s2. Queue some operations
|
||||
* (like increment kernel) on both s1 and s2. End the stream capture
|
||||
* on s2 and verify the error returned by the End capture.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_chkError_on_wrongStream") {
|
||||
int *A_d{nullptr}, *A_h{nullptr};
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t err;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = sizeof(int);
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeRelaxed;
|
||||
|
||||
A_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
// Initialize the Host data
|
||||
*A_h = 0;
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes,
|
||||
hipMemcpyHostToDevice, stream1));
|
||||
|
||||
hipLaunchKernelGGL(increment, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d);
|
||||
hipLaunchKernelGGL(increment, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, A_d);
|
||||
|
||||
err = hipStreamEndCapture(stream2, &graph);
|
||||
REQUIRE(err == hipErrorStreamCaptureUnmatched);
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
free(A_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
}
|
||||
static void thread_func4(hipStream_t stream1, hipStream_t stream2,
|
||||
hipEvent_t event, size_t Nbytes, int* B_d, int* B_h) {
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
HIP_CHECK(hipEventRecord(event, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event, 0));
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Begin stream capture in s1 and spawn a captured
|
||||
* fork stream s2. In main thread, queue a memcpy operation on s1.
|
||||
* Launch a thread, queue a memcpy operation on s2. Perform hipEventRecord on
|
||||
* s2 and wait Event on S1. Wait for the thread to complete. Queue operations
|
||||
* kernel addition(Cd = Ad + Bd) operation and memcpy(Ch <- Cd) in s1. End the
|
||||
* stream capture in s1. Create an executable graph and launch the graph on input
|
||||
* data and validate the output.
|
||||
* */
|
||||
TEST_CASE("Unit_hipStreamEndCapture_streamMerge_in_thread") {
|
||||
// Device Pointers
|
||||
int *A_d, *B_d, *C_d;
|
||||
// Host Pointers
|
||||
int *A_h, *B_h, *C_h, *D_h;
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForGraph{nullptr};
|
||||
hipEvent_t forkStreamEvent{nullptr}, event{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 5;
|
||||
size_t Nbytes = N * sizeof(int);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
HIP_CHECK(hipEventCreate(&event));
|
||||
// Memory allocation to Host Pointers
|
||||
A_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Initialize the Host data
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1 + i;
|
||||
B_h[i] = 2 + i;
|
||||
C_h[i] = 0;
|
||||
D_h[i] = 0;
|
||||
}
|
||||
// Memory allocation to Device Pointers
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&B_d), Nbytes));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&C_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Begin Capture
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes,
|
||||
hipMemcpyHostToDevice, stream1));
|
||||
// Thread Launch
|
||||
std::thread t(thread_func4, stream1, stream2, event, Nbytes, B_d, B_h);
|
||||
std::thread t(thread_func_pos, stream, &graph);
|
||||
t.join();
|
||||
// Launch kernal
|
||||
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d,
|
||||
B_d, C_d, N);
|
||||
// Validate end capture is successful
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes,
|
||||
hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] + B_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
// Release the memory
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
Negative Testcase Scenarios :
|
||||
1) Pass stream as nullptr and verify there is no crash, api returns error code.
|
||||
2) Pass graph as nullptr and verify there is no crash, api returns error code.
|
||||
3) Pass graph as nullptr and and stream as hipStreamPerThread verify there
|
||||
is no crash, api returns error code.
|
||||
4) End capture on stream where capture has not yet started and verify
|
||||
error code is returned.
|
||||
5) Destroy stream and try to end capture.
|
||||
6) Destroy Graph and try to end capture.
|
||||
7) Begin capture on a thread with mode other than hipStreamCaptureModeRelaxed
|
||||
and try to end capture from different thread. Expect to return
|
||||
hipErrorStreamCaptureWrongThread.
|
||||
8) Start stream capture on stream1 using mode hipStreamCaptureModeRelaxed.
|
||||
In stream1 queue a memcpy operation, queue a kernel square of a number operation.
|
||||
Launch a thread. In the thread, queue a memcpy operation. End the capture on
|
||||
stream1 and return the captured graph. Wait for the thread in main function.
|
||||
Create an executable graph and launch the graph on input data and validate the
|
||||
output.
|
||||
9) Create 2 streams s1 and s2. Begin stream capture in s1, spawn a
|
||||
captured fork stream on s2. Queue some operations
|
||||
(like increment kernel) on both s1 and s2. End the stream capture
|
||||
on s2 and verify the error returned by the End capture.
|
||||
10)Create 2 streams s1 and s2. Begin stream capture in s1 and spawn a captured
|
||||
fork stream s2. In main thread, queue a memcpy operation on s1.
|
||||
Launch a thread, queue a memcpy operation on s2. Perform hipEventRecord on
|
||||
s2 and wait Event on S1. Wait for the thread to complete. Queue operations
|
||||
kernel addition(Cd = Ad + Bd) operation and memcpy(Ch <- Cd) in s1. End the
|
||||
stream capture in s1. Create an executable graph and launch the graph on input
|
||||
data and validate the output.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Negative") {
|
||||
hipError_t ret;
|
||||
SECTION("Pass stream as nullptr") {
|
||||
hipGraph_t graph;
|
||||
ret = hipStreamEndCapture(nullptr, &graph);
|
||||
REQUIRE(hipErrorIllegalState == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass graph as nullptr") {
|
||||
hipStream_t stream;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
ret = hipStreamEndCapture(stream, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
SECTION("Pass graph as nullptr and stream as hipStreamPerThread") {
|
||||
ret = hipStreamEndCapture(hipStreamPerThread, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("End capture on stream where capture has not yet started") {
|
||||
hipStream_t stream;
|
||||
hipGraph_t graph;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipErrorIllegalState == ret);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
SECTION("Destroy stream and try to end capture") {
|
||||
hipStream_t stream;
|
||||
hipGraph_t graph;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipErrorContextIsDestroyed == ret);
|
||||
}
|
||||
SECTION("Destroy graph and try to end capture in between") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
ret = hipStreamEndCapture(stream, &graph);
|
||||
REQUIRE(hipSuccess == ret);
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_func(hipStream_t stream, hipGraph_t graph) {
|
||||
HIP_ASSERT(hipErrorStreamCaptureWrongThread ==
|
||||
hipStreamEndCapture(stream, &graph));
|
||||
}
|
||||
static void StreamEndCaptureThreadNegative(float* A_d, float* A_h,
|
||||
float* C_d, float* C_h, hipStreamCaptureMode mode) {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
std::thread t(thread_func, stream, graph);
|
||||
t.join();
|
||||
|
||||
#if HT_AMD
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
#endif
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
TEST_CASE("Unit_hipStreamEndCapture_Thread_Negative") {
|
||||
constexpr size_t N = 100000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
SECTION("Capture Mode:hipStreamCaptureModeGlobal") {
|
||||
StreamEndCaptureThreadNegative(A_d, A_h, C_d, C_h,
|
||||
hipStreamCaptureModeGlobal);
|
||||
}
|
||||
SECTION("Capture Mode:hipStreamCaptureModeThreadLocal") {
|
||||
StreamEndCaptureThreadNegative(A_d, A_h, C_d, C_h,
|
||||
hipStreamCaptureModeThreadLocal);
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
// Thread function
|
||||
static void thread_func1(hipStream_t stream, hipGraph_t *graph,
|
||||
size_t Nbytes, float* A_d, float* B_h) {
|
||||
HIP_CHECK(hipMemcpyAsync(B_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
HIP_CHECK(hipStreamEndCapture(stream, graph));
|
||||
}
|
||||
/*
|
||||
* Start stream capture on stream1 using mode hipStreamCaptureModeRelaxed.
|
||||
* In stream1 queue a memcpy operation, queue a kernel square of a number operation.
|
||||
* Launch a thread. In the thread, queue a memcpy operation. End the capture on
|
||||
* stream1 and return the captured graph. Wait for the thread in main function.
|
||||
* Create an executable graph and launch the graph on input data and validate the output.
|
||||
* */
|
||||
TEST_CASE("Unit_hipStreamEndCapture_mode_hipStreamCaptureModeRelaxed") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 10;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
// Device Pointers
|
||||
float *A_d;
|
||||
// Host Pointers
|
||||
float *A_h, *B_h, *C_h;
|
||||
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Initialize the Host data
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.0f + i;
|
||||
C_h[i] = A_h[i];
|
||||
}
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeRelaxed));
|
||||
// Copy data from Host to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, A_d, N);
|
||||
// Thread Launch
|
||||
std::thread t(thread_func1, stream, &graph, Nbytes, A_d, B_h);
|
||||
t.join();
|
||||
|
||||
// Launch the graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Output verification
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
C_h[i] = C_h[i] * C_h[i];
|
||||
REQUIRE(B_h[i] == C_h[i]);
|
||||
}
|
||||
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
}
|
||||
|
||||
static __global__ void increment(int* A_d) {
|
||||
atomicAdd(A_d, 1);
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Begin stream capture in s1, spawn a
|
||||
* captured fork stream on s2. Queue some operations
|
||||
* (like increment kernel) on both s1 and s2. End the stream capture
|
||||
* on s2 and verify the error returned by the End capture.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamEndCapture_chkError_on_wrongStream") {
|
||||
int *A_d{nullptr}, *A_h{nullptr};
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t err;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = sizeof(int);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
|
||||
A_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
// Initialize the Host data
|
||||
*A_h = 0;
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes,
|
||||
hipMemcpyHostToDevice, stream1));
|
||||
|
||||
hipLaunchKernelGGL(increment, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d);
|
||||
hipLaunchKernelGGL(increment, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, A_d);
|
||||
|
||||
err = hipStreamEndCapture(stream2, &graph);
|
||||
REQUIRE(err == hipErrorStreamCaptureUnmatched);
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
free(A_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
}
|
||||
static void thread_func4(hipStream_t stream1, hipStream_t stream2,
|
||||
hipEvent_t event, size_t Nbytes, int* B_d, int* B_h) {
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
HIP_CHECK(hipEventRecord(event, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event, 0));
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Begin stream capture in s1 and spawn a captured
|
||||
* fork stream s2. In main thread, queue a memcpy operation on s1.
|
||||
* Launch a thread, queue a memcpy operation on s2. Perform hipEventRecord on
|
||||
* s2 and wait Event on S1. Wait for the thread to complete. Queue operations
|
||||
* kernel addition(Cd = Ad + Bd) operation and memcpy(Ch <- Cd) in s1. End the
|
||||
* stream capture in s1. Create an executable graph and launch the graph on input
|
||||
* data and validate the output.
|
||||
* */
|
||||
TEST_CASE("Unit_hipStreamEndCapture_streamMerge_in_thread") {
|
||||
// Device Pointers
|
||||
int *A_d, *B_d, *C_d;
|
||||
// Host Pointers
|
||||
int *A_h, *B_h, *C_h, *D_h;
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForGraph{nullptr};
|
||||
hipEvent_t forkStreamEvent{nullptr}, event{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 5;
|
||||
size_t Nbytes = N * sizeof(int);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
HIP_CHECK(hipEventCreate(&event));
|
||||
// Memory allocation to Host Pointers
|
||||
A_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<int*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Initialize the Host data
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1 + i;
|
||||
B_h[i] = 2 + i;
|
||||
C_h[i] = 0;
|
||||
D_h[i] = 0;
|
||||
}
|
||||
// Memory allocation to Device Pointers
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_d), Nbytes));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&B_d), Nbytes));
|
||||
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&C_d), Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Begin Capture
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes,
|
||||
hipMemcpyHostToDevice, stream1));
|
||||
// Thread Launch
|
||||
std::thread t(thread_func4, stream1, stream2, event, Nbytes, B_d, B_h);
|
||||
t.join();
|
||||
// Launch kernal
|
||||
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d,
|
||||
B_d, C_d, N);
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes,
|
||||
hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] + B_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
// Release the memory
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
@@ -17,207 +17,129 @@ OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Testcase Scenarios
|
||||
------------------
|
||||
Functional:
|
||||
1) Start stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusActive
|
||||
and identifier returned is valid/non-zero.
|
||||
2) End stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone
|
||||
and identifier is not returned/updated by api.
|
||||
3) Begin capture on hipStreamPerThread and get capture info. Verify api is success, capture status is hipStreamCaptureStatusActive
|
||||
and identifier returned is valid/non-zero.
|
||||
4) End capture on hipStreamPerThread, get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone
|
||||
and identifier is not returned/updated by api.
|
||||
5) Perform multiple captures and verify the identifier returned is unique.
|
||||
|
||||
Argument Validation/Negative:
|
||||
1) Pass pId as nullptr and verify api doesn’t crash and returns success.
|
||||
2) Pass pCaptureStatus as nullptr and verify api doesn’t crash and returns error code.
|
||||
|
||||
Extended Scenarios
|
||||
------------------
|
||||
1.Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and wait for event e1 on s2. Queue some operations
|
||||
in s1 and s2. Invoke hipStreamGetCaptureInfo on both s1 and s2. Verify that the capture info (status and id) of both s1 and s2
|
||||
are identical. Record event e2 on s2 and wait for event e2 on s1. End the capture of stream s1. Verify that the capture info
|
||||
(status and id) of both s1 and s2 are identical.
|
||||
|
||||
2.Create a stream s1. Start capturing s1. Get the capture info of s1. Launch a thread. In the thread get the capture info of s1
|
||||
using hipStreamGetCaptureInfo. Verify that it is in state hipStreamCaptureStatusActive and capture id inside thread is same as
|
||||
capture id in main function. Exit the thread and end the capture
|
||||
|
||||
3.Verify that the id remains same througout the capture. Create a stream s1. Start capturing s1. Get the capture info of s1.
|
||||
Queue some oprations in s1. Again get the capture info. Queue different operations in s1. Again get the capture info.
|
||||
Verify that all the capture info are identical.
|
||||
|
||||
4.Create a stream with default flag (hipStreamDefault). Start capturing the stream. Invoke hipStreamGetCaptureInfo() on the null
|
||||
stream. Verify hipErrorStreamCaptureImplicit is returned by hipStreamGetCaptureInfo(). Verify capture status of created stream.
|
||||
Do some operatoins. End the capture on the created stream.Verify the capture status. Execute the graph and verify the output
|
||||
from the operations.
|
||||
|
||||
5. Test scenario 1 using hipStreamGetCaptureInfo_v2.
|
||||
6. Test scenario 2 using hipStreamGetCaptureInfo_v2.
|
||||
7. Test scenario 3 using hipStreamGetCaptureInfo_v2.
|
||||
8. Test scenario 4 using hipStreamGetCaptureInfo_v2.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
constexpr int LAUNCH_ITERS = 1;
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
* Validates stream capture info, launches graph and verify results
|
||||
* @addtogroup hipStreamGetCaptureInfo hipStreamGetCaptureInfo
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipStreamGetCaptureInfo(hipStream_t stream, hipStreamCaptureStatus
|
||||
* *pCaptureStatus, unsigned long long *pId)` - get capture status of a stream
|
||||
*/
|
||||
void validateStreamCaptureInfo(hipStream_t mstream) {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForLaunch{nullptr};
|
||||
hipEvent_t memsetEvent1, memsetEvent2, forkStreamEvent;
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&streamForLaunch));
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
}
|
||||
|
||||
// Create cross stream dependencies.
|
||||
// memset operations are done on stream1 and stream2
|
||||
// and they are joined back to mainstream
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent1));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(mstream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, mstream));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, Nbytes, stream1));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent1, stream1));
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream2));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent1, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent2, 0));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, mstream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, mstream, A_d, C_d, N);
|
||||
void checkStreamCaptureInfo(hipStreamCaptureMode mode, hipStream_t stream) {
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0; // NOLINT
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(mstream, &captureStatus, &capSequenceID));
|
||||
|
||||
// verify capture status is active and sequence id is valid
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
// Capture status is active and sequence id is valid
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
|
||||
// End capture and verify graph is returned
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, mstream));
|
||||
HIP_CHECK(hipStreamEndCapture(mstream, &graph));
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// verify capture status is inactive and sequence id is not updated
|
||||
capSequenceID = 0;
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(mstream, &captureStatus, &capSequenceID));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
REQUIRE(capSequenceID == 0);
|
||||
|
||||
// Verify api still returns capture status when capture ID is nullptr
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, nullptr));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < LAUNCH_ITERS; i++) {
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForLaunch));
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(streamForLaunch));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec))
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForLaunch));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent1));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
|
||||
// Validate the computation
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (C_h[i] != A_h[i] * A_h[i]) {
|
||||
INFO("A and C not matching at " << i << " C_h[i] " << C_h[i]
|
||||
<< " A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Functional Test for stream capture and getting capture info.
|
||||
* Regular/custom stream is used for stream capture.
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify that hipStreamCaptureStatusActive is returned during
|
||||
* stream capture. When capture is ended, status is changed to
|
||||
* hipStreamCaptureStatusNone and error is not reported when some arguments are
|
||||
* not passed
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_BasicFunctional") {
|
||||
hipStream_t streamForCapture;
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_Positive_Functional") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&streamForCapture));
|
||||
validateStreamCaptureInfo(streamForCapture);
|
||||
HIP_CHECK(hipStreamDestroy(streamForCapture));
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
checkStreamCaptureInfo(captureMode, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test performs stream capture on hipStreamPerThread and validates
|
||||
* capture info.
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test starts stream capture on multiple streams and verifies uniqueness
|
||||
* of identifiers returned
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_hipStreamPerThread") {
|
||||
validateStreamCaptureInfo(hipStreamPerThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test starts stream capture on multiple streams and verifies uniqueness of
|
||||
* identifiers returned.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_UniqueID") {
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_Positive_UniqueID") {
|
||||
constexpr int numStreams = 100;
|
||||
hipStream_t streams[numStreams]{};
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
std::vector<int> idlist;
|
||||
unsigned long long capSequenceID{}; //NOLINT
|
||||
unsigned long long capSequenceID{}; // NOLINT
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
StreamsGuard streams(numStreams);
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamCreate(&streams[i]));
|
||||
HIP_CHECK(hipStreamBeginCapture(streams[i], hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(streams[i], &captureStatus,
|
||||
&capSequenceID));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(streams[i], &captureStatus, &capSequenceID));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
idlist.push_back(capSequenceID);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
for (int j = i+1; j < numStreams; j++) {
|
||||
for (int j = i + 1; j < numStreams; j++) {
|
||||
if (idlist[i] == idlist[j]) {
|
||||
INFO("Same identifier returned for stream "
|
||||
<< i << " and stream " << j);
|
||||
INFO("Same identifier returned for stream " << i << " and stream " << j);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
@@ -226,396 +148,50 @@ TEST_CASE("Unit_hipStreamGetCaptureInfo_UniqueID") {
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamEndCapture(streams[i], &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streams[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument validation/Negative tests for api
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Capture status is nullptr
|
||||
* -# Capture status checked on legacy/null stream
|
||||
* -# Stream is uninitialized
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_ArgValidation") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream;
|
||||
hipStreamCaptureStatus captureStatus;
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_Negative_Parameters") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
unsigned long long capSequenceID; // NOLINT
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
SECTION("Capture ID location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo(stream, &captureStatus, nullptr);
|
||||
// Capture ID is optional
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
SECTION("Capture Status location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo(stream, nullptr, &capSequenceID);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo(stream, nullptr, &capSequenceID), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and
|
||||
* wait for event e1 on s2. Queue some operations in s1 and s2. Invoke
|
||||
* hipStreamGetCaptureInfo on both s1 and s2. Verify that the capture info
|
||||
* (status and id) of both s1 and s2 are identical. Record event e2 on s2
|
||||
* and wait for event e2 on s1. End the capture of stream s1. Verify that the
|
||||
* capture info (status and id) of both s1 and s2 are identical.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_ParentAndForkedStrm_CaptureStatus") {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t event2{nullptr}, forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&event2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
// Start capture on stream1
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d, C_d, N);
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, B_d, D_d, N);
|
||||
// Copy data back to the Host
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream2));
|
||||
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID1, capSequenceID2, capSequenceID3, //NOLINT
|
||||
capSequenceID4;
|
||||
SECTION("hipStreamGetCaptureInfo verification before End capture") {
|
||||
// Capture info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream1, &captureStatus1,
|
||||
&capSequenceID1));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream2, &captureStatus2,
|
||||
&capSequenceID2));
|
||||
// Verfication of results
|
||||
REQUIRE(capSequenceID1 == capSequenceID2);
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
#if HT_NVIDIA // EXSWHTEC-216, EXSWHTEC-228
|
||||
SECTION("Capture status when checked on null stream") {
|
||||
hipGraph_t graph{nullptr};
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo(nullptr, &cStatus, &capSequenceID),
|
||||
hipErrorStreamCaptureImplicit);
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 verification before End capture") {
|
||||
// Capture info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream1, &captureStatus1,
|
||||
&capSequenceID1, nullptr, nullptr, nullptr));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream2, &captureStatus2,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Verfication of results
|
||||
REQUIRE(capSequenceID1 == capSequenceID2);
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
SECTION("Capture status when stream is uninitialized") {
|
||||
constexpr auto InvalidStream = [] {
|
||||
StreamGuard sg(Streams::created);
|
||||
return sg.stream();
|
||||
};
|
||||
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo(InvalidStream(), &cStatus, &capSequenceID),
|
||||
hipErrorContextIsDestroyed);
|
||||
}
|
||||
|
||||
|
||||
HIP_CHECK(hipEventRecord(event2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event2, 0));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
SECTION("hipStreamGetCaptureInfo verification after End capture") {
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream1, &captureStatus3,
|
||||
&capSequenceID3));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream2, &captureStatus4,
|
||||
&capSequenceID4));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 verification after End capture") {
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream1, &captureStatus3,
|
||||
&capSequenceID3, nullptr, nullptr, nullptr));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream2, &captureStatus4,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
}
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(event2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
// Thread Function
|
||||
static void thread_func(hipStream_t stream, unsigned long long capSequenceID1, //NOLINT
|
||||
unsigned long long capSequenceID2) { //NOLINT
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID3, capSequenceID4; //NOLINT
|
||||
SECTION("hipStreamGetCaptureInfo CaptureStatus in Thread") {
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID3));
|
||||
REQUIRE(capSequenceID1 == capSequenceID3);
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 CaptureStatus in Thread") {
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
REQUIRE(capSequenceID2 == capSequenceID4);
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Create a stream s1. Start capturing s1. Get the capture info of s1. Launch
|
||||
* a thread. In the thread get the capture info of s1 using hipStreamGetCaptureInfo.
|
||||
* Verify that it is in state hipStreamCaptureStatusActive and capture id inside
|
||||
* thread is same as capture id in main function. Exit the thread and end the capture
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_CaptureStatus_InThread") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture info
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID1, capSequenceID2; //NOLINT
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID1));
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Thread launch
|
||||
std::thread t(thread_func, stream, capSequenceID1, capSequenceID2);
|
||||
t.join();
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
/*
|
||||
* Verify that the id remains same througout the capture. Create a stream s1.
|
||||
* Start capturing s1. Get the capture info of s1. Queue some oprations in s1.
|
||||
* Again get the capture info. Queue different operations in s1. Again get the
|
||||
* capture info. Verify that all the capture info are identical.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_CaptureStatus_Througout_Capture") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture Info
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone},
|
||||
captureStatus5{hipStreamCaptureStatusNone},
|
||||
captureStatus6{hipStreamCaptureStatusNone};
|
||||
|
||||
unsigned long long capSequenceID1, capSequenceID2, capSequenceID3, //NOLINT
|
||||
capSequenceID4, capSequenceID5, capSequenceID6;
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus1, &capSequenceID1));
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus2,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus3, &capSequenceID3));
|
||||
REQUIRE(captureStatus1 == captureStatus3);
|
||||
REQUIRE(capSequenceID1 == capSequenceID3);
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus4,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
REQUIRE(captureStatus2 == captureStatus4);
|
||||
REQUIRE(capSequenceID2 == capSequenceID4);
|
||||
|
||||
// Kernal Operations
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, B_d, D_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus5, &capSequenceID5));
|
||||
REQUIRE(captureStatus3 == captureStatus5);
|
||||
REQUIRE(capSequenceID3 == capSequenceID5);
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus6,
|
||||
&capSequenceID6, nullptr, nullptr, nullptr));
|
||||
REQUIRE(captureStatus4 == captureStatus6);
|
||||
REQUIRE(capSequenceID4 == capSequenceID6);
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
/*
|
||||
* Create a stream with default flag (hipStreamDefault). Start capturing the stream.
|
||||
* Invoke hipStreamGetCaptureInfo() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
* is returned by hipStreamGetCaptureInfo(). Verify capture status of created stream. Do some
|
||||
* operatoins. End the capture on the created stream.Verify the capture status. Execute the
|
||||
* graph and verify the output from the operations.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_Nullstream_CaptureInfo") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t ret;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 1.0f + i;
|
||||
D_h[i] = 0.0f;
|
||||
}
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone},
|
||||
captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0, // NOLINT
|
||||
capSequenceID1 = 0;
|
||||
|
||||
// Verify the Error returned with null stream.
|
||||
SECTION("hipStreamGetCaptureInfo with null stream") {
|
||||
ret = hipStreamGetCaptureInfo(0, &captureStatus, &capSequenceID);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 with null stream") {
|
||||
ret = hipStreamGetCaptureInfo_v2(0, &captureStatus, &capSequenceID,
|
||||
nullptr, nullptr, nullptr);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
}
|
||||
|
||||
|
||||
// Check the capture status of the stream
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus1));
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
// Kernal Operation
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// Capture Status
|
||||
SECTION("hipStreamGetCaptureInfo with null stream after End capture") {
|
||||
ret = hipStreamGetCaptureInfo(0, &captureStatus2, &capSequenceID1);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 with null stream after End capture") {
|
||||
ret = hipStreamGetCaptureInfo_v2(0, &captureStatus2, &capSequenceID1,
|
||||
nullptr, nullptr, nullptr);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] * A_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Testcase Scenarios
|
||||
------------------
|
||||
Functional:
|
||||
1) Start stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusActive
|
||||
and identifier returned is valid/non-zero.
|
||||
2) End stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone
|
||||
and identifier is not returned/updated by api.
|
||||
3) Begin capture on hipStreamPerThread and get capture info. Verify api is success, capture status is hipStreamCaptureStatusActive
|
||||
and identifier returned is valid/non-zero.
|
||||
4) End capture on hipStreamPerThread, get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone
|
||||
and identifier is not returned/updated by api.
|
||||
5) Perform multiple captures and verify the identifier returned is unique.
|
||||
|
||||
Argument Validation/Negative:
|
||||
1) Pass pId as nullptr and verify api doesn’t crash and returns success.
|
||||
2) Pass pCaptureStatus as nullptr and verify api doesn’t crash and returns error code.
|
||||
|
||||
Extended Scenarios
|
||||
------------------
|
||||
1.Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and wait for event e1 on s2. Queue some operations
|
||||
in s1 and s2. Invoke hipStreamGetCaptureInfo on both s1 and s2. Verify that the capture info (status and id) of both s1 and s2
|
||||
are identical. Record event e2 on s2 and wait for event e2 on s1. End the capture of stream s1. Verify that the capture info
|
||||
(status and id) of both s1 and s2 are identical.
|
||||
|
||||
2.Create a stream s1. Start capturing s1. Get the capture info of s1. Launch a thread. In the thread get the capture info of s1
|
||||
using hipStreamGetCaptureInfo. Verify that it is in state hipStreamCaptureStatusActive and capture id inside thread is same as
|
||||
capture id in main function. Exit the thread and end the capture
|
||||
|
||||
3.Verify that the id remains same througout the capture. Create a stream s1. Start capturing s1. Get the capture info of s1.
|
||||
Queue some oprations in s1. Again get the capture info. Queue different operations in s1. Again get the capture info.
|
||||
Verify that all the capture info are identical.
|
||||
|
||||
4.Create a stream with default flag (hipStreamDefault). Start capturing the stream. Invoke hipStreamGetCaptureInfo() on the null
|
||||
stream. Verify hipErrorStreamCaptureImplicit is returned by hipStreamGetCaptureInfo(). Verify capture status of created stream.
|
||||
Do some operatoins. End the capture on the created stream.Verify the capture status. Execute the graph and verify the output
|
||||
from the operations.
|
||||
|
||||
5. Test scenario 1 using hipStreamGetCaptureInfo_v2.
|
||||
6. Test scenario 2 using hipStreamGetCaptureInfo_v2.
|
||||
7. Test scenario 3 using hipStreamGetCaptureInfo_v2.
|
||||
8. Test scenario 4 using hipStreamGetCaptureInfo_v2.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
constexpr int LAUNCH_ITERS = 1;
|
||||
|
||||
/**
|
||||
* Validates stream capture info, launches graph and verify results
|
||||
*/
|
||||
void validateStreamCaptureInfo(hipStream_t mstream) {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForLaunch{nullptr};
|
||||
hipEvent_t memsetEvent1, memsetEvent2, forkStreamEvent;
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&streamForLaunch));
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
}
|
||||
|
||||
// Create cross stream dependencies.
|
||||
// memset operations are done on stream1 and stream2
|
||||
// and they are joined back to mainstream
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent1));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(mstream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, mstream));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, Nbytes, stream1));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent1, stream1));
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream2));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent1, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent2, 0));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, mstream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, mstream, A_d, C_d, N);
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0; // NOLINT
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(mstream, &captureStatus, &capSequenceID));
|
||||
|
||||
// verify capture status is active and sequence id is valid
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
|
||||
// End capture and verify graph is returned
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, mstream));
|
||||
HIP_CHECK(hipStreamEndCapture(mstream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// verify capture status is inactive and sequence id is not updated
|
||||
capSequenceID = 0;
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(mstream, &captureStatus, &capSequenceID));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
REQUIRE(capSequenceID == 0);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < LAUNCH_ITERS; i++) {
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForLaunch));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(streamForLaunch));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForLaunch));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent1));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
|
||||
// Validate the computation
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (C_h[i] != A_h[i] * A_h[i]) {
|
||||
INFO("A and C not matching at " << i << " C_h[i] " << C_h[i]
|
||||
<< " A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Functional Test for stream capture and getting capture info.
|
||||
* Regular/custom stream is used for stream capture.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_BasicFunctional") {
|
||||
hipStream_t streamForCapture;
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&streamForCapture));
|
||||
validateStreamCaptureInfo(streamForCapture);
|
||||
HIP_CHECK(hipStreamDestroy(streamForCapture));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test performs stream capture on hipStreamPerThread and validates
|
||||
* capture info.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_hipStreamPerThread") {
|
||||
validateStreamCaptureInfo(hipStreamPerThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test starts stream capture on multiple streams and verifies uniqueness of
|
||||
* identifiers returned.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_UniqueID") {
|
||||
constexpr int numStreams = 100;
|
||||
hipStream_t streams[numStreams]{};
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
std::vector<int> idlist;
|
||||
unsigned long long capSequenceID{}; //NOLINT
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamCreate(&streams[i]));
|
||||
HIP_CHECK(hipStreamBeginCapture(streams[i], hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(streams[i], &captureStatus,
|
||||
&capSequenceID));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
idlist.push_back(capSequenceID);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
for (int j = i+1; j < numStreams; j++) {
|
||||
if (idlist[i] == idlist[j]) {
|
||||
INFO("Same identifier returned for stream "
|
||||
<< i << " and stream " << j);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamEndCapture(streams[i], &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streams[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument validation/Negative tests for api
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_ArgValidation") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream;
|
||||
hipStreamCaptureStatus captureStatus;
|
||||
unsigned long long capSequenceID; // NOLINT
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
SECTION("Capture ID location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo(stream, &captureStatus, nullptr);
|
||||
// Capture ID is optional
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
|
||||
SECTION("Capture Status location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo(stream, nullptr, &capSequenceID);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and
|
||||
* wait for event e1 on s2. Queue some operations in s1 and s2. Invoke
|
||||
* hipStreamGetCaptureInfo on both s1 and s2. Verify that the capture info
|
||||
* (status and id) of both s1 and s2 are identical. Record event e2 on s2
|
||||
* and wait for event e2 on s1. End the capture of stream s1. Verify that the
|
||||
* capture info (status and id) of both s1 and s2 are identical.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_ParentAndForkedStrm_CaptureStatus") {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t event2{nullptr}, forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&event2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
// Start capture on stream1
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d, C_d, N);
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, B_d, D_d, N);
|
||||
// Copy data back to the Host
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream2));
|
||||
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID1, capSequenceID2, capSequenceID3, //NOLINT
|
||||
capSequenceID4;
|
||||
SECTION("hipStreamGetCaptureInfo verification before End capture") {
|
||||
// Capture info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream1, &captureStatus1,
|
||||
&capSequenceID1));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream2, &captureStatus2,
|
||||
&capSequenceID2));
|
||||
// Verfication of results
|
||||
REQUIRE(capSequenceID1 == capSequenceID2);
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 verification before End capture") {
|
||||
// Capture info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream1, &captureStatus1,
|
||||
&capSequenceID1, nullptr, nullptr, nullptr));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream2, &captureStatus2,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Verfication of results
|
||||
REQUIRE(capSequenceID1 == capSequenceID2);
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
}
|
||||
|
||||
|
||||
HIP_CHECK(hipEventRecord(event2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event2, 0));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
SECTION("hipStreamGetCaptureInfo verification after End capture") {
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream1, &captureStatus3,
|
||||
&capSequenceID3));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream2, &captureStatus4,
|
||||
&capSequenceID4));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 verification after End capture") {
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream1, &captureStatus3,
|
||||
&capSequenceID3, nullptr, nullptr, nullptr));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream2, &captureStatus4,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
}
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(event2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
// Thread Function
|
||||
static void thread_func(hipStream_t stream, unsigned long long capSequenceID1, //NOLINT
|
||||
unsigned long long capSequenceID2) { //NOLINT
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID3, capSequenceID4; //NOLINT
|
||||
SECTION("hipStreamGetCaptureInfo CaptureStatus in Thread") {
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID3));
|
||||
REQUIRE(capSequenceID1 == capSequenceID3);
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 CaptureStatus in Thread") {
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
REQUIRE(capSequenceID2 == capSequenceID4);
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Create a stream s1. Start capturing s1. Get the capture info of s1. Launch
|
||||
* a thread. In the thread get the capture info of s1 using hipStreamGetCaptureInfo.
|
||||
* Verify that it is in state hipStreamCaptureStatusActive and capture id inside
|
||||
* thread is same as capture id in main function. Exit the thread and end the capture
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_CaptureStatus_InThread") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture info
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID1, capSequenceID2; //NOLINT
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus, &capSequenceID1));
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Thread launch
|
||||
std::thread t(thread_func, stream, capSequenceID1, capSequenceID2);
|
||||
t.join();
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
/*
|
||||
* Verify that the id remains same througout the capture. Create a stream s1.
|
||||
* Start capturing s1. Get the capture info of s1. Queue some oprations in s1.
|
||||
* Again get the capture info. Queue different operations in s1. Again get the
|
||||
* capture info. Verify that all the capture info are identical.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_CaptureStatus_Througout_Capture") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture Info
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone},
|
||||
captureStatus5{hipStreamCaptureStatusNone},
|
||||
captureStatus6{hipStreamCaptureStatusNone};
|
||||
|
||||
unsigned long long capSequenceID1, capSequenceID2, capSequenceID3, //NOLINT
|
||||
capSequenceID4, capSequenceID5, capSequenceID6;
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus1, &capSequenceID1));
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus2,
|
||||
&capSequenceID2, nullptr, nullptr, nullptr));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus3, &capSequenceID3));
|
||||
REQUIRE(captureStatus1 == captureStatus3);
|
||||
REQUIRE(capSequenceID1 == capSequenceID3);
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus4,
|
||||
&capSequenceID4, nullptr, nullptr, nullptr));
|
||||
REQUIRE(captureStatus2 == captureStatus4);
|
||||
REQUIRE(capSequenceID2 == capSequenceID4);
|
||||
|
||||
// Kernal Operations
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, B_d, D_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// hipStreamGetCaptureInfo Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo(stream, &captureStatus5, &capSequenceID5));
|
||||
REQUIRE(captureStatus3 == captureStatus5);
|
||||
REQUIRE(capSequenceID3 == capSequenceID5);
|
||||
// hipStreamGetCaptureInfo_v2 Capture status
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus6,
|
||||
&capSequenceID6, nullptr, nullptr, nullptr));
|
||||
REQUIRE(captureStatus4 == captureStatus6);
|
||||
REQUIRE(capSequenceID4 == capSequenceID6);
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
/*
|
||||
* Create a stream with default flag (hipStreamDefault). Start capturing the stream.
|
||||
* Invoke hipStreamGetCaptureInfo() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
* is returned by hipStreamGetCaptureInfo(). Verify capture status of created stream. Do some
|
||||
* operatoins. End the capture on the created stream.Verify the capture status. Execute the
|
||||
* graph and verify the output from the operations.
|
||||
* The above scenario using hipStreamGetCaptureInfo_v2 API
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_Nullstream_CaptureInfo") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t ret;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 1.0f + i;
|
||||
D_h[i] = 0.0f;
|
||||
}
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone},
|
||||
captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0, // NOLINT
|
||||
capSequenceID1 = 0;
|
||||
|
||||
// Verify the Error returned with null stream.
|
||||
SECTION("hipStreamGetCaptureInfo with null stream") {
|
||||
ret = hipStreamGetCaptureInfo(0, &captureStatus, &capSequenceID);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 with null stream") {
|
||||
ret = hipStreamGetCaptureInfo_v2(0, &captureStatus, &capSequenceID,
|
||||
nullptr, nullptr, nullptr);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
}
|
||||
|
||||
|
||||
// Check the capture status of the stream
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus1));
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
// Kernal Operation
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// Capture Status
|
||||
SECTION("hipStreamGetCaptureInfo with null stream after End capture") {
|
||||
ret = hipStreamGetCaptureInfo(0, &captureStatus2, &capSequenceID1);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
SECTION("hipStreamGetCaptureInfo_v2 with null stream after End capture") {
|
||||
ret = hipStreamGetCaptureInfo_v2(0, &captureStatus2, &capSequenceID1,
|
||||
nullptr, nullptr, nullptr);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] * A_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
@@ -17,90 +17,74 @@ OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Testcase Scenarios
|
||||
------------------
|
||||
Functional:
|
||||
1) Start stream capture and get capture info v2. Verify api is success, capture status is hipStreamCaptureStatusActive,
|
||||
identifier returned is valid/non-zero, graph object is returned.
|
||||
2) When stream capture is in progress, create dependent nodes by creating multistream dependencies and verify the api returns
|
||||
valid dependent nodes.
|
||||
3) End stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone and
|
||||
identifier/graph/nodes are not returned by api.
|
||||
4) When optional parameters are not passed, make sure api still returns capture status of stream.
|
||||
5) Begin capture on hipStreamPerThread, get capture info v2 and validate results.
|
||||
6) Perform multiple captures and verify the identifier returned is unique.
|
||||
|
||||
Parameter Validation/Negative:
|
||||
1) Capture Status location as nullptr and verify api returns error code.
|
||||
2) Stream as nullptr and verify api returns error code.
|
||||
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr int LAUNCH_ITERS = 1;
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
* Validates stream capture infov2, launches graph and verifies results
|
||||
* @addtogroup hipStreamGetCaptureInfo_v2 hipStreamGetCaptureInfo_v2
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipStreamGetCaptureInfo_v2(hipStream_t stream, hipStreamCaptureStatus
|
||||
* *captureStatus_out, unsigned long long *id_out __dparm(0), hipGraph_t
|
||||
* *graph_out __dparm(0), const hipGraphNode_t **dependencies_out __dparm(0),
|
||||
* size_t *numDependencies_out __dparm(0)))` - Get stream's capture state
|
||||
*/
|
||||
void validateStreamCaptureInfoV2(hipStream_t mstream) {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForLaunch{nullptr};
|
||||
hipEvent_t memcpyEvent1, memsetEvent2, forkStreamEvent;
|
||||
|
||||
void checkStreamCaptureInfo_v2(hipStreamCaptureMode mode, hipStream_t stream) {
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
hipGraph_t graph{nullptr}, capInfoGraph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
const hipGraphNode_t *nodelist{};
|
||||
size_t Nbytes = N * sizeof(float), numDependencies;
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&streamForLaunch));
|
||||
const hipGraphNode_t* nodelist{};
|
||||
int numDepsCreated = 0;
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
hipGraphNodeType type(hipGraphNodeTypeEmpty);
|
||||
unsigned long long capSequenceID = 0; // NOLINT
|
||||
size_t numDependencies;
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> B_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
EventsGuard events_guard(3);
|
||||
StreamsGuard streams_guard(2);
|
||||
|
||||
SECTION("Linear sequence graph") {
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
captureSequenceLinear(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream);
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, &capSequenceID, &capInfoGraph,
|
||||
&nodelist, &numDependencies));
|
||||
numDepsCreated = 1;
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[0], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type0 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Create cross stream dependencies.
|
||||
// memset/memcpy operations are done on stream1 and stream2
|
||||
// and they are joined back to mainstream
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&memcpyEvent1));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(mstream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, mstream));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, Nbytes, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipEventRecord(memcpyEvent1, stream1));
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream2));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memcpyEvent1, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent2, 0));
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0; // NOLINT
|
||||
constexpr int numDepsCreated = 2; // Num of dependencies created
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies));
|
||||
SECTION("Branched sequence graph") {
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
captureSequenceBranched(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream,
|
||||
streams_guard.stream_list(), events_guard.event_list());
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, &capSequenceID, &capInfoGraph,
|
||||
&nodelist, &numDependencies));
|
||||
numDepsCreated = 2;
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[0], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type0 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[1], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type1 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
// verify capture status is active, sequence id is valid, graph is returned,
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
@@ -108,27 +92,10 @@ void validateStreamCaptureInfoV2(hipStream_t mstream) {
|
||||
REQUIRE(capInfoGraph != nullptr);
|
||||
REQUIRE(numDependencies == numDepsCreated);
|
||||
|
||||
// verify dependency nodes list returned is the one we created.
|
||||
hipGraphNodeType type(hipGraphNodeTypeEmpty);
|
||||
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[0], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type0 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[1], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type1 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, mstream, A_d, C_d, N);
|
||||
captureSequenceCompute(A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream);
|
||||
|
||||
// End capture and verify graph is returned
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, mstream));
|
||||
HIP_CHECK(hipStreamEndCapture(mstream, &graph));
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// verify capture status is inactive and other params are not updated
|
||||
@@ -136,8 +103,8 @@ void validateStreamCaptureInfoV2(hipStream_t mstream) {
|
||||
capInfoGraph = nullptr;
|
||||
numDependencies = 0;
|
||||
nodelist = nullptr;
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, &capSequenceID, &capInfoGraph,
|
||||
&nodelist, &numDependencies));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
REQUIRE(capSequenceID == 0);
|
||||
REQUIRE(capInfoGraph == nullptr);
|
||||
@@ -145,88 +112,88 @@ void validateStreamCaptureInfoV2(hipStream_t mstream) {
|
||||
REQUIRE(numDependencies == 0);
|
||||
|
||||
// Verify api still returns capture status when optional args are not passed
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < LAUNCH_ITERS; i++) {
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForLaunch));
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i) * static_cast<float>(i), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(streamForLaunch));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec))
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForLaunch));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(memcpyEvent1));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
|
||||
// Validate the computation
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (C_h[i] != A_h[i] * A_h[i]) {
|
||||
INFO("A and C not matching at " << i << " C_h[i] " << C_h[i]
|
||||
<< " A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Functional Test for stream capture and getting capture info V2.
|
||||
* Regular/custom stream is used for stream capture.
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify that hipStreamCaptureStatusActive is returned during
|
||||
* stream capture, correct number of created dependencies is returned and
|
||||
* sequence ID is valid. When capture is ended, status is changed to
|
||||
* hipStreamCaptureStatusNone and error is not reported when some arguments are
|
||||
* not passed.
|
||||
* -# Sequence graph is linear, number of created dependencies is 1, node
|
||||
* type is correct
|
||||
* -# Sequence graph is branched, number of created dependencies is 2,
|
||||
* node types are correct
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo_v2.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_BasicFunctional") {
|
||||
hipStream_t streamForCapture;
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_Positive_Functional") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&streamForCapture));
|
||||
validateStreamCaptureInfoV2(streamForCapture);
|
||||
HIP_CHECK(hipStreamDestroy(streamForCapture));
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
checkStreamCaptureInfo_v2(captureMode, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test performs stream capture on hipStreamPerThread and validates
|
||||
* capture info V2.
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify stream capture on multiple streams and verifies
|
||||
* uniqueness of identifiers returned from capture Info V2:
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo_v2.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_hipStreamPerThread") {
|
||||
validateStreamCaptureInfoV2(hipStreamPerThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test starts stream capture on multiple streams and verifies uniqueness of
|
||||
* identifiers returned from capture Info V2.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_UniqueID") {
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_Positive_UniqueID") {
|
||||
constexpr int numStreams = 100;
|
||||
hipStream_t streams[numStreams]{};
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
std::vector<int> idlist;
|
||||
unsigned long long capSequenceID{}; // NOLINT
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
StreamsGuard streams(numStreams);
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamCreate(&streams[i]));
|
||||
HIP_CHECK(hipStreamBeginCapture(streams[i], hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(streams[i], &captureStatus,
|
||||
&capSequenceID, nullptr, nullptr, nullptr));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(streams[i], &captureStatus, &capSequenceID, nullptr,
|
||||
nullptr, nullptr));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
idlist.push_back(capSequenceID);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
for (int j = i+1; j < numStreams; j++) {
|
||||
for (int j = i + 1; j < numStreams; j++) {
|
||||
if (idlist[i] == idlist[j]) {
|
||||
INFO("Same identifier returned for stream "
|
||||
<< i << " and stream " << j);
|
||||
INFO("Same identifier returned for stream " << i << " and stream " << j);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
@@ -235,46 +202,58 @@ TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_UniqueID") {
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamEndCapture(streams[i], &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streams[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter validation/Negative tests for api
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Capture status is nullptr
|
||||
* -# Capture status checked on legacy/null stream
|
||||
* -# Capture status when stream is uninitialized
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamGetCaptureInfo_v2.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_ParamValidation") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream;
|
||||
float *A_d;
|
||||
hipGraph_t graph{}, capInfoGraph{};
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_Negative_Parameters") {
|
||||
hipGraph_t capInfoGraph{};
|
||||
hipStreamCaptureStatus captureStatus;
|
||||
unsigned long long capSequenceID; // NOLINT
|
||||
size_t numDependencies;
|
||||
const hipGraphNode_t *nodelist{};
|
||||
constexpr int numBytes{100};
|
||||
const hipGraphNode_t* nodelist{};
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, numBytes));
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, numBytes, stream));
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
SECTION("Capture Status location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo_v2(stream, nullptr,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo_v2(stream, nullptr, &capSequenceID, &capInfoGraph,
|
||||
&nodelist, &numDependencies),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Stream as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo_v2(nullptr, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies);
|
||||
if ((ret != hipErrorUnknown) && (ret != hipErrorStreamCaptureImplicit)) {
|
||||
INFO("Ret : " << ret);
|
||||
REQUIRE(false);
|
||||
}
|
||||
#if HT_NVIDIA // EXSWHTEC-216, EXSWHTEC-228
|
||||
SECTION("Capture status when checked on null stream") {
|
||||
hipGraph_t graph{nullptr};
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo_v2(nullptr, &captureStatus, &capSequenceID,
|
||||
&capInfoGraph, &nodelist, &numDependencies),
|
||||
hipErrorStreamCaptureImplicit);
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
SECTION("Capture status when stream is uninitialized") {
|
||||
constexpr auto InvalidStream = [] {
|
||||
StreamGuard sg(Streams::created);
|
||||
return sg.stream();
|
||||
};
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
}
|
||||
HIP_CHECK_ERROR(hipStreamGetCaptureInfo_v2(InvalidStream(), &captureStatus, &capSequenceID,
|
||||
&capInfoGraph, &nodelist, &numDependencies),
|
||||
hipErrorContextIsDestroyed);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Testcase Scenarios
|
||||
------------------
|
||||
Functional:
|
||||
1) Start stream capture and get capture info v2. Verify api is success, capture status is hipStreamCaptureStatusActive,
|
||||
identifier returned is valid/non-zero, graph object is returned.
|
||||
2) When stream capture is in progress, create dependent nodes by creating multistream dependencies and verify the api returns
|
||||
valid dependent nodes.
|
||||
3) End stream capture and get capture info. Verify api is success, capture status is hipStreamCaptureStatusNone and
|
||||
identifier/graph/nodes are not returned by api.
|
||||
4) When optional parameters are not passed, make sure api still returns capture status of stream.
|
||||
5) Begin capture on hipStreamPerThread, get capture info v2 and validate results.
|
||||
6) Perform multiple captures and verify the identifier returned is unique.
|
||||
|
||||
Parameter Validation/Negative:
|
||||
1) Capture Status location as nullptr and verify api returns error code.
|
||||
2) Stream as nullptr and verify api returns error code.
|
||||
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr int LAUNCH_ITERS = 1;
|
||||
|
||||
/**
|
||||
* Validates stream capture infov2, launches graph and verifies results
|
||||
*/
|
||||
void validateStreamCaptureInfoV2(hipStream_t mstream) {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr}, streamForLaunch{nullptr};
|
||||
hipEvent_t memcpyEvent1, memsetEvent2, forkStreamEvent;
|
||||
hipGraph_t graph{nullptr}, capInfoGraph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
const hipGraphNode_t *nodelist{};
|
||||
size_t Nbytes = N * sizeof(float), numDependencies;
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&streamForLaunch));
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
}
|
||||
|
||||
// Create cross stream dependencies.
|
||||
// memset/memcpy operations are done on stream1 and stream2
|
||||
// and they are joined back to mainstream
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&memcpyEvent1));
|
||||
HIP_CHECK(hipEventCreate(&memsetEvent2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(mstream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, mstream));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, Nbytes, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipEventRecord(memcpyEvent1, stream1));
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream2));
|
||||
HIP_CHECK(hipEventRecord(memsetEvent2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memcpyEvent1, 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent2, 0));
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
unsigned long long capSequenceID = 0; // NOLINT
|
||||
constexpr int numDepsCreated = 2; // Num of dependencies created
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies));
|
||||
|
||||
// verify capture status is active, sequence id is valid, graph is returned,
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
REQUIRE(capInfoGraph != nullptr);
|
||||
REQUIRE(numDependencies == numDepsCreated);
|
||||
|
||||
// verify dependency nodes list returned is the one we created.
|
||||
hipGraphNodeType type(hipGraphNodeTypeEmpty);
|
||||
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[0], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type0 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphNodeGetType(nodelist[1], &type));
|
||||
if ((type != hipGraphNodeTypeMemset) && (type != hipGraphNodeTypeMemcpy)) {
|
||||
INFO("Type1 returned as " << type);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, mstream, A_d, C_d, N);
|
||||
|
||||
// End capture and verify graph is returned
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, mstream));
|
||||
HIP_CHECK(hipStreamEndCapture(mstream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// verify capture status is inactive and other params are not updated
|
||||
capSequenceID = 0;
|
||||
capInfoGraph = nullptr;
|
||||
numDependencies = 0;
|
||||
nodelist = nullptr;
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
REQUIRE(capSequenceID == 0);
|
||||
REQUIRE(capInfoGraph == nullptr);
|
||||
REQUIRE(nodelist == nullptr);
|
||||
REQUIRE(numDependencies == 0);
|
||||
|
||||
// Verify api still returns capture status when optional args are not passed
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(mstream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusNone);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < LAUNCH_ITERS; i++) {
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForLaunch));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(streamForLaunch));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForLaunch));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(memcpyEvent1));
|
||||
HIP_CHECK(hipEventDestroy(memsetEvent2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
|
||||
// Validate the computation
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (C_h[i] != A_h[i] * A_h[i]) {
|
||||
INFO("A and C not matching at " << i << " C_h[i] " << C_h[i]
|
||||
<< " A_h[i] " << A_h[i]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Functional Test for stream capture and getting capture info V2.
|
||||
* Regular/custom stream is used for stream capture.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_BasicFunctional") {
|
||||
hipStream_t streamForCapture;
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&streamForCapture));
|
||||
validateStreamCaptureInfoV2(streamForCapture);
|
||||
HIP_CHECK(hipStreamDestroy(streamForCapture));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test performs stream capture on hipStreamPerThread and validates
|
||||
* capture info V2.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_hipStreamPerThread") {
|
||||
validateStreamCaptureInfoV2(hipStreamPerThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test starts stream capture on multiple streams and verifies uniqueness of
|
||||
* identifiers returned from capture Info V2.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_UniqueID") {
|
||||
constexpr int numStreams = 100;
|
||||
hipStream_t streams[numStreams]{};
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
std::vector<int> idlist;
|
||||
unsigned long long capSequenceID{}; // NOLINT
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamCreate(&streams[i]));
|
||||
HIP_CHECK(hipStreamBeginCapture(streams[i], hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(streams[i], &captureStatus,
|
||||
&capSequenceID, nullptr, nullptr, nullptr));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capSequenceID > 0);
|
||||
idlist.push_back(capSequenceID);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
for (int j = i+1; j < numStreams; j++) {
|
||||
if (idlist[i] == idlist[j]) {
|
||||
INFO("Same identifier returned for stream "
|
||||
<< i << " and stream " << j);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
HIP_CHECK(hipStreamEndCapture(streams[i], &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streams[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter validation/Negative tests for api
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetCaptureInfo_v2_ParamValidation") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream;
|
||||
float *A_d;
|
||||
hipGraph_t graph{}, capInfoGraph{};
|
||||
hipStreamCaptureStatus captureStatus;
|
||||
unsigned long long capSequenceID; // NOLINT
|
||||
size_t numDependencies;
|
||||
const hipGraphNode_t *nodelist{};
|
||||
constexpr int numBytes{100};
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, numBytes));
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipMemsetAsync(A_d, 0, numBytes, stream));
|
||||
|
||||
SECTION("Capture Status location as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo_v2(stream, nullptr,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Stream as nullptr") {
|
||||
ret = hipStreamGetCaptureInfo_v2(nullptr, &captureStatus,
|
||||
&capSequenceID, &capInfoGraph, &nodelist, &numDependencies);
|
||||
if ((ret != hipErrorUnknown) && (ret != hipErrorStreamCaptureImplicit)) {
|
||||
INFO("Ret : " << ret);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
}
|
||||
@@ -18,419 +18,195 @@ THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
constexpr size_t Nbytes = N * sizeof(float);
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
API - hipStreamIsCapturing
|
||||
Negative Testcase Scenarios : Negative
|
||||
1) Check capture status with null pCaptureStatus.
|
||||
2) Check capture status with hipStreamPerThread and null pCaptureStatus.
|
||||
Functional Testcase Scenarios :
|
||||
1) Check capture status with null stream.
|
||||
2) Check capture status with hipStreamPerThread.
|
||||
3) Functional : Create a stream, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
4) Functional : Start capturing a stream and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
5) Functional : Stop capturing a stream and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
6) Functional : Use hipStreamPerThread, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
7) Functional : Start capturing using hipStreamPerThread and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
8) Functional : Stop capturing using hipStreamPerThread and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
9) Functional : Create 2 streams s1 and s2. Start capturing s1. Record event e1
|
||||
on s1 and wait for event e1 on s2. Queue some operations in s1 and s2. Invoke
|
||||
hipStreamIsCapturing on both s1 and s2. Verify that the capture info (status)
|
||||
of both s1 and s2 are identical. Record event e2 on s2 and wait for event e2
|
||||
on s1. End the capture of stream s1. Invoke hipStreamIsCapturing on both streams.
|
||||
Verify that the capture info(status)of both s1 and s2 are identical
|
||||
10)Functional : Create a stream s1. Start capturing s1. Get the capture info using
|
||||
hipStreamIsCapturing of s1. Launch a thread. In the thread get the capture info
|
||||
of s1 using hipStreamIsCapturing. Verify that it is in state hipStreamCaptureStatusActive
|
||||
in thread. Exit the thread and end the capture.
|
||||
11)Functional : Create a stream with default flag (hipStreamDefault). Start capturing
|
||||
the stream. Invoke hipStreamIsCapturing() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
is returned by hipStreamIsCapturing(). Verify capture status of created stream. Do some operatoins.
|
||||
End the capture on the created stream. Execute the graph and verify the output from the operations.
|
||||
*/
|
||||
* @addtogroup hipStreamIsCapturing hipStreamIsCapturing
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipStreamIsCapturing(hipStream_t stream, hipStreamCaptureStatus
|
||||
* *pCaptureStatus)` - get stream's capture state
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Negative") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream{};
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Capture status is nullptr
|
||||
* -# Capture status is checked on null stream
|
||||
* -# Stream is uninitialized
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamIsCapturing.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Negative_Parameters") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
SECTION("Check capture status with null pCaptureStatus.") {
|
||||
ret = hipStreamIsCapturing(stream, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
HIP_CHECK_ERROR(hipStreamIsCapturing(stream, nullptr), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Check capture status with hipStreamPerThread and"
|
||||
" nullptr as pCaptureStatus.") {
|
||||
ret = hipStreamIsCapturing(hipStreamPerThread, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Functional_Basic") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
SECTION("Check capture status when checked on null stream") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
SECTION("Check capture status with null stream.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(nullptr, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK_ERROR(hipStreamIsCapturing(nullptr, &cStatus), hipErrorStreamCaptureImplicit);
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
SECTION("Check capture status with hipStreamPerThread.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
#if HT_NVIDIA // EXSWHTEC-216
|
||||
SECTION("Check capture status when stream is uninitialized") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
|
||||
constexpr auto InvalidStream = [] {
|
||||
StreamGuard sg(Streams::created);
|
||||
return sg.stream();
|
||||
};
|
||||
|
||||
HIP_CHECK_ERROR(hipStreamIsCapturing(InvalidStream(), &cStatus), hipErrorContextIsDestroyed);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
1) Functional : Create a stream, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
2) Functional : Start capturing a stream and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
3) Functional : Stop capturing a stream and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Functional") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Initiate simple API call for stream capture status on custom
|
||||
* stream/hipStreamPerThread
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamIsCapturing.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Positive_Basic") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
void checkStreamCaptureStatus(hipStreamCaptureMode mode, hipStream_t stream) {
|
||||
constexpr size_t N = 1000000;
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
hipStreamCaptureStatus cStatus;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
|
||||
SECTION("Check the stream capture status before start capturing.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Status is none before capture begins
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
|
||||
SECTION("Start capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
}
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
// Status is active during stream capture
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
SECTION("Stop capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
// Status is none after capture ends
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
REQUIRE(graphExec != nullptr);
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec))
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
1) Functional : Use hipStreamPerThread, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
2) Functional : Start capturing using hipStreamPerThread and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
3) Functional : Stop capturing using hipStreamPerThread and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
*/
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Initiate stream capture with different modes on custom
|
||||
* stream/hipStreamPerThread. Check that capture status is correct in different
|
||||
* capturing phases
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamIsCapturing.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Positive_Functional") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_hipStreamPerThread") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
hipGraph_t graph{nullptr};
|
||||
hipStreamCaptureStatus cStatus;
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
SECTION("Check the stream capture status before start capturing.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(hipStreamPerThread,
|
||||
hipStreamCaptureModeGlobal));
|
||||
|
||||
SECTION("Start capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice,
|
||||
hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, hipStreamPerThread));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, hipStreamPerThread, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost,
|
||||
hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(hipStreamPerThread, &graph));
|
||||
|
||||
SECTION("Stop capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
checkStreamCaptureStatus(captureMode, stream);
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and wait
|
||||
* for event e1 on s2. Queue some operations in s1 and s2. Invoke hipStreamIsCapturing
|
||||
* on both s1 and s2. Verify that the capture info (status) of both s1 and s2 are identical.
|
||||
* Record event e2 on s2 and wait for event e2 on s1. End the capture of stream s1.
|
||||
* Invoke hipStreamIsCapturing on both streams. Verify that the capture info(status)
|
||||
* of both s1 and s2 are identical.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_ParentAndForkedStream") {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t event2{nullptr}, forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
B_h[i] = A_h[i];
|
||||
}
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&event2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
// Start capture on stream1
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d, C_d, N);
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, B_d, D_d, N);
|
||||
// Copy data back to the Host
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream2));
|
||||
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone};
|
||||
// Capturing info
|
||||
HIP_CHECK(hipStreamIsCapturing(stream1, &captureStatus1));
|
||||
HIP_CHECK(hipStreamIsCapturing(stream2, &captureStatus2));
|
||||
// Verfication of results
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
|
||||
HIP_CHECK(hipEventRecord(event2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event2, 0));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamIsCapturing(stream1, &captureStatus3));
|
||||
HIP_CHECK(hipStreamIsCapturing(stream2, &captureStatus4));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(event2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
/*
|
||||
* Create a stream s1. Start capturing s1. Get the capture info using hipStreamIsCapturing
|
||||
* of s1. Launch a thread. In the thread get the capture info of s1 using hipStreamIsCapturing.
|
||||
* Verify that it is in state hipStreamCaptureStatusActive in thread. Exit the thread and end
|
||||
* the capture.
|
||||
*/
|
||||
// Thread Function
|
||||
static void thread_func(hipStream_t stream) {
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
hipStreamCaptureStatus cStatus;
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_CheckCaptureStatus_FromThread") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Initiate stream capture with different modes on custom
|
||||
* stream/hipStreamPerThread. Check that capture status is correct when status
|
||||
* is checked in a separate thread
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamIsCapturing.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.2
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Positive_Thread") {
|
||||
constexpr size_t N = 1000000;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
const hipStreamCaptureMode captureMode = hipStreamCaptureModeGlobal;
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceSimple(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), N, stream);
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture info
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
// Thread launch
|
||||
std::thread t(thread_func, stream);
|
||||
t.join();
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a stream with default flag (hipStreamDefault). Start capturing the stream.
|
||||
* Invoke hipStreamIsCapturing() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
* is returned by hipStreamIsCapturing(). Verify capture status of created stream. Do some operatoins.
|
||||
* End the capture on the created stream. Execute the graph and verify the output from the operations.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_ChkNullStrmStatus") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t ret;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 1.0f + i;
|
||||
D_h[i] = 0.0f;
|
||||
}
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone},
|
||||
captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone};
|
||||
// Verify the Error returned if null stream is passed.
|
||||
ret = hipStreamIsCapturing(0, &captureStatus);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
// Check the capture status of the stream
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus1));
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
ret = hipStreamIsCapturing(0, &captureStatus2);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] * A_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
}
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
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_test_kernels.hh>
|
||||
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
constexpr size_t N = 100000;
|
||||
constexpr size_t Nbytes = N * sizeof(float);
|
||||
|
||||
/**
|
||||
API - hipStreamIsCapturing
|
||||
Negative Testcase Scenarios : Negative
|
||||
1) Check capture status with null pCaptureStatus.
|
||||
2) Check capture status with hipStreamPerThread and null pCaptureStatus.
|
||||
Functional Testcase Scenarios :
|
||||
1) Check capture status with null stream.
|
||||
2) Check capture status with hipStreamPerThread.
|
||||
3) Functional : Create a stream, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
4) Functional : Start capturing a stream and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
5) Functional : Stop capturing a stream and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
6) Functional : Use hipStreamPerThread, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
7) Functional : Start capturing using hipStreamPerThread and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
8) Functional : Stop capturing using hipStreamPerThread and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
9) Functional : Create 2 streams s1 and s2. Start capturing s1. Record event e1
|
||||
on s1 and wait for event e1 on s2. Queue some operations in s1 and s2. Invoke
|
||||
hipStreamIsCapturing on both s1 and s2. Verify that the capture info (status)
|
||||
of both s1 and s2 are identical. Record event e2 on s2 and wait for event e2
|
||||
on s1. End the capture of stream s1. Invoke hipStreamIsCapturing on both streams.
|
||||
Verify that the capture info(status)of both s1 and s2 are identical
|
||||
10)Functional : Create a stream s1. Start capturing s1. Get the capture info using
|
||||
hipStreamIsCapturing of s1. Launch a thread. In the thread get the capture info
|
||||
of s1 using hipStreamIsCapturing. Verify that it is in state hipStreamCaptureStatusActive
|
||||
in thread. Exit the thread and end the capture.
|
||||
11)Functional : Create a stream with default flag (hipStreamDefault). Start capturing
|
||||
the stream. Invoke hipStreamIsCapturing() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
is returned by hipStreamIsCapturing(). Verify capture status of created stream. Do some operatoins.
|
||||
End the capture on the created stream. Execute the graph and verify the output from the operations.
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Negative") {
|
||||
hipError_t ret;
|
||||
hipStream_t stream{};
|
||||
|
||||
SECTION("Check capture status with null pCaptureStatus.") {
|
||||
ret = hipStreamIsCapturing(stream, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
SECTION("Check capture status with hipStreamPerThread and"
|
||||
" nullptr as pCaptureStatus.") {
|
||||
ret = hipStreamIsCapturing(hipStreamPerThread, nullptr);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Functional_Basic") {
|
||||
hipStreamCaptureStatus cStatus;
|
||||
|
||||
SECTION("Check capture status with null stream.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(nullptr, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
SECTION("Check capture status with hipStreamPerThread.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
1) Functional : Create a stream, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
2) Functional : Start capturing a stream and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
3) Functional : Stop capturing a stream and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_Functional") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipStreamCaptureStatus cStatus;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
SECTION("Check the stream capture status before start capturing.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
|
||||
SECTION("Start capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
|
||||
SECTION("Stop capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
1) Functional : Use hipStreamPerThread, call api and check
|
||||
capture status is hipStreamCaptureStatusNone.
|
||||
2) Functional : Start capturing using hipStreamPerThread and check
|
||||
capture status returned as hipStreamCaptureStatusActive.
|
||||
3) Functional : Stop capturing using hipStreamPerThread and check
|
||||
status is returned as hipStreamCaptureStatusNone.
|
||||
*/
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_hipStreamPerThread") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
hipGraph_t graph{nullptr};
|
||||
hipStreamCaptureStatus cStatus;
|
||||
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
|
||||
// Fill with Phi + i
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
A_h[i] = 1.618f + i;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
SECTION("Check the stream capture status before start capturing.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(hipStreamPerThread,
|
||||
hipStreamCaptureModeGlobal));
|
||||
|
||||
SECTION("Start capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusActive == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice,
|
||||
hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, hipStreamPerThread));
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, hipStreamPerThread, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost,
|
||||
hipStreamPerThread));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(hipStreamPerThread, &graph));
|
||||
|
||||
SECTION("Stop capturing a stream and check the status.") {
|
||||
HIP_CHECK(hipStreamIsCapturing(hipStreamPerThread, &cStatus));
|
||||
REQUIRE(hipStreamCaptureStatusNone == cStatus);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
/*
|
||||
* Create 2 streams s1 and s2. Start capturing s1. Record event e1 on s1 and wait
|
||||
* for event e1 on s2. Queue some operations in s1 and s2. Invoke hipStreamIsCapturing
|
||||
* on both s1 and s2. Verify that the capture info (status) of both s1 and s2 are identical.
|
||||
* Record event e2 on s2 and wait for event e2 on s1. End the capture of stream s1.
|
||||
* Invoke hipStreamIsCapturing on both streams. Verify that the capture info(status)
|
||||
* of both s1 and s2 are identical.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_ParentAndForkedStream") {
|
||||
hipStream_t stream1{nullptr}, stream2{nullptr};
|
||||
hipEvent_t event2{nullptr}, forkStreamEvent{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
float *A_d, *B_d, *C_d, *D_d;
|
||||
float *A_h, *B_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
B_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(B_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&B_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&D_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(B_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
REQUIRE(D_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 3.146f + i; // Pi
|
||||
B_h[i] = A_h[i];
|
||||
}
|
||||
HIP_CHECK(hipStreamCreate(&stream1));
|
||||
HIP_CHECK(hipStreamCreate(&stream2));
|
||||
HIP_CHECK(hipEventCreate(&event2));
|
||||
HIP_CHECK(hipEventCreate(&forkStreamEvent));
|
||||
// Start capture on stream1
|
||||
HIP_CHECK(hipStreamBeginCapture(stream1, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipEventRecord(forkStreamEvent, stream1));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(B_d, B_h, Nbytes, hipMemcpyHostToDevice, stream2));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream1, A_d, C_d, N);
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream2, B_d, D_d, N);
|
||||
// Copy data back to the Host
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream1));
|
||||
HIP_CHECK(hipMemcpyAsync(D_h, D_d, Nbytes, hipMemcpyDeviceToHost, stream2));
|
||||
|
||||
hipStreamCaptureStatus captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone},
|
||||
captureStatus3{hipStreamCaptureStatusNone},
|
||||
captureStatus4{hipStreamCaptureStatusNone};
|
||||
// Capturing info
|
||||
HIP_CHECK(hipStreamIsCapturing(stream1, &captureStatus1));
|
||||
HIP_CHECK(hipStreamIsCapturing(stream2, &captureStatus2));
|
||||
// Verfication of results
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
REQUIRE(captureStatus2 == hipStreamCaptureStatusActive);
|
||||
|
||||
HIP_CHECK(hipEventRecord(event2, stream2));
|
||||
HIP_CHECK(hipStreamWaitEvent(stream1, event2, 0));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream1, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
// Capture Info
|
||||
HIP_CHECK(hipStreamIsCapturing(stream1, &captureStatus3));
|
||||
HIP_CHECK(hipStreamIsCapturing(stream2, &captureStatus4));
|
||||
// Verification of results
|
||||
REQUIRE(captureStatus3 == hipStreamCaptureStatusNone);
|
||||
REQUIRE(captureStatus4 == hipStreamCaptureStatusNone);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream1));
|
||||
HIP_CHECK(hipStreamDestroy(stream2));
|
||||
HIP_CHECK(hipEventDestroy(forkStreamEvent));
|
||||
HIP_CHECK(hipEventDestroy(event2));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(B_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
HIP_CHECK(hipFree(D_d));
|
||||
free(A_h);
|
||||
free(B_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
/*
|
||||
* Create a stream s1. Start capturing s1. Get the capture info using hipStreamIsCapturing
|
||||
* of s1. Launch a thread. In the thread get the capture info of s1 using hipStreamIsCapturing.
|
||||
* Verify that it is in state hipStreamCaptureStatusActive in thread. Exit the thread and end
|
||||
* the capture.
|
||||
*/
|
||||
// Thread Function
|
||||
static void thread_func(hipStream_t stream) {
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_CheckCaptureStatus_FromThread") {
|
||||
hipStream_t stream{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
// Capture info
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
// Thread launch
|
||||
std::thread t(thread_func, stream);
|
||||
t.join();
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a stream with default flag (hipStreamDefault). Start capturing the stream.
|
||||
* Invoke hipStreamIsCapturing() on the null stream. Verify hipErrorStreamCaptureImplicit
|
||||
* is returned by hipStreamIsCapturing(). Verify capture status of created stream. Do some operatoins.
|
||||
* End the capture on the created stream. Execute the graph and verify the output from the operations.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamIsCapturing_ChkNullStrmStatus") {
|
||||
hipStream_t stream{nullptr}, streamForGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
hipError_t ret;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h, *D_h;
|
||||
// Memory allocation to Host pointers
|
||||
A_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
C_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
D_h = reinterpret_cast<float*>(malloc(Nbytes));
|
||||
REQUIRE(A_h != nullptr);
|
||||
REQUIRE(C_h != nullptr);
|
||||
REQUIRE(D_h != nullptr);
|
||||
|
||||
// Memory allocation to Device pointers
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
// Initialize input buffer
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
A_h[i] = 1.0f + i;
|
||||
D_h[i] = 0.0f;
|
||||
}
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone},
|
||||
captureStatus1{hipStreamCaptureStatusNone},
|
||||
captureStatus2{hipStreamCaptureStatusNone};
|
||||
// Verify the Error returned if null stream is passed.
|
||||
ret = hipStreamIsCapturing(0, &captureStatus);
|
||||
REQUIRE(ret == hipErrorStreamCaptureImplicit);
|
||||
// Check the capture status of the stream
|
||||
HIP_CHECK(hipStreamIsCapturing(stream, &captureStatus1));
|
||||
REQUIRE(captureStatus1 == hipStreamCaptureStatusActive);
|
||||
// Copy data to Device
|
||||
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
|
||||
// Kernal Operations
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
|
||||
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
|
||||
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
// End the capture
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
ret = hipStreamIsCapturing(0, &captureStatus2);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
|
||||
// Launch graph
|
||||
hipGraphExec_t graphExec;
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
// Verify Output
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
D_h[i] = A_h[i] * A_h[i];
|
||||
REQUIRE(C_h[i] == D_h[i]);
|
||||
}
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
free(D_h);
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <hip_test_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
/**
|
||||
* @addtogroup hipStreamUpdateCaptureDependencies
|
||||
* hipStreamUpdateCaptureDependencies
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipStreamUpdateCaptureDependencies(hipStream_t stream, hipGraphNode_t
|
||||
* *dependencies, size_t numDependencies, unsigned int flags __dparm(0)))` -
|
||||
* update the set of dependencies in a capturing stream
|
||||
*/
|
||||
|
||||
static __global__ void vectorSet(const float* A_d, float* B_d, int64_t NELEM) {
|
||||
size_t offset = (blockIdx.x * blockDim.x + threadIdx.x);
|
||||
size_t stride = blockDim.x * gridDim.x;
|
||||
|
||||
for (size_t i = offset; i < NELEM; i += stride) {
|
||||
B_d[i] = A_d[i];
|
||||
}
|
||||
}
|
||||
|
||||
static __global__ void vectorSum(const float* A_d, const float* B_d, float* C_d, size_t NELEM) {
|
||||
size_t offset = (blockIdx.x * blockDim.x + threadIdx.x);
|
||||
size_t stride = blockDim.x * gridDim.x;
|
||||
|
||||
for (size_t i = offset; i < NELEM; i += stride) {
|
||||
C_d[i] = A_d[i] + B_d[i] + C_d[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Local Function for setting new dependency
|
||||
*/
|
||||
static void UpdateStreamCaptureDependenciesSet(hipStream_t stream,
|
||||
hipStreamCaptureMode captureMode) {
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
hipGraph_t capInfoGraph{nullptr};
|
||||
const hipGraphNode_t* nodelist{};
|
||||
size_t numDependencies;
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> C_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> B_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> C_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
EventsGuard events_guard(3);
|
||||
StreamsGuard streams_guard(2);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceBranched(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream,
|
||||
streams_guard.stream_list(), events_guard.event_list());
|
||||
|
||||
constexpr int numDepsCreated = 2; // Num of dependencies created
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capInfoGraph != nullptr);
|
||||
REQUIRE(numDependencies == numDepsCreated);
|
||||
|
||||
SECTION("Set dependency to independent Memcpy node") {
|
||||
// Create memcpy node and set it as a capture dependency in graph
|
||||
hipMemcpy3DParms myparams{};
|
||||
hipGraphNode_t memcpyNodeC{};
|
||||
|
||||
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
|
||||
myparams.srcPos = make_hipPos(0, 0, 0);
|
||||
myparams.dstPos = make_hipPos(0, 0, 0);
|
||||
myparams.extent = make_hipExtent(Nbytes, 1, 1);
|
||||
myparams.srcPtr = make_hipPitchedPtr(C_h.host_ptr(), Nbytes, N, 1);
|
||||
myparams.dstPtr = make_hipPitchedPtr(C_d.ptr(), Nbytes, N, 1);
|
||||
myparams.kind = hipMemcpyHostToDevice;
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNodeC, capInfoGraph, nullptr, 0, &myparams));
|
||||
|
||||
// Replace capture dependency with new memcpy node created.
|
||||
// Further nodes captured in stream will depend on the new memcpy node.
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, &memcpyNodeC, 1,
|
||||
hipStreamSetCaptureDependencies));
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
|
||||
// Verify updating dependency is taking effect.
|
||||
REQUIRE(numDependencies == 1);
|
||||
REQUIRE(nodelist[0] == memcpyNodeC);
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), dim3(threadsPerBlock), 0, stream,
|
||||
C_d.ptr(), C_d.ptr(), N);
|
||||
}
|
||||
|
||||
SECTION("Set dependency to Kernel node depending on graph branch") {
|
||||
hipGraphNode_t kernelNode{};
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
|
||||
// Add node to modify vector sqr result and plug-in the nod
|
||||
float* C_ptr = C_d.ptr();
|
||||
float* A_ptr = A_d.ptr();
|
||||
size_t NElem{N};
|
||||
void* kernelArgs[] = {&A_ptr, &C_ptr, reinterpret_cast<void*>(&NElem)};
|
||||
kernelNodeParams.func = reinterpret_cast<void*>(HipTest::vector_square<float>);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&kernelNode, capInfoGraph, &nodelist[0], 1, &kernelNodeParams));
|
||||
|
||||
// Replace capture dependency with new kernel node created.
|
||||
// Further nodes captured in stream will depend on the new kernel node.
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, &kernelNode, 1,
|
||||
hipStreamSetCaptureDependencies));
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
|
||||
// Verify updating dependency is taking effect.
|
||||
REQUIRE(numDependencies == 1);
|
||||
REQUIRE(nodelist[0] == kernelNode);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(B_h.ptr(), C_d.ptr(), Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
std::fill_n(C_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i) * static_cast<float>(i), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/* Local Function for adding new dependency
|
||||
*/
|
||||
static void UpdateStreamCaptureDependenciesAdd(hipStream_t stream,
|
||||
hipStreamCaptureMode captureMode) {
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
hipStreamCaptureStatus captureStatus{hipStreamCaptureStatusNone};
|
||||
hipGraph_t capInfoGraph{nullptr};
|
||||
const hipGraphNode_t* nodelist{};
|
||||
size_t numDependencies;
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> C_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> B_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> C_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
EventsGuard events_guard(3);
|
||||
StreamsGuard streams_guard(2);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, captureMode));
|
||||
captureSequenceBranched(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream,
|
||||
streams_guard.stream_list(), events_guard.event_list());
|
||||
|
||||
constexpr int numDepsCreated = 2; // Num of dependencies created
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
REQUIRE(captureStatus == hipStreamCaptureStatusActive);
|
||||
REQUIRE(capInfoGraph != nullptr);
|
||||
REQUIRE(numDependencies == numDepsCreated);
|
||||
|
||||
SECTION("Add Dependency to independant Memcpy node") {
|
||||
// Create memcpy node and add it as additional dependency in graph
|
||||
hipMemcpy3DParms myparams{};
|
||||
hipGraphNode_t memcpyNodeC{};
|
||||
|
||||
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
|
||||
myparams.srcPos = make_hipPos(0, 0, 0);
|
||||
myparams.dstPos = make_hipPos(0, 0, 0);
|
||||
myparams.extent = make_hipExtent(Nbytes, 1, 1);
|
||||
myparams.srcPtr = make_hipPitchedPtr(C_h.host_ptr(), Nbytes, N, 1);
|
||||
myparams.dstPtr = make_hipPitchedPtr(C_d.ptr(), Nbytes, N, 1);
|
||||
myparams.kind = hipMemcpyHostToDevice;
|
||||
|
||||
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNodeC, capInfoGraph, nullptr, 0, &myparams));
|
||||
|
||||
// Add/Append additional dependency MemcpyNodeC to the existing set.
|
||||
// Further nodes captured in stream will depend on Memcpy nodes A, B and C.
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, &memcpyNodeC, 1,
|
||||
hipStreamAddCaptureDependencies));
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
|
||||
REQUIRE(numDependencies == numDepsCreated + 1);
|
||||
|
||||
hipLaunchKernelGGL(vectorSum, dim3(blocks), dim3(threadsPerBlock), 0, stream, A_d.ptr(),
|
||||
C_d.ptr(), B_d.ptr(), N);
|
||||
}
|
||||
|
||||
SECTION("Add Dependency to Kernel node depending on graph branch") {
|
||||
hipGraphNode_t kernelNode{};
|
||||
hipKernelNodeParams kernelNodeParams{};
|
||||
|
||||
// Add node to modify vector sqr result and plug-in the nod
|
||||
float* C_ptr = C_d.ptr();
|
||||
float* A_ptr = A_d.ptr();
|
||||
size_t NElem{N};
|
||||
void* kernelArgs[] = {&A_ptr, &C_ptr, reinterpret_cast<void*>(&NElem)};
|
||||
kernelNodeParams.func = reinterpret_cast<void*>(vectorSet);
|
||||
kernelNodeParams.gridDim = dim3(blocks);
|
||||
kernelNodeParams.blockDim = dim3(threadsPerBlock);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs);
|
||||
kernelNodeParams.extra = nullptr;
|
||||
HIP_CHECK(hipGraphAddKernelNode(&kernelNode, capInfoGraph, &nodelist[0], 1, &kernelNodeParams));
|
||||
|
||||
// Add/Append additional dependency addNode to the existing set.
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, &kernelNode, 1,
|
||||
hipStreamAddCaptureDependencies));
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
|
||||
REQUIRE(numDependencies == numDepsCreated + 1);
|
||||
|
||||
hipLaunchKernelGGL(vectorSum, dim3(blocks), dim3(threadsPerBlock), 0, stream, A_d.ptr(),
|
||||
C_d.ptr(), B_d.ptr(), N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(B_h.ptr(), B_d.ptr(), Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
// Replay the recorded sequence multiple times
|
||||
for (int i = 0; i < kLaunchIters; i++) {
|
||||
std::fill_n(A_h.host_ptr(), N, static_cast<float>(i));
|
||||
std::fill_n(C_h.host_ptr(), N, static_cast<float>(i));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
ArrayFindIfNot(B_h.host_ptr(), static_cast<float>(i) * 2, N);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify replacing existing dependency set with new nodes by
|
||||
* calling the api with flag hipStreamSetCaptureDependencies for
|
||||
* created/hipStreamPerThread for all capture modes. Verify updated dependency
|
||||
* list is taking effect:
|
||||
* -# Replace existing dependencies with a new memcpy node that has no
|
||||
* dependencies
|
||||
* -# Replace existing dependencies with a new kernel node which depends
|
||||
* on a previously captured sequence
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamUpdateCaptureDependencies.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamSetCaptureDependencies_Positive_Functional") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
UpdateStreamCaptureDependenciesSet(stream, captureMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify adding additional depencies in the flow by calling the
|
||||
* api with flag hipStreamAddCaptureDependencies for created/hipStreamPerThread
|
||||
* for all capture modes. Verify updated dependency list is taking effect:
|
||||
* -# Add new memcpy node that has no parent to the existing dependecies
|
||||
* -# Add new kernel node which depends on a previously captured sequence
|
||||
* to the existing dependencies
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamUpdateCaptureDependencies.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamAddCaptureDependencies_Positive_Functional") {
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
UpdateStreamCaptureDependenciesAdd(stream, captureMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify when dependencies are passed as nullptr and numDeps as 0,
|
||||
* api returns success
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamUpdateCaptureDependencies.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamUpdateCaptureDependencies_Positive_Parameters") {
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
const auto stream_type = GENERATE(Streams::perThread, Streams::created);
|
||||
StreamGuard stream_guard(stream_type);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureMode = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
const hipStreamUpdateCaptureDependenciesFlags flag =
|
||||
GENERATE(hipStreamAddCaptureDependencies, hipStreamSetCaptureDependencies);
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, nullptr, 0, flag));
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Pass Dependencies as nullptr and numDeps as nonzero
|
||||
* -# numDeps exceeds actual number of nodes
|
||||
* -# Invalid flag is passed
|
||||
* -# Dependency node is a un-initialized/invalid parameter
|
||||
* -# Stream is not capturing
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipStreamUpdateCaptureDependencies.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamUpdateCaptureDependencies_Negative_Parameters") {
|
||||
const int Nbytes = 100;
|
||||
hipGraph_t capInfoGraph{nullptr};
|
||||
hipGraph_t graph{nullptr};
|
||||
|
||||
hipStreamCaptureStatus captureStatus;
|
||||
size_t numDependencies;
|
||||
const hipGraphNode_t* nodelist{};
|
||||
hipGraphNode_t memsetNode{};
|
||||
std::vector<hipGraphNode_t> dependencies;
|
||||
|
||||
LinearAllocGuard<char> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
|
||||
HIP_CHECK(hipMemsetAsync(A_d.ptr(), 0, Nbytes, stream));
|
||||
|
||||
HIP_CHECK(hipStreamGetCaptureInfo_v2(stream, &captureStatus, nullptr, &capInfoGraph, &nodelist,
|
||||
&numDependencies));
|
||||
|
||||
hipMemsetParams memsetParams{};
|
||||
memsetParams.dst = reinterpret_cast<void*>(A_d.ptr());
|
||||
memsetParams.value = 1;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(char);
|
||||
memsetParams.width = Nbytes;
|
||||
memsetParams.height = 1;
|
||||
HIP_CHECK(
|
||||
hipGraphAddMemsetNode(&memsetNode, capInfoGraph, nodelist, numDependencies, &memsetParams));
|
||||
dependencies.push_back(memsetNode);
|
||||
|
||||
SECTION("Dependencies as nullptr and numDeps as nonzero") {
|
||||
HIP_CHECK_ERROR(hipStreamUpdateCaptureDependencies(stream, nullptr, dependencies.size(),
|
||||
hipStreamAddCaptureDependencies),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Invalid flag") {
|
||||
constexpr int invalidFlag = 20;
|
||||
HIP_CHECK_ERROR(hipStreamUpdateCaptureDependencies(stream, dependencies.data(),
|
||||
dependencies.size(), invalidFlag),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
#if HT_NVIDIA // EXSWHTEC-227
|
||||
SECTION("numDeps exceeding actual number of nodes") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipStreamUpdateCaptureDependencies(stream, dependencies.data(), dependencies.size() + 1,
|
||||
hipStreamAddCaptureDependencies),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("depnode as un-initialized/invalid parameter") {
|
||||
hipGraphNode_t uninit_node{};
|
||||
HIP_CHECK_ERROR(hipStreamUpdateCaptureDependencies(stream, &uninit_node, 1,
|
||||
hipStreamAddCaptureDependencies),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HT_AMD // EXSWHTEC-227
|
||||
HIP_CHECK(hipStreamUpdateCaptureDependencies(stream, dependencies.data(), dependencies.size(),
|
||||
hipStreamAddCaptureDependencies));
|
||||
#endif
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
|
||||
SECTION("Stream is not capturing") {
|
||||
HIP_CHECK_ERROR(
|
||||
hipStreamUpdateCaptureDependencies(stream, dependencies.data(), dependencies.size(),
|
||||
hipStreamAddCaptureDependencies),
|
||||
hipErrorIllegalState);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
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_checkers.hh>
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <hip_test_defgroups.hh>
|
||||
|
||||
#include "stream_capture_common.hh"
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup hipThreadExchangeStreamCaptureMode
|
||||
* hipThreadExchangeStreamCaptureMode
|
||||
* @{
|
||||
* @ingroup GraphTest
|
||||
* `hipThreadExchangeStreamCaptureMode(hipStreamCaptureMode *mode)` -
|
||||
* swaps the stream capture mode of a thread
|
||||
*/
|
||||
|
||||
/* Local Function for swaping stream capture mode of a thread
|
||||
*/
|
||||
static void hipGraphLaunchWithMode(hipStream_t stream, hipStreamCaptureMode mode) {
|
||||
constexpr size_t N = 1024;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
constexpr float fill_value = 5.0f;
|
||||
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
|
||||
LinearAllocGuard<float> A_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> B_h(LinearAllocs::malloc, Nbytes);
|
||||
LinearAllocGuard<float> A_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
LinearAllocGuard<float> B_d(LinearAllocs::hipMalloc, Nbytes);
|
||||
float* C_d;
|
||||
|
||||
HIP_CHECK(hipThreadExchangeStreamCaptureMode(&mode));
|
||||
|
||||
HIP_CHECK(hipStreamBeginCapture(stream, mode));
|
||||
|
||||
captureSequenceLinear(A_h.host_ptr(), A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream);
|
||||
captureSequenceCompute(A_d.ptr(), B_h.host_ptr(), B_d.ptr(), N, stream);
|
||||
|
||||
if (mode == hipStreamCaptureModeRelaxed) {
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamEndCapture(stream, &graph));
|
||||
|
||||
// Validate end capture is successful
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
std::fill_n(A_h.host_ptr(), N, fill_value);
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, stream));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
|
||||
// Validate the computation
|
||||
ArrayFindIfNot(B_h.host_ptr(), fill_value * fill_value, N);
|
||||
if (mode == hipStreamCaptureModeRelaxed) {
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
}
|
||||
|
||||
void threadFuncCaptureMode(hipStream_t stream, hipStreamCaptureMode mode) {
|
||||
hipGraphLaunchWithMode(stream, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify basic functionality for API that swaps the stream capture
|
||||
* mode of a thread. All combinations for main and other thread capture modes
|
||||
* are tested
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipThreadExchangeStreamCaptureMode.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
TEST_CASE("Unit_hipThreadExchangeStreamCaptureMode_Positive_Functional") {
|
||||
StreamGuard stream_guard(Streams::created);
|
||||
hipStream_t stream = stream_guard.stream();
|
||||
|
||||
const hipStreamCaptureMode captureModeMain = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
const hipStreamCaptureMode captureModeThread = GENERATE(
|
||||
hipStreamCaptureModeGlobal, hipStreamCaptureModeThreadLocal, hipStreamCaptureModeRelaxed);
|
||||
|
||||
hipGraphLaunchWithMode(stream, captureModeMain);
|
||||
std::thread t(threadFuncCaptureMode, stream, captureModeThread);
|
||||
t.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Description
|
||||
* ------------------------
|
||||
* - Test to verify API behavior with invalid arguments:
|
||||
* -# Mode as nullptr
|
||||
* -# Mode as -1
|
||||
* -# Mode as INT_MAX
|
||||
* -# Mode other than existing 3 modes (hipStreamCaptureModeRelaxed + 1)
|
||||
* Test source
|
||||
* ------------------------
|
||||
* - catch\unit\graph\hipThreadExchangeStreamCaptureMode.cc
|
||||
* Test requirements
|
||||
* ------------------------
|
||||
* - HIP_VERSION >= 5.3
|
||||
*/
|
||||
#if HT_AMD // getting error in Cuda Setup
|
||||
TEST_CASE("Unit_hipThreadExchangeStreamCaptureMode_Negative_Parameters") {
|
||||
hipStreamCaptureMode mode;
|
||||
|
||||
SECTION("Pass Mode as nullptr") {
|
||||
HIP_CHECK_ERROR(hipThreadExchangeStreamCaptureMode(nullptr), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Pass Mode as -1") {
|
||||
mode = hipStreamCaptureMode(-1);
|
||||
HIP_CHECK_ERROR(hipThreadExchangeStreamCaptureMode(&mode), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Pass Mode as INT_MAX") {
|
||||
mode = hipStreamCaptureMode(INT_MAX);
|
||||
HIP_CHECK_ERROR(hipThreadExchangeStreamCaptureMode(&mode), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Pass Mode as hipStreamCaptureModeRelaxed + 1") {
|
||||
mode = hipStreamCaptureMode(hipStreamCaptureModeRelaxed + 1);
|
||||
HIP_CHECK_ERROR(hipThreadExchangeStreamCaptureMode(&mode), hipErrorInvalidValue);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
#include <utils.hh>
|
||||
#include <resource_guards.hh>
|
||||
|
||||
namespace {
|
||||
inline constexpr size_t kLaunchIters = 10;
|
||||
} // anonymous namespace
|
||||
|
||||
template <typename T>
|
||||
void captureSequenceSimple(T* hostMem1, T* devMem1, T* hostMem2, size_t N,
|
||||
hipStream_t captureStream) {
|
||||
size_t Nbytes = N * sizeof(T);
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(devMem1, 0, Nbytes, captureStream));
|
||||
HIP_CHECK(hipMemcpyAsync(devMem1, hostMem1, Nbytes, hipMemcpyHostToDevice, captureStream));
|
||||
HIP_CHECK(hipMemcpyAsync(hostMem2, devMem1, Nbytes, hipMemcpyDeviceToHost, captureStream));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void captureSequenceLinear(T* hostMem1, T* devMem1, T* hostMem2, T* devMem2, size_t N,
|
||||
hipStream_t captureStream) {
|
||||
size_t Nbytes = N * sizeof(T);
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(devMem1, hostMem1, Nbytes, hipMemcpyHostToDevice, captureStream));
|
||||
|
||||
HIP_CHECK(hipMemsetAsync(devMem2, 0, Nbytes, captureStream));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void captureSequenceBranched(T* hostMem1, T* devMem1, T* hostMem2, T* devMem2, size_t N,
|
||||
hipStream_t captureStream, std::vector<hipStream_t>& streams,
|
||||
std::vector<hipEvent_t>& events) {
|
||||
size_t Nbytes = N * sizeof(T);
|
||||
|
||||
HIP_CHECK(hipEventRecord(events[0], captureStream));
|
||||
HIP_CHECK(hipStreamWaitEvent(streams[0], events[0], 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(streams[1], events[0], 0));
|
||||
HIP_CHECK(hipMemsetAsync(devMem1, 0, Nbytes, streams[0]));
|
||||
HIP_CHECK(hipMemcpyAsync(devMem1, hostMem1, Nbytes, hipMemcpyHostToDevice, streams[0]));
|
||||
HIP_CHECK(hipEventRecord(events[1], streams[0]));
|
||||
HIP_CHECK(hipMemsetAsync(devMem2, 0, Nbytes, streams[1]));
|
||||
HIP_CHECK(hipEventRecord(events[2], streams[1]));
|
||||
HIP_CHECK(hipStreamWaitEvent(captureStream, events[1], 0));
|
||||
HIP_CHECK(hipStreamWaitEvent(captureStream, events[2], 0));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void captureSequenceCompute(T* devMem1, T* hostMem2, T* devMem2, size_t N, hipStream_t stream) {
|
||||
size_t Nbytes = N * sizeof(T);
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
|
||||
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), dim3(threadsPerBlock), 0, stream,
|
||||
devMem1, devMem2, N);
|
||||
|
||||
HIP_CHECK(hipMemcpyAsync(hostMem2, devMem2, Nbytes, hipMemcpyDeviceToHost, stream));
|
||||
}
|
||||
Αναφορά σε νέο ζήτημα
Block a user