SWDEV-299127 - Merge 'develop' into 'amd-staging'
Change-Id: I9b17091d0113e2cceedec0c12390578b062ee55b
This commit is contained in:
فروخته شده
+3
-1
@@ -59,6 +59,7 @@ def hipBuildTest(String backendLabel) {
|
||||
# Check if backend label contains string "amd" or backend host is a server with amd gpu
|
||||
if [[ $backendLabel =~ amd ]]; then
|
||||
LLVM_PATH=/opt/rocm/llvm ctest -E 'cooperative_streams_least_capacity.tst|cooperative_streams_half_capacity.tst|cooperative_streams_full_capacity.tst|grid_group_data_sharing.tst|hipIpcMemAccessTest.tst|p2p_copy_coherency.tst'
|
||||
sleep 120
|
||||
else
|
||||
make test
|
||||
fi
|
||||
@@ -100,7 +101,8 @@ def hipBuildTest(String backendLabel) {
|
||||
# Check if backend label contains string "amd" or backend host is a server with amd gpu
|
||||
if [[ $backendLabel =~ amd ]]; then
|
||||
export HT_CONFIG_FILE="$HIP_DIR/tests/catch/hipTestMain/config/config_amd_linux.json"
|
||||
LLVM_PATH=/opt/rocm/llvm ctest -E 'Unit_hipGraphChildGraphNodeGetGraph_Functional|Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative'
|
||||
LLVM_PATH=/opt/rocm/llvm ctest -E 'Unit_hipGraphChildGraphNodeGetGraph_Functional|Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative|Unit_hipPtrGetAttribute_Simple'
|
||||
sleep 120
|
||||
else
|
||||
make test
|
||||
fi
|
||||
|
||||
@@ -107,14 +107,9 @@ find_library(CLANGRT_BUILTINS
|
||||
PATHS
|
||||
${HIP_CLANGRT_LIB_SEARCH_PATHS}
|
||||
${HIP_CLANG_INCLUDE_PATH}/../lib/linux)
|
||||
#FILE_REORG_BACKWARD_COMPATIBILITY
|
||||
set_target_properties(hip-lang::device PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/../include;
|
||||
$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/include;
|
||||
${HIP_CLANG_INCLUDE_PATH}>"
|
||||
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/../include;
|
||||
$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/include;
|
||||
${HIP_CLANG_INCLUDE_PATH}>"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/include;${HIP_CLANG_INCLUDE_PATH}>"
|
||||
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:HIP>:${_IMPORT_PREFIX}/include;${HIP_CLANG_INCLUDE_PATH}>"
|
||||
)
|
||||
|
||||
set_target_properties(hip-lang::amdhip64 PROPERTIES
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright (c) 2015 - 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.
|
||||
*/
|
||||
#ifndef HIP_MATH_CONSTANTS_H
|
||||
#define HIP_MATH_CONSTANTS_H
|
||||
#if(defined(__HIP_PLATFORM_HCC__) || defined(__HIP_PLATFORM_AMD__))
|
||||
#include "hip/amd_detail/amd_hip_math_constants.h"
|
||||
#elif(defined(__HIP_PLATFORM_NVCC__) || defined(__HIP_PLATFORM_NVIDIA__))
|
||||
#include "hip/nvidia_detail/nvidia_hip_math_constants.h"
|
||||
#else
|
||||
#error("Must define exactly one of __HIP_PLATFORM_AMD__ or __HIP_PLATFORM_NVIDIA__");
|
||||
#endif
|
||||
#endif
|
||||
@@ -160,9 +160,10 @@ typedef enum hipMemoryType {
|
||||
hipMemoryTypeHost, ///< Memory is physically located on host
|
||||
hipMemoryTypeDevice, ///< Memory is physically located on device. (see deviceId for specific
|
||||
///< device)
|
||||
hipMemoryTypeArray, ///< Array memory, physically located on device. (see deviceId for specific
|
||||
///< device)
|
||||
hipMemoryTypeUnified ///< Not used currently
|
||||
hipMemoryTypeArray, ///< Array memory, physically located on device. (see deviceId for specific
|
||||
///< device)
|
||||
hipMemoryTypeUnified, ///< Not used currently
|
||||
hipMemoryTypeManaged ///< Managed memory, automaticallly managed by the unified memory system
|
||||
} hipMemoryType;
|
||||
|
||||
/**
|
||||
@@ -547,8 +548,10 @@ typedef struct hipFuncAttributes {
|
||||
} hipFuncAttributes;
|
||||
typedef struct ihipEvent_t* hipEvent_t;
|
||||
enum hipLimit_t {
|
||||
hipLimitPrintfFifoSize = 0x01,
|
||||
hipLimitMallocHeapSize = 0x02,
|
||||
hipLimitStackSize = 0x0, // limit device stack size
|
||||
hipLimitPrintfFifoSize = 0x01, // limit printf fifo size
|
||||
hipLimitMallocHeapSize = 0x02, // limit heap size
|
||||
hipLimitRange // supported limit range
|
||||
};
|
||||
/**
|
||||
* @addtogroup GlobalDefs More
|
||||
@@ -1263,6 +1266,7 @@ hipError_t hipRuntimeGetVersion(int* runtimeVersion);
|
||||
* @returns #hipSuccess, #hipErrorInavlidDevice
|
||||
*/
|
||||
hipError_t hipDeviceGet(hipDevice_t* device, int ordinal);
|
||||
|
||||
/**
|
||||
* @brief Returns the compute capability of the device
|
||||
* @param [out] major
|
||||
@@ -1534,6 +1538,16 @@ hipError_t hipDeviceGetCacheConfig(hipFuncCache_t* cacheConfig);
|
||||
*
|
||||
*/
|
||||
hipError_t hipDeviceGetLimit(size_t* pValue, enum hipLimit_t limit);
|
||||
/**
|
||||
* @brief Set Resource limits of current device
|
||||
*
|
||||
* @param [in] limit
|
||||
* @param [in] value
|
||||
*
|
||||
* @returns #hipSuccess, #hipErrorUnsupportedLimit, #hipErrorInvalidValue
|
||||
*
|
||||
*/
|
||||
hipError_t hipDeviceSetLimit ( enum hipLimit_t limit, size_t value );
|
||||
/**
|
||||
* @brief Returns bank width of shared memory for current device
|
||||
*
|
||||
|
||||
@@ -22,7 +22,7 @@ project(bit_extract)
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
if(NOT DEFINED __HIP_ENABLE_PCH)
|
||||
if(NOT WIN32 AND NOT DEFINED __HIP_ENABLE_PCH)
|
||||
set(__HIP_ENABLE_PCH ON CACHE BOOL "enable/disable pre-compiled hip headers")
|
||||
endif()
|
||||
|
||||
@@ -49,4 +49,4 @@ set(CMAKE_CXX_LINKER ${HIP_HIPCC_EXECUTABLE})
|
||||
add_executable(bit_extract bit_extract.cpp)
|
||||
|
||||
# Link with HIP
|
||||
target_link_libraries(bit_extract hip::host)
|
||||
target_link_libraries(bit_extract hip::host)
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
# THE SOFTWARE.
|
||||
|
||||
#Dependencies : [MYHIP]/bin must be in user's path.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -35,8 +35,8 @@ THE SOFTWARE.
|
||||
}
|
||||
|
||||
__global__ void bit_extract_kernel(uint32_t* C_d, const uint32_t* A_d, size_t N) {
|
||||
size_t offset = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x);
|
||||
size_t stride = hipBlockDim_x * hipGridDim_x;
|
||||
size_t offset = (blockIdx.x * blockDim.x + threadIdx.x);
|
||||
size_t stride = blockDim.x * gridDim.x;
|
||||
|
||||
for (size_t i = offset; i < N; i += stride) {
|
||||
#ifdef __HIP_PLATFORM_AMD__
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -23,6 +23,6 @@ THE SOFTWARE.
|
||||
#include "hip/hip_runtime.h"
|
||||
|
||||
extern "C" __global__ void hello_world(float* a, float* b) {
|
||||
int tx = hipThreadIdx_x;
|
||||
int tx = threadIdx.x;
|
||||
b[tx] = a[tx];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -28,11 +28,11 @@ __device__ float myDeviceGlobal;
|
||||
__device__ float myDeviceGlobalArray[16];
|
||||
|
||||
extern "C" __global__ void hello_world(const float* a, float* b) {
|
||||
int tx = hipThreadIdx_x;
|
||||
int tx = threadIdx.x;
|
||||
b[tx] = a[tx];
|
||||
}
|
||||
|
||||
extern "C" __global__ void test_globals(const float* a, float* b) {
|
||||
int tx = hipThreadIdx_x;
|
||||
int tx = threadIdx.x;
|
||||
b[tx] = a[tx] + myDeviceGlobal + myDeviceGlobalArray[tx % ARRAY_SIZE];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -38,8 +38,8 @@ THE SOFTWARE.
|
||||
*/
|
||||
template <typename T>
|
||||
__global__ void vector_square(T* C_d, const T* A_d, size_t N) {
|
||||
size_t offset = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x);
|
||||
size_t stride = hipBlockDim_x * hipGridDim_x;
|
||||
size_t offset = (blockIdx.x * blockDim_x + threadIdx.x);
|
||||
size_t stride = blockDim.x * gridDim.x;
|
||||
|
||||
for (size_t i = offset; i < N; i += stride) {
|
||||
C_d[i] = A_d[i] * A_d[i];
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -137,7 +137,11 @@ void RunBenchmark_H2D(ResultDatabase& resultDB) {
|
||||
}
|
||||
} else if (p_malloc_mode == MallocUnpinned) {
|
||||
if (p_alignedhost) {
|
||||
hostMem = (float*)aligned_alloc(p_alignedhost, numMaxFloats * sizeof(float));
|
||||
#ifdef _WIN32
|
||||
hostMem = (float*)_aligned_malloc(numMaxFloats * sizeof(float),p_alignedhost);
|
||||
#else
|
||||
hostMem = (float*)aligned_alloc(p_alignedhost, numMaxFloats * sizeof(float));
|
||||
#endif
|
||||
} else {
|
||||
hostMem = new float[numMaxFloats];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#include <typeinfo>
|
||||
|
||||
#include <hip/hip_runtime.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "ResultDatabase.h"
|
||||
#include "nullkernel.hip.cpp"
|
||||
@@ -134,9 +135,15 @@ int parseStandardArguments(int argc, char* argv[]) {
|
||||
|
||||
// Returns the current system time in microseconds
|
||||
inline long long get_time() {
|
||||
#ifdef _WIN32
|
||||
struct timespec ts;
|
||||
timespec_get(&ts, TIME_UTC);
|
||||
return (ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -815,8 +822,11 @@ int main(int argc, char* argv[]) {
|
||||
if (p_blockingSync) {
|
||||
#ifdef __HIP_PLATFORM_AMD__
|
||||
printf("setting BlockingSync for AMD\n");
|
||||
setenv("HIP_BLOCKING_SYNC", "1", 1);
|
||||
|
||||
#ifdef _WIN32
|
||||
_putenv_s("HIP_BLOCKING_SYNC", "1");
|
||||
#else
|
||||
setenv("HIP_BLOCKING_SYNC", "1", 1);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __HIP_PLATFORM_NVIDIA__
|
||||
printf("setting cudaDeviceBlockingSync\n");
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -37,8 +37,8 @@ THE SOFTWARE.
|
||||
|
||||
// Device (Kernel) function, it must be void
|
||||
__global__ void matrixTranspose(float* out, float* in, const int width) {
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
out[y * width + x] = in[x * width + y];
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ __global__ void matrixTranspose(float *out,
|
||||
const int width,
|
||||
const int height)
|
||||
{
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + bhreadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + bhreadIdx.y;
|
||||
|
||||
out[y * width + x] = in[x * height + y];
|
||||
}
|
||||
@@ -39,7 +39,7 @@ other function-type qualifiers are:
|
||||
`__device__` functions are Executed on the device and Called from the device only
|
||||
`__host__` functions are Executed on the host and Called from the host
|
||||
|
||||
`__host__` can combine with `__device__`, in which case the function compiles for both the host and device. These functions cannot use the HIP grid coordinate functions (for example, "hipThreadIdx_x", will talk about it latter). A possible workaround is to pass the necessary coordinate info as an argument to the function.
|
||||
`__host__` can combine with `__device__`, in which case the function compiles for both the host and device. These functions cannot use the HIP grid coordinate functions (for example, "threadIdx.x", will talk about it latter). A possible workaround is to pass the necessary coordinate info as an argument to the function.
|
||||
`__host__` cannot combine with `__global__`.
|
||||
|
||||
`__global__` functions are often referred to as *kernels*, and calling one is termed *launching the kernel*.
|
||||
@@ -47,9 +47,9 @@ other function-type qualifiers are:
|
||||
Next keyword is `void`. HIP `__global__` functions must have a `void` return type. Global functions require the caller to specify an "execution configuration" that includes the grid and block dimensions. The execution configuration can also include other information for the launch, such as the amount of additional shared memory to allocate and the stream where the kernel should execute.
|
||||
|
||||
The kernel function begins with
|
||||
` int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;`
|
||||
` int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;`
|
||||
here the keyword hipBlockIdx_x, hipBlockIdx_y and hipBlockIdx_z(not used here) are the built-in functions to identify the threads in a block. The keyword hipBlockDim_x, hipBlockDim_y and hipBlockDim_z(not used here) are to identify the dimensions of the block.
|
||||
` int x = blockDim.x * blockIdx.x + threadIdx.x;`
|
||||
` int y = blockDim.y * blockIdx.y + threadIdx.y;`
|
||||
here the keyword blockIdx.x, blockIdx.y and blockIdx.z(not used here) are the built-in functions to identify the threads in a block. The keyword blockDim.x, blockDim.y and blockDim.z(not used here) are to identify the dimensions of the block.
|
||||
|
||||
We are familiar with rest of the code on device-side.
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -35,8 +35,8 @@ THE SOFTWARE.
|
||||
|
||||
// Device (Kernel) function, it must be void
|
||||
__global__ void matrixTranspose(float* out, float* in, const int width) {
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
asm volatile("v_mov_b32_e32 %0, %1" : "=v"(out[x * width + y]) : "v"(in[y * width + x]));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -19,15 +19,62 @@ 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"
|
||||
|
||||
texture<float, 2, hipReadModeElementType> tex;
|
||||
texture<char, hipTextureType2D, hipReadModeElementType> texChar;
|
||||
texture<short, hipTextureType2D, hipReadModeElementType> texShort;
|
||||
texture<int, hipTextureType2D, hipReadModeElementType> texInt;
|
||||
texture<float, hipTextureType2D, hipReadModeElementType> texFloat;
|
||||
|
||||
extern "C" __global__ void tex2dKernel(float* outputData, int width, int height) {
|
||||
#if !defined(__HIP_NO_IMAGE_SUPPORT) || !__HIP_NO_IMAGE_SUPPORT
|
||||
int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
|
||||
int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y;
|
||||
outputData[y * width + x] = tex2D(tex, x, y);
|
||||
#endif
|
||||
texture<char4, hipTextureType2D, hipReadModeElementType> texChar4;
|
||||
texture<short4, hipTextureType2D, hipReadModeElementType> texShort4;
|
||||
texture<int4, hipTextureType2D, hipReadModeElementType> texInt4;
|
||||
texture<float4, hipTextureType2D, hipReadModeElementType> texFloat4;
|
||||
|
||||
extern "C" __global__ void tex2dKernelChar(char* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texChar, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelShort(short* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texShort, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelInt(int* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texInt, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelFloat(float* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texFloat, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelChar4(char4* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texChar4, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelShort4(short4* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texShort4, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelInt4(int4* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texInt4, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void tex2dKernelFloat4(float4* outputData, int width, int height) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2D(texFloat4, x, y);
|
||||
}
|
||||
|
||||
@@ -39,92 +39,181 @@ bool testResult = true;
|
||||
} \
|
||||
}
|
||||
|
||||
bool runTest(int argc, char** argv) {
|
||||
unsigned int width = 256;
|
||||
unsigned int height = 256;
|
||||
unsigned int size = width * height * sizeof(float);
|
||||
float* hData = (float*)malloc(size);
|
||||
memset(hData, 0, size);
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
hData[i * width + j] = i * width + j;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value>::type *t = nullptr>
|
||||
static inline hipArray_Format getArrayFormat() {
|
||||
if (std::is_same<char, T>::value) {
|
||||
return HIP_AD_FORMAT_SIGNED_INT8;
|
||||
} else if (std::is_same<short, T>::value) {
|
||||
return HIP_AD_FORMAT_SIGNED_INT16;
|
||||
} else if (std::is_same<int, T>::value) {
|
||||
return HIP_AD_FORMAT_SIGNED_INT32;
|
||||
} else if (std::is_same<float, T>::value) {
|
||||
return HIP_AD_FORMAT_FLOAT;
|
||||
}
|
||||
return HIP_AD_FORMAT_HALF;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value>::type *t = nullptr>
|
||||
static inline hipArray_Format getArrayFormat() {
|
||||
return getArrayFormat<decltype(T::x)>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline constexpr int rank() {
|
||||
return sizeof(T) / sizeof(decltype(T::x));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T getRandom() {
|
||||
double r = 0;
|
||||
if (std::is_signed < T > ::value) {
|
||||
r = (std::rand() - RAND_MAX / 2.0) / (RAND_MAX / 2.0 + 1.);
|
||||
} else {
|
||||
r = std::rand() / (RAND_MAX + 1.);
|
||||
}
|
||||
return static_cast<T>(std::numeric_limits < T > ::max() * r);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
static inline constexpr int getChannels() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value>::type *t = nullptr,
|
||||
typename std::enable_if<rank<T>() != 0>::type *r = nullptr>
|
||||
static inline constexpr int getChannels() {
|
||||
return rank<T>();
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
static inline void printDiff(const int &i, const int &j, const T &expected,
|
||||
const T &output) {
|
||||
std::cout << "Difference [" << i << " " << j << "]: " << expected << " - "
|
||||
<< output << "\n";
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr,
|
||||
typename std::enable_if<rank<T>() == 4>::type* = nullptr>
|
||||
static inline void printDiff(const int &i, const int &j, const T &expected,
|
||||
const T &output) {
|
||||
std::cout << "Difference [" << i << " " << j << "]: " << expected.x << ","
|
||||
<< expected.y << "," << expected.z << "," << expected.w << " - "
|
||||
<< output.x << "," << output.y << "," << output.z << "," << output.w
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
static inline void initVal(T &val) {
|
||||
val = getRandom<T>();
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr,
|
||||
typename std::enable_if<rank<T>() == 4>::type* = nullptr>
|
||||
static inline void initVal(T &val) {
|
||||
val.x = getRandom<decltype(T::x)>();
|
||||
val.y = getRandom<decltype(T::x)>();
|
||||
val.z = getRandom<decltype(T::x)>();
|
||||
val.w = getRandom<decltype(T::x)>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool runTest(hipModule_t &module, const char *refName, const char *funcName) {
|
||||
hipArray_Format format = getArrayFormat<T>();
|
||||
int channels = getChannels<T>();
|
||||
unsigned int width = 256;
|
||||
unsigned int height = 256;
|
||||
unsigned int size = width * height * sizeof(T);
|
||||
T *hData = (T*) malloc(size);
|
||||
memset(hData, 0, size);
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
initVal(hData[i * width + j]);
|
||||
}
|
||||
hipModule_t Module;
|
||||
HIP_CHECK(hipModuleLoad(&Module, fileName));
|
||||
}
|
||||
|
||||
hipArray* array;
|
||||
HIP_ARRAY_DESCRIPTOR desc;
|
||||
desc.Format = HIP_AD_FORMAT_FLOAT;
|
||||
desc.NumChannels = 1;
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
HIP_CHECK(hipArrayCreate(&array, &desc));
|
||||
hipArray *array;
|
||||
HIP_ARRAY_DESCRIPTOR desc;
|
||||
desc.Format = format;
|
||||
desc.NumChannels = channels;
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
HIP_CHECK(hipArrayCreate(&array, &desc));
|
||||
|
||||
hip_Memcpy2D copyParam;
|
||||
memset(©Param, 0, sizeof(copyParam));
|
||||
copyParam.dstMemoryType = hipMemoryTypeArray;
|
||||
copyParam.dstArray = array;
|
||||
copyParam.srcMemoryType = hipMemoryTypeHost;
|
||||
copyParam.srcHost = hData;
|
||||
copyParam.srcPitch = width * sizeof(float);
|
||||
copyParam.WidthInBytes = copyParam.srcPitch;
|
||||
copyParam.Height = height;
|
||||
HIP_CHECK(hipMemcpyParam2D(©Param));
|
||||
hip_Memcpy2D copyParam;
|
||||
memset(©Param, 0, sizeof(copyParam));
|
||||
copyParam.dstMemoryType = hipMemoryTypeArray;
|
||||
copyParam.dstArray = array;
|
||||
copyParam.srcMemoryType = hipMemoryTypeHost;
|
||||
copyParam.srcHost = hData;
|
||||
copyParam.srcPitch = width * sizeof(T);
|
||||
copyParam.WidthInBytes = copyParam.srcPitch;
|
||||
copyParam.Height = height;
|
||||
HIP_CHECK(hipMemcpyParam2D(©Param));
|
||||
|
||||
textureReference* texref;
|
||||
HIP_CHECK(hipModuleGetTexRef(&texref, Module, "tex"));
|
||||
HIP_CHECK(hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap));
|
||||
HIP_CHECK(hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap));
|
||||
HIP_CHECK(hipTexRefSetFilterMode(texref, hipFilterModePoint));
|
||||
HIP_CHECK(hipTexRefSetFlags(texref, 0));
|
||||
HIP_CHECK(hipTexRefSetFormat(texref, HIP_AD_FORMAT_FLOAT, 1));
|
||||
HIP_CHECK(hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT));
|
||||
textureReference *texref;
|
||||
HIP_CHECK(hipModuleGetTexRef(&texref, module, refName));
|
||||
HIP_CHECK(hipTexRefSetAddressMode(texref, 0, hipAddressModeClamp));
|
||||
HIP_CHECK(hipTexRefSetAddressMode(texref, 1, hipAddressModeClamp));
|
||||
HIP_CHECK(hipTexRefSetFilterMode(texref, hipFilterModePoint));
|
||||
HIP_CHECK(hipTexRefSetFlags(texref, HIP_TRSF_READ_AS_INTEGER));
|
||||
HIP_CHECK(hipTexRefSetFormat(texref, format, channels));
|
||||
HIP_CHECK(hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT));
|
||||
|
||||
float* dData = NULL;
|
||||
HIP_CHECK(hipMalloc((void**)&dData, size));
|
||||
T *dData = NULL;
|
||||
HIP_CHECK(hipMalloc((void** )&dData, size));
|
||||
|
||||
struct {
|
||||
void* _Ad;
|
||||
unsigned int _Bd;
|
||||
unsigned int _Cd;
|
||||
} args;
|
||||
args._Ad = (void*) dData;
|
||||
args._Bd = width;
|
||||
args._Cd = height;
|
||||
struct {
|
||||
void *_Ad;
|
||||
unsigned int _Bd;
|
||||
unsigned int _Cd;
|
||||
} args;
|
||||
args._Ad = (void*) dData;
|
||||
args._Bd = width;
|
||||
args._Cd = height;
|
||||
|
||||
size_t sizeTemp = sizeof(args);
|
||||
size_t sizeTemp = sizeof(args);
|
||||
|
||||
void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, HIP_LAUNCH_PARAM_BUFFER_SIZE,
|
||||
&sizeTemp, HIP_LAUNCH_PARAM_END};
|
||||
void *config[] = { HIP_LAUNCH_PARAM_BUFFER_POINTER, &args,
|
||||
HIP_LAUNCH_PARAM_BUFFER_SIZE, &sizeTemp, HIP_LAUNCH_PARAM_END };
|
||||
|
||||
hipFunction_t Function;
|
||||
HIP_CHECK(hipModuleGetFunction(&Function, Module, "tex2dKernel"));
|
||||
hipFunction_t Function;
|
||||
HIP_CHECK(hipModuleGetFunction(&Function, module, funcName));
|
||||
|
||||
int temp1 = width / 16;
|
||||
int temp2 = height / 16;
|
||||
HIP_CHECK(
|
||||
hipModuleLaunchKernel(Function, 16, 16, 1, temp1, temp2, 1, 0, 0, NULL, (void**)&config));
|
||||
hipDeviceSynchronize();
|
||||
int temp1 = width / 16;
|
||||
int temp2 = height / 16;
|
||||
HIP_CHECK(
|
||||
hipModuleLaunchKernel(Function, 16, 16, 1, temp1, temp2, 1, 0, 0, NULL,
|
||||
(void** )&config));
|
||||
hipDeviceSynchronize();
|
||||
|
||||
float* hOutputData = (float*)malloc(size);
|
||||
memset(hOutputData, 0, size);
|
||||
HIP_CHECK(hipMemcpy(hOutputData, dData, size, hipMemcpyDeviceToHost));
|
||||
T *hOutputData = (T*) malloc(size);
|
||||
memset(hOutputData, 0, size);
|
||||
HIP_CHECK(hipMemcpy(hOutputData, dData, size, hipMemcpyDeviceToHost));
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
if (hData[i * width + j] != hOutputData[i * width + j]) {
|
||||
printf("Difference [ %d %d ]:%f ----%f\n", i, j, hData[i * width + j],
|
||||
hOutputData[i * width + j]);
|
||||
testResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
if (hData[i * width + j] != hOutputData[i * width + j]) {
|
||||
printDiff<T>(i, j, hData[i * width + j], hOutputData[i * width + j]);
|
||||
testResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HIP_CHECK(hipUnbindTexture(texref));
|
||||
HIP_CHECK(hipFree(dData));
|
||||
HIP_CHECK(hipFreeArray(array));
|
||||
return testResult;
|
||||
}
|
||||
HIP_CHECK(hipUnbindTexture(texref));
|
||||
HIP_CHECK(hipFree(dData));
|
||||
HIP_CHECK(hipFreeArray(array));
|
||||
free(hOutputData);
|
||||
free(hData);
|
||||
printf("%s test %s ...\n", funcName, testResult ? "PASSED" : "FAILED");
|
||||
return testResult;
|
||||
}
|
||||
|
||||
inline bool isImageSupported() {
|
||||
@@ -137,13 +226,23 @@ inline bool isImageSupported() {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (!isImageSupported()) {
|
||||
printf("Texture is not support on the device. Skipped.\n");
|
||||
return 0;
|
||||
}
|
||||
hipInit(0);
|
||||
testResult = runTest(argc, argv);
|
||||
printf("%s ...\n", testResult ? "PASSED" : "FAILED");
|
||||
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
if (!isImageSupported()) {
|
||||
printf("Texture is not support on the device. Skipped.\n");
|
||||
return 0;
|
||||
}
|
||||
hipInit(0);
|
||||
hipModule_t module;
|
||||
HIP_CHECK(hipModuleLoad(&module, fileName));
|
||||
testResult = testResult && runTest<char>(module, "texChar", "tex2dKernelChar");
|
||||
testResult = testResult && runTest<short>(module, "texShort", "tex2dKernelShort");
|
||||
testResult = testResult && runTest<int>(module, "texInt", "tex2dKernelInt");
|
||||
testResult = testResult && runTest<float>(module, "texFloat", "tex2dKernelFloat");
|
||||
testResult = testResult && runTest<char4>(module, "texChar4", "tex2dKernelChar4");
|
||||
testResult = testResult && runTest<short4>(module, "texShort4", "tex2dKernelShort4");
|
||||
testResult = testResult && runTest<int4>(module, "texInt4", "tex2dKernelInt4");
|
||||
testResult = testResult && runTest<float4>(module, "texFloat4", "tex2dKernelFloat4");
|
||||
|
||||
HIP_CHECK(hipModuleUnload(module));
|
||||
printf("texture2dDrv %s ...\n", testResult ? "PASSED" : "FAILED");
|
||||
return testResult ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ if(NOT DEFINED HIP_PATH)
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_MODULE_PATH "${HIP_PATH}/cmake" ${CMAKE_MODULE_PATH})
|
||||
|
||||
set(CMAKE_HIP_ARCHITECTURES OFF)
|
||||
project(12_cmake)
|
||||
|
||||
set(HIP_CLANG_NUM_PARALLEL_JOBS 2)
|
||||
@@ -58,4 +58,4 @@ find_package(hip QUIET)
|
||||
if(TARGET hip::host)
|
||||
message(STATUS "Found hip::host at ${hip_DIR}")
|
||||
target_link_libraries(${MY_TARGET_NAME} hip::host)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -37,8 +37,8 @@ THE SOFTWARE.
|
||||
|
||||
// Device (Kernel) function, it must be void
|
||||
__global__ void matrixTranspose(float* out, float* in, const int width) {
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
out[y * width + x] = in[x * width + y];
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -36,7 +36,7 @@ THE SOFTWARE.
|
||||
// 'out'
|
||||
// but it will update with "NOT_SUPPORTED" for any other gfx archs.
|
||||
__global__ void incrementKernel(int32_t* in, int32_t* out, int32_t value, size_t buffSize) {
|
||||
int index = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int index = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
if (index < buffSize) {
|
||||
#if defined(__gfx908__)
|
||||
out[index] = in[index] + value;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -37,8 +37,8 @@ THE SOFTWARE.
|
||||
__global__ void matrixTranspose(float* out, float* in, const int width) {
|
||||
extern __shared__ float sharedMem[];
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
sharedMem[y * width + x] = in[x * width + y];
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -37,8 +37,8 @@ __global__ void matrixTranspose_static_shared(float* out, float* in,
|
||||
const int width) {
|
||||
__shared__ float sharedMem[WIDTH * WIDTH];
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
sharedMem[y * width + x] = in[x * width + y];
|
||||
|
||||
@@ -51,8 +51,8 @@ __global__ void matrixTranspose_dynamic_shared(float* out, float* in,
|
||||
const int width) {
|
||||
extern __shared__ float sharedMem[];
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
sharedMem[y * width + x] = in[x * width + y];
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -110,8 +110,8 @@ __global__ void matrixTranspose_static_shared(float* out, float* in,
|
||||
const int width) {
|
||||
__shared__ float sharedMem[WIDTH * WIDTH];
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
sharedMem[y * width + x] = in[x * width + y];
|
||||
|
||||
@@ -124,8 +124,8 @@ __global__ void matrixTranspose_dynamic_shared(float* out, float* in,
|
||||
const int width) {
|
||||
extern __shared__ float sharedMem[];
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
int x = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
int y = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
|
||||
sharedMem[y * width + x] = in[x * width + y];
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
# 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.
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Makefile is not supported on windows platform. Please use cmake instead to build sample.)
|
||||
endif
|
||||
ROCM_PATH?= $(wildcard /opt/rocm/)
|
||||
HIP_PATH?= $(wildcard $(ROCM_PATH)/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
|
||||
@@ -43,7 +43,7 @@ void matrixRowSum(int* input, int* output, int width) {
|
||||
|
||||
// Device (kernel) function
|
||||
__global__ void gpuMatrixRowSum(int* input, int* output, int width) {
|
||||
int index = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int index = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
#pragma unroll
|
||||
for (int i = 0; i < width; i++) {
|
||||
output[index] += input[index * width + i];
|
||||
|
||||
@@ -74,6 +74,12 @@
|
||||
"Unit_hipGraphAddEventRecordNode_MultipleRun",
|
||||
"Unit_hipMalloc3D_Negative",
|
||||
"Unit_hipPointerGetAttribute_MappedMem",
|
||||
"Unit_hipGraphAddMemcpyNode1D_Functional",
|
||||
"Unit_hipGraphAddMemcpyNode1D_Negative",
|
||||
"Unit_hipStreamBeginCapture_BasicFunctional",
|
||||
"Unit_hipStreamBeginCapture_hipStreamPerThread",
|
||||
"Unit_hiprtc_functional",
|
||||
"Unit_hipStreamValue_Write",
|
||||
"# Following test is related to ticket EXSWCPHIPT-41",
|
||||
"Unit_hipStreamGetPriority_happy"
|
||||
]
|
||||
|
||||
@@ -12,6 +12,8 @@ set(LINUX_TEST_SRC
|
||||
hipHostMallocTestsMproc.cc
|
||||
hipMallocConcurrencyMproc.cc
|
||||
hipMemCoherencyTstMProc.cc
|
||||
hipIpcEventHandle.cc
|
||||
hipIpcMemAccessTest.cc
|
||||
)
|
||||
|
||||
# the last argument linker libraries is required for this test but optional to the function
|
||||
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
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, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Testcase Scenarios
|
||||
------------------
|
||||
Functional:
|
||||
1) Validate usecase of Event handle along with memory handle across multiple
|
||||
processes with complex scenario.
|
||||
|
||||
Negative/Argument Validation:
|
||||
1) Get event handle with eventHandle(nullptr).
|
||||
2) Get event handle with event(nullptr).
|
||||
3) Get event handle with invalid event object.
|
||||
4) Get event handle for event allocated without Interprocess flag.
|
||||
5) Open event handle with event(nullptr).
|
||||
6) Open event handle with eventHandle as invalid.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
#define MAX_DEVICES 8
|
||||
|
||||
|
||||
typedef struct ipcEventInfo {
|
||||
int device;
|
||||
pid_t pid;
|
||||
hipIpcEventHandle_t eventHandle;
|
||||
hipIpcMemHandle_t memHandle;
|
||||
} ipcEventInfo_t;
|
||||
|
||||
typedef struct ipcDevices {
|
||||
int count;
|
||||
int ordinals[MAX_DEVICES];
|
||||
} ipcDevices_t;
|
||||
|
||||
typedef struct ipcBarrier {
|
||||
int count;
|
||||
bool sense;
|
||||
bool allExit;
|
||||
} ipcBarrier_t;
|
||||
|
||||
/**
|
||||
Get device count and list down devices with
|
||||
P2P access with Device 0.
|
||||
*/
|
||||
void getDevices(ipcDevices_t *devices) {
|
||||
pid_t pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
// HIP APIs are called in child process,
|
||||
// to avoid HIP Initialization in main process.
|
||||
int i, devCnt{};
|
||||
HIP_CHECK(hipGetDeviceCount(&devCnt));
|
||||
|
||||
if (devCnt < 2) {
|
||||
devices->count = 0;
|
||||
WARN("Count less than expected number of devices");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Device 0
|
||||
devices->ordinals[0] = 0;
|
||||
devices->count = 1;
|
||||
|
||||
// Check possibility for peer accesses, relevant to our tests
|
||||
INFO("Checking GPU(s) for support of p2p memory access ");
|
||||
INFO("Between GPU0 and other GPU(s)");
|
||||
|
||||
int canPeerAccess_0i, canPeerAccess_i0;
|
||||
for (i = 1; i < devCnt; i++) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canPeerAccess_0i, 0, i));
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&canPeerAccess_i0, i, 0));
|
||||
|
||||
if (canPeerAccess_0i * canPeerAccess_i0) {
|
||||
devices->ordinals[i] = i;
|
||||
INFO("Two-way peer access is available between GPU"
|
||||
<< devices->ordinals[0] <<" and GPU"
|
||||
<< devices->ordinals[devices->count]);
|
||||
devices->count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
HIP_ASSERT(!status);
|
||||
}
|
||||
}
|
||||
|
||||
static ipcBarrier_t *g_Barrier{};
|
||||
static bool g_procSense;
|
||||
static int g_processCnt;
|
||||
|
||||
/**
|
||||
Calling process waits for other processes to signal/complete.
|
||||
*/
|
||||
void processBarrier() {
|
||||
int newCount = __sync_add_and_fetch(&g_Barrier->count, 1);
|
||||
|
||||
if (newCount == g_processCnt) {
|
||||
g_Barrier->count = 0;
|
||||
g_Barrier->sense = !g_procSense;
|
||||
|
||||
} else {
|
||||
while (g_Barrier->sense == g_procSense) {
|
||||
if (!g_Barrier->allExit) {
|
||||
sched_yield();
|
||||
} else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_procSense = !g_procSense;
|
||||
}
|
||||
|
||||
|
||||
__global__ void computeKernel(int *dst, int *src, int num) {
|
||||
int idx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
dst[idx] = src[idx] / num;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1) Process 0 allocates buffer in GPU0 memory and exports the memory handle.
|
||||
* 2) Other processes opens memory handle of GPU0 memory, performs computation
|
||||
* and records event.
|
||||
* 3) Process 0 synchronizes event and validates the resulting buffer.
|
||||
*/
|
||||
void runMultiProcKernel(ipcEventInfo_t *shmEventInfo, int index) {
|
||||
int *d_ptr;
|
||||
int hData[BUF_SIZE]{};
|
||||
unsigned int seed = time(nullptr);
|
||||
|
||||
// Randomize data before computation
|
||||
for (int i = 0; i < BUF_SIZE; i++) {
|
||||
hData[i] = rand_r(&seed);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipSetDevice(shmEventInfo[index].device));
|
||||
|
||||
if (index == 0) {
|
||||
int h_results[BUF_SIZE * MAX_DEVICES];
|
||||
hipEvent_t event[MAX_DEVICES];
|
||||
|
||||
HIP_CHECK(hipMalloc(&d_ptr, BUF_SIZE * g_processCnt * sizeof(int)));
|
||||
HIP_CHECK(hipIpcGetMemHandle(&shmEventInfo[0].memHandle, d_ptr));
|
||||
HIP_CHECK(hipMemcpy(d_ptr, hData,
|
||||
BUF_SIZE * sizeof(int), hipMemcpyHostToDevice));
|
||||
|
||||
// Barrier 1: Process0 will wait for all processes to create event handles,
|
||||
// signals device memory creation.
|
||||
processBarrier();
|
||||
|
||||
for (int i = 1; i < g_processCnt; i++) {
|
||||
HIP_CHECK(hipIpcOpenEventHandle(&event[i], shmEventInfo[i].eventHandle));
|
||||
}
|
||||
|
||||
// Barrier 2: Process0 waits for kernels to be launched
|
||||
// and the events to be recorded.
|
||||
processBarrier();
|
||||
|
||||
for (int i = 1; i < g_processCnt; i++) {
|
||||
HIP_CHECK(hipEventSynchronize(event[i]));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipMemcpy(h_results, d_ptr + BUF_SIZE,
|
||||
BUF_SIZE * (g_processCnt - 1) * sizeof(int), hipMemcpyDeviceToHost));
|
||||
|
||||
// Barrier 3: Process0 signals event usage is done.
|
||||
processBarrier();
|
||||
HIP_CHECK(hipFree(d_ptr));
|
||||
for (int n = 1; n < g_processCnt; n++) {
|
||||
for (int i = 0; i < BUF_SIZE; i++) {
|
||||
if (hData[i]/(n + 1) != h_results[(n-1) * BUF_SIZE + i]) {
|
||||
WARN("Data validation error at index " << i << " n" << n);
|
||||
g_Barrier->allExit = true;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hipEvent_t event;
|
||||
HIP_CHECK(hipEventCreateWithFlags(&event,
|
||||
hipEventDisableTiming | hipEventInterprocess));
|
||||
HIP_CHECK(hipIpcGetEventHandle(&shmEventInfo[index].eventHandle, event));
|
||||
|
||||
// Barrier 1 : wait until proc 0 initializes device memory,
|
||||
// signals event creation.
|
||||
processBarrier();
|
||||
HIP_CHECK(hipIpcOpenMemHandle(reinterpret_cast<void **>(&d_ptr),
|
||||
shmEventInfo[0].memHandle,
|
||||
hipIpcMemLazyEnablePeerAccess));
|
||||
const dim3 threads(512, 1);
|
||||
const dim3 blocks(BUF_SIZE / threads.x, 1);
|
||||
hipLaunchKernelGGL(computeKernel, dim3(blocks), dim3(threads), 0, 0,
|
||||
d_ptr + index *BUF_SIZE, d_ptr, index + 1);
|
||||
HIP_CHECK(hipEventRecord(event));
|
||||
|
||||
// Barrier 2 : Signals that event is recorded
|
||||
processBarrier();
|
||||
HIP_CHECK(hipIpcCloseMemHandle(d_ptr));
|
||||
|
||||
// Barrier 3 : wait for all the events to be used up by processes
|
||||
processBarrier();
|
||||
HIP_CHECK(hipEventDestroy(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Functional test demonstrating IPC event usage along with IPC memory handle
|
||||
*/
|
||||
TEST_CASE("Unit_hipIpcEventHandle_Functional") {
|
||||
ipcDevices_t *shmDevices;
|
||||
ipcEventInfo_t *shmEventInfo;
|
||||
shmDevices = reinterpret_cast<ipcDevices_t *> (mmap(NULL, sizeof(*shmDevices),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0));
|
||||
REQUIRE(MAP_FAILED != shmDevices);
|
||||
|
||||
getDevices(shmDevices);
|
||||
|
||||
if (shmDevices->count < 2) {
|
||||
WARN("Test requires atleast two GPUs with P2P access. Skipping test.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_processCnt = shmDevices->count;
|
||||
|
||||
// Barrier is used to synchronize processes created.
|
||||
g_Barrier = reinterpret_cast<ipcBarrier_t *> (mmap(NULL, sizeof(*g_Barrier),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0));
|
||||
REQUIRE(MAP_FAILED != g_Barrier);
|
||||
memset(g_Barrier, 0, sizeof(*g_Barrier));
|
||||
|
||||
// set local barrier sense flag
|
||||
g_procSense = 0;
|
||||
|
||||
// shared memory for Event and memHandle Info
|
||||
shmEventInfo = reinterpret_cast<ipcEventInfo_t *>(mmap(NULL,
|
||||
g_processCnt * sizeof(*shmEventInfo),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0));
|
||||
REQUIRE(MAP_FAILED != shmEventInfo);
|
||||
|
||||
// initialize shared memory
|
||||
memset(shmEventInfo, 0, g_processCnt * sizeof(*shmEventInfo));
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (int i = 1; i < g_processCnt; i++) {
|
||||
int pid = fork();
|
||||
|
||||
if (!pid) {
|
||||
index = i;
|
||||
break;
|
||||
} else {
|
||||
shmEventInfo[i].pid = pid;
|
||||
}
|
||||
}
|
||||
|
||||
shmEventInfo[index].device = shmDevices->ordinals[index];
|
||||
|
||||
// Run the test
|
||||
runMultiProcKernel(shmEventInfo, index);
|
||||
|
||||
// Cleanup
|
||||
if (index == 0) {
|
||||
for (int i = 1; i < g_processCnt; i++) {
|
||||
int status;
|
||||
waitpid(shmEventInfo[i].pid, &status, 0);
|
||||
HIP_ASSERT(WIFEXITED(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Performs API Parameter validation.
|
||||
*/
|
||||
TEST_CASE("Unit_hipIpcEventHandle_ParameterValidation") {
|
||||
hipEvent_t event;
|
||||
hipIpcEventHandle_t eventHandle;
|
||||
hipError_t ret;
|
||||
HIP_CHECK(hipEventCreateWithFlags(&event,
|
||||
hipEventDisableTiming | hipEventInterprocess));
|
||||
#if HT_AMD
|
||||
// Test disabled for nvidia due to segfault with cuda api
|
||||
SECTION("Get event handle with eventHandle(nullptr)") {
|
||||
ret = hipIpcGetEventHandle(nullptr, event);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Get event handle with event(nullptr)") {
|
||||
ret = hipIpcGetEventHandle(&eventHandle, nullptr);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Get event handle with invalid event object") {
|
||||
hipEvent_t eventUninit{};
|
||||
ret = hipIpcGetEventHandle(&eventHandle, eventUninit);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Get event handle for event allocated without Interprocess flag") {
|
||||
hipEvent_t eventNoIpc;
|
||||
HIP_CHECK(hipEventCreateWithFlags(&eventNoIpc, hipEventDisableTiming));
|
||||
|
||||
ret = hipIpcGetEventHandle(&eventHandle, eventNoIpc);
|
||||
if ((ret != hipErrorInvalidResourceHandle) &&
|
||||
(ret != hipErrorInvalidConfiguration)) {
|
||||
INFO("Error returned : " << ret);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Open event handle with event(nullptr)") {
|
||||
hipIpcEventHandle_t ipc_handle{};
|
||||
ret = hipIpcOpenEventHandle(nullptr, ipc_handle);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Open event handle with eventHandle as invalid") {
|
||||
hipIpcEventHandle_t ipc_handle{};
|
||||
hipEvent_t eventOut;
|
||||
ret = hipIpcOpenEventHandle(&eventOut, ipc_handle);
|
||||
if ((ret != hipErrorInvalidValue) && (ret != hipErrorMapFailed)) {
|
||||
INFO("Error returned : " << ret);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
@@ -18,8 +18,9 @@ THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This testcase verifies the hipIpcMemAccess APIs by creating memory handle
|
||||
1)Testcase verifies the hipIpcMemAccess APIs by creating memory handle
|
||||
in parent process and access it in child process.
|
||||
2)Test case performs Parameter validation of hipIpcMemAccess APIs.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
@@ -33,6 +34,11 @@ in parent process and access it in child process.
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define NUM_ELMTS 1024
|
||||
#define NUM_THREADS 10
|
||||
|
||||
|
||||
typedef struct mem_handle {
|
||||
int device;
|
||||
hipIpcMemHandle_t memHandle;
|
||||
@@ -40,6 +46,7 @@ typedef struct mem_handle {
|
||||
} hip_ipc_t;
|
||||
|
||||
|
||||
|
||||
// This testcase verifies the hipIpcMemAccess APIs as follows
|
||||
// The following program spawns a child process and does the following
|
||||
// Parent iterate through each device, create memory -- create hipIpcMemhandle
|
||||
@@ -153,4 +160,63 @@ TEST_CASE("Unit_hipIpcMemAccess_Semaphores") {
|
||||
waitpid(pid, &rFlag, 0);
|
||||
REQUIRE(shrd_mem->IfTestPassed == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipIpcMemAccess_ParameterValidation") {
|
||||
hipIpcMemHandle_t MemHandle;
|
||||
hipIpcMemHandle_t MemHandleUninit;
|
||||
void *Ad{}, *Ad2{};
|
||||
hipError_t ret;
|
||||
|
||||
HIP_CHECK(hipMalloc(&Ad, 1024));
|
||||
|
||||
#if HT_AMD
|
||||
// Test is disabled for nvidia as api resulting in seg fault.
|
||||
SECTION("Get mem handle with handle as nullptr") {
|
||||
ret = hipIpcGetMemHandle(nullptr, Ad);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
SECTION("Get mem handle with devptr as nullptr") {
|
||||
ret = hipIpcGetMemHandle(&MemHandle, nullptr);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Get mem handle with handle/devptr as nullptr") {
|
||||
ret = hipIpcGetMemHandle(nullptr, nullptr);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Get mem handle with valid devptr") {
|
||||
ret = hipIpcGetMemHandle(&MemHandle, Ad);
|
||||
REQUIRE(ret == hipSuccess);
|
||||
}
|
||||
|
||||
SECTION("Open mem handle with devptr as nullptr") {
|
||||
ret = hipIpcOpenMemHandle(nullptr, MemHandle,
|
||||
hipIpcMemLazyEnablePeerAccess);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
SECTION("Open mem handle with handle as un-initialized") {
|
||||
ret = hipIpcOpenMemHandle(&Ad2, MemHandleUninit,
|
||||
hipIpcMemLazyEnablePeerAccess);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
#if HT_AMD
|
||||
// Test is disabled for nvidia as api not returning expected value.
|
||||
SECTION("Open mem handle with flags as random value") {
|
||||
constexpr unsigned int flags = 123;
|
||||
HIP_CHECK(hipIpcGetMemHandle(&MemHandle, Ad));
|
||||
ret = hipIpcOpenMemHandle(&Ad2, MemHandle, flags);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
#endif
|
||||
SECTION("Close mem handle with devptr(nullptr)") {
|
||||
ret = hipIpcCloseMemHandle(nullptr);
|
||||
REQUIRE(ret == hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipFree(Ad));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -56,6 +56,8 @@ set(TEST_SRC
|
||||
hipGraphEventRecordNodeSetEvent.cc
|
||||
hipGraphEventWaitNodeGetEvent.cc
|
||||
hipGraphExecMemcpyNodeSetParams.cc
|
||||
hipStreamBeginCapture.cc
|
||||
hipGraphAddMemcpyNode1D.cc
|
||||
)
|
||||
|
||||
hip_add_exe_to_target(NAME GraphsTest
|
||||
|
||||
@@ -19,6 +19,12 @@ THE SOFTWARE.
|
||||
|
||||
/**
|
||||
Testcase Scenarios :
|
||||
Functional -
|
||||
1) Add 1D memcpy node to graph and verify memcpy operation is success for all memcpy kinds(H2D, D2H and D2D).
|
||||
Memcpy nodes are added and assigned to default device.
|
||||
2) Allocate memory on default device(Dev 0), Perform memcpy operation for 1D arrays on Peer device(Dev 1) and
|
||||
verify the results.
|
||||
|
||||
Negative -
|
||||
1) Pass pGraphNode as nullptr and check if api returns error.
|
||||
2) When graph is un-initialized argument(skipping graph creation), api should return error code.
|
||||
@@ -32,6 +38,101 @@ Negative -
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_checkers.hh>
|
||||
|
||||
|
||||
static void validateMemcpyNode1DArray(bool peerAccess) {
|
||||
constexpr int SIZE{32};
|
||||
int harray1D[SIZE]{};
|
||||
int harray1Dres[SIZE]{};
|
||||
hipGraph_t graph;
|
||||
hipArray *devArray1, *devArray2;
|
||||
hipGraphNode_t memcpyH2D, memcpyD2H, memcpyD2D;
|
||||
constexpr int numBytes{SIZE * sizeof(int)};
|
||||
hipStream_t streamForGraph;
|
||||
hipGraphExec_t graphExec;
|
||||
|
||||
HIP_CHECK(hipSetDevice(0));
|
||||
HIP_CHECK(hipStreamCreate(&streamForGraph));
|
||||
HIP_CHECK(hipMalloc(&devArray1, numBytes));
|
||||
HIP_CHECK(hipMalloc(&devArray2, numBytes));
|
||||
|
||||
// Initialize 1D object
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
harray1D[i] = i + 1;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipGraphCreate(&graph, 0));
|
||||
|
||||
// For peer access test, Memory is allocated on device(0)
|
||||
// while memcpy nodes are allocated and assigned to peer device(1)
|
||||
if (peerAccess) {
|
||||
HIP_CHECK(hipSetDevice(1));
|
||||
}
|
||||
|
||||
// Host to Device (harray1D -> devArray1)
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D, graph, nullptr, 0,
|
||||
devArray1, harray1D, numBytes, hipMemcpyHostToDevice));
|
||||
|
||||
// Device to Device (devArray1 -> devArray2)
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2D, graph, &memcpyH2D, 1,
|
||||
devArray2, devArray1, numBytes, hipMemcpyDeviceToDevice));
|
||||
|
||||
// Device to host (devArray2 -> harray1Dres)
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H, graph, &memcpyD2D, 1,
|
||||
harray1Dres, devArray2, numBytes, hipMemcpyDeviceToHost));
|
||||
|
||||
// Instantiate and launch the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
HIP_CHECK(hipStreamSynchronize(streamForGraph));
|
||||
|
||||
// Validate result
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (harray1D[i] != harray1Dres[i]) {
|
||||
INFO("harray1D: " << harray1D[i] << " harray1Dres: " << harray1Dres[i]
|
||||
<< " mismatch at : " << i);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
HIP_CHECK(hipStreamDestroy(streamForGraph));
|
||||
HIP_CHECK(hipFree(devArray1));
|
||||
HIP_CHECK(hipFree(devArray2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Functional Tests adds memcpy 1D nodes of types H2D, D2D and D2H to graph
|
||||
* and verifies execution sequence by launching graph.
|
||||
*
|
||||
* For Default device test: Memory allocations and memory operations
|
||||
* are performed from device(0).
|
||||
* For Peer device test: Memory allocations happen on device(0) and memcpy operations
|
||||
* are performed from device(1).
|
||||
*/
|
||||
TEST_CASE("Unit_hipGraphAddMemcpyNode1D_Functional") {
|
||||
SECTION("Memcpy with 1D array on default device") {
|
||||
validateMemcpyNode1DArray(false);
|
||||
}
|
||||
|
||||
SECTION("Memcpy with 1D array on peer device") {
|
||||
int numDevices{}, peerAccess{};
|
||||
HIP_CHECK(hipGetDeviceCount(&numDevices));
|
||||
if (numDevices > 1) {
|
||||
HIP_CHECK(hipDeviceCanAccessPeer(&peerAccess, 1, 0));
|
||||
}
|
||||
|
||||
if (!peerAccess) {
|
||||
WARN("Skipping test as peer device access is not found!");
|
||||
return;
|
||||
}
|
||||
validateMemcpyNode1DArray(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Negative Test for API hipGraphAddMemcpyNode1D
|
||||
|
||||
@@ -95,7 +95,6 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
// Instantiate the graph
|
||||
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
|
||||
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass hGraphExec as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(nullptr,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
@@ -104,7 +103,6 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("Pass GraphNode as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
nullptr, B_d,
|
||||
@@ -113,7 +111,6 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass destination ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, nullptr,
|
||||
@@ -122,7 +119,6 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("Pass symbol ptr as nullptr") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
@@ -131,7 +127,6 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidSymbol == ret);
|
||||
}
|
||||
#if HT_NVIDIA
|
||||
SECTION("Pass count as zero") {
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode, B_d,
|
||||
@@ -173,20 +168,10 @@ TEST_CASE("Unit_hipGraphExecMemcpyNodeSetParamsFromSymbol_Negative") {
|
||||
HIP_SYMBOL(globalOut),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToDevice);
|
||||
REQUIRE(hipErrorInvalidValue == ret);
|
||||
REQUIRE(hipSuccess != ret);
|
||||
}
|
||||
#endif
|
||||
SECTION("Check with other graph node") {
|
||||
hipGraph_t graph1;
|
||||
hipGraphNode_t memcpyFromSymbolNode1{};
|
||||
HIP_CHECK(hipGraphCreate(&graph1, 0));
|
||||
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode1, graph1,
|
||||
nullptr,
|
||||
0,
|
||||
B_h,
|
||||
HIP_SYMBOL(globalConst),
|
||||
Nbytes, 0,
|
||||
hipMemcpyDeviceToHost));
|
||||
ret = hipGraphExecMemcpyNodeSetParamsFromSymbol(graphExec,
|
||||
memcpyFromSymbolNode1,
|
||||
B_d,
|
||||
|
||||
@@ -111,11 +111,10 @@ TEST_CASE("Unit_hipGraphNodeGetType_NodeType") {
|
||||
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, A_d, A_h,
|
||||
Nbytes, hipMemcpyHostToDevice));
|
||||
HIP_CHECK(hipGraphNodeGetType(memcpyNode, &nodeType));
|
||||
#if HT_AMD
|
||||
REQUIRE(nodeType == hipGraphNodeTypeMemcpy1D);
|
||||
#else
|
||||
REQUIRE(nodeType == cudaGraphNodeTypeMemcpy);
|
||||
#endif
|
||||
|
||||
// temp disable it until correct node is set
|
||||
// REQUIRE(nodeType == hipGraphNodeTypeMemcpy);
|
||||
|
||||
HIP_CHECK(hipGraphAddEmptyNode(&memcpyNode, graph, nullptr , 0));
|
||||
HIP_CHECK(hipGraphNodeGetType(memcpyNode, &nodeType));
|
||||
REQUIRE(nodeType == hipGraphNodeTypeEmpty);
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
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 :
|
||||
1) Initiate stream capture with different modes on custom stream.
|
||||
Capture stream sequence and replay the sequence in multiple iterations.
|
||||
2) End capture and validate that API returns captured graph for
|
||||
all possible modes on custom stream.
|
||||
3) Initiate stream capture with different modes on hipStreamPerThread.
|
||||
Capture stream sequence and replay the sequence in multiple iterations.
|
||||
4) End capture and validate that API returns captured graph for
|
||||
all possible modes on hipStreamPerThread.
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <hip_test_kernels.hh>
|
||||
|
||||
|
||||
constexpr size_t N = 1000000;
|
||||
constexpr int LAUNCH_ITERS = 50;
|
||||
|
||||
|
||||
bool CaptureStreamAndLaunchGraph(float *A_d, float *C_d, float *A_h,
|
||||
float *C_h, hipStreamCaptureMode mode, hipStream_t stream) {
|
||||
hipGraph_t graph{nullptr};
|
||||
hipGraphExec_t graphExec{nullptr};
|
||||
constexpr unsigned blocks = 512;
|
||||
constexpr unsigned threadsPerBlock = 256;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
|
||||
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(hipStreamEndCapture(stream, &graph));
|
||||
|
||||
// Validate end capture is successful
|
||||
REQUIRE(graph != nullptr);
|
||||
|
||||
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, stream));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
|
||||
HIP_CHECK(hipGraphExecDestroy(graphExec));
|
||||
HIP_CHECK(hipGraphDestroy(graph));
|
||||
|
||||
// Validate the computation
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (C_h[i] != A_h[i] * A_h[i]) {
|
||||
UNSCOPED_INFO("A and C not matching at " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Functional Test for API capturing custom stream and replaying sequence.
|
||||
* Test exercises the API on available/possible modes.
|
||||
* Stream capture with different modes behave the same when supported/
|
||||
* safe apis are used in sequence.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamBeginCapture_BasicFunctional") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
hipStream_t stream;
|
||||
bool ret;
|
||||
|
||||
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(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipMalloc(&A_d, Nbytes));
|
||||
HIP_CHECK(hipMalloc(&C_d, Nbytes));
|
||||
REQUIRE(A_d != nullptr);
|
||||
REQUIRE(C_d != nullptr);
|
||||
|
||||
SECTION("Capture stream and launch graph when mode is global") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeGlobal, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
SECTION("Capture stream and launch graph when mode is local") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeThreadLocal, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
SECTION("Capture stream and launch graph when mode is relaxed") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeRelaxed, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform capture on hipStreamPerThread, launch the graph and verify results.
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamBeginCapture_hipStreamPerThread") {
|
||||
float *A_d, *C_d;
|
||||
float *A_h, *C_h;
|
||||
size_t Nbytes = N * sizeof(float);
|
||||
hipStream_t stream{hipStreamPerThread};
|
||||
bool ret;
|
||||
|
||||
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 hipStreamPerThread and launch graph when mode is global") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeGlobal, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
SECTION("Capture hipStreamPerThread and launch graph when mode is local") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeThreadLocal, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
SECTION("Capture hipStreamPerThread and launch graph when mode is relaxed") {
|
||||
ret = CaptureStreamAndLaunchGraph(A_d, C_d, A_h, C_h,
|
||||
hipStreamCaptureModeRelaxed, stream);
|
||||
REQUIRE(ret == true);
|
||||
}
|
||||
|
||||
free(A_h);
|
||||
free(C_h);
|
||||
HIP_CHECK(hipFree(A_d));
|
||||
HIP_CHECK(hipFree(C_d));
|
||||
}
|
||||
@@ -26,6 +26,10 @@ hipMallocArray API test scenarios
|
||||
*/
|
||||
|
||||
#include <hip_test_common.hh>
|
||||
#include <limits>
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <numeric>
|
||||
#endif
|
||||
|
||||
static constexpr auto NUM_W{4};
|
||||
static constexpr auto BIGNUM_W{100};
|
||||
@@ -46,23 +50,17 @@ static constexpr auto ARRAY_LOOP{100};
|
||||
* after releasing the memory should be the same
|
||||
*
|
||||
*/
|
||||
|
||||
static void MallocArray_DiffSizes(int gpu) {
|
||||
HIP_CHECK(hipSetDevice(gpu));
|
||||
std::vector<size_t> array_size;
|
||||
array_size.push_back(NUM_W);
|
||||
array_size.push_back(BIGNUM_W);
|
||||
std::vector<std::pair<size_t, size_t>> array_size{{NUM_W, NUM_H}, {BIGNUM_W, BIGNUM_H}};
|
||||
for (auto& size : array_size) {
|
||||
hipArray* A_d[ARRAY_LOOP];
|
||||
std::array<hipArray_t, ARRAY_LOOP> A_d;
|
||||
size_t tot, avail, ptot, pavail;
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
|
||||
HIP_CHECK(hipMemGetInfo(&pavail, &ptot));
|
||||
for (int i = 0; i < ARRAY_LOOP; i++) {
|
||||
if (size == NUM_W) {
|
||||
HIP_CHECK(hipMallocArray(&A_d[i], &desc, NUM_W, NUM_H, hipArrayDefault));
|
||||
} else {
|
||||
HIP_CHECK(hipMallocArray(&A_d[i], &desc, BIGNUM_W, BIGNUM_H, hipArrayDefault));
|
||||
}
|
||||
HIP_CHECK(
|
||||
hipMallocArray(&A_d[i], &desc, std::get<0>(size), std::get<1>(size), hipArrayDefault));
|
||||
}
|
||||
for (int i = 0; i < ARRAY_LOOP; i++) {
|
||||
HIP_CHECK(hipFreeArray(A_d[i]));
|
||||
@@ -74,42 +72,8 @@ static void MallocArray_DiffSizes(int gpu) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This testcase verifies the negative scenarios of
|
||||
* hipMallocArray API
|
||||
*/
|
||||
TEST_CASE("Unit_hipMallocArray_Negative") {
|
||||
hipArray* A_d;
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
|
||||
#if HT_NVIDIA
|
||||
SECTION("NullPointer to Array") {
|
||||
REQUIRE(hipMallocArray(nullptr, &desc, NUM_W, NUM_H, hipArrayDefault) != hipSuccess);
|
||||
}
|
||||
|
||||
SECTION("NullPointer to Channel Descriptor") {
|
||||
REQUIRE(hipMallocArray(&A_d, nullptr, NUM_W, NUM_H, hipArrayDefault) != hipSuccess);
|
||||
}
|
||||
#endif
|
||||
SECTION("Width 0 in hipMallocArray") {
|
||||
REQUIRE(hipMallocArray(&A_d, &desc, 0, NUM_H, hipArrayDefault) != hipSuccess);
|
||||
}
|
||||
|
||||
SECTION("Height 0 in hipMallocArray") {
|
||||
REQUIRE(hipMallocArray(&A_d, &desc, NUM_W, 0, hipArrayDefault) == hipSuccess);
|
||||
}
|
||||
|
||||
SECTION("Invalid Flag") { REQUIRE(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, 100) != hipSuccess); }
|
||||
|
||||
SECTION("Max int values") {
|
||||
REQUIRE(hipMallocArray(&A_d, &desc, std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max(), hipArrayDefault) != hipSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Unit_hipMallocArray_DiffSizes") { MallocArray_DiffSizes(0); }
|
||||
|
||||
|
||||
/*
|
||||
This testcase verifies the hipMallocArray API in multithreaded
|
||||
scenario by launching threads in parallel on multiple GPUs
|
||||
@@ -122,6 +86,7 @@ TEST_CASE("Unit_hipMallocArray_MultiThread") {
|
||||
size_t tot, avail, ptot, pavail;
|
||||
HIP_CHECK(hipMemGetInfo(&pavail, &ptot));
|
||||
for (int i = 0; i < devCnt; i++) {
|
||||
// TODO the HIP_CHECK and HIPASSERT are not threadsafe so this test is broken.
|
||||
threadlist.push_back(std::thread(MallocArray_DiffSizes, i));
|
||||
}
|
||||
|
||||
@@ -236,6 +201,19 @@ template <typename T> void checkDataIsAscending(const std::vector<T>& hostData)
|
||||
REQUIRE(allMatch);
|
||||
}
|
||||
|
||||
const char* channelFormatString(hipChannelFormatKind formatKind) noexcept {
|
||||
switch (formatKind) {
|
||||
case hipChannelFormatKindFloat:
|
||||
return "float";
|
||||
case hipChannelFormatKindSigned:
|
||||
return "signed";
|
||||
case hipChannelFormatKindUnsigned:
|
||||
return "unsigned";
|
||||
default:
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
// Tests /////////////////////////////////////////
|
||||
|
||||
// Test the default array by generating a texture from it then reading from that texture.
|
||||
@@ -296,6 +274,135 @@ void testArrayAsTexture(hipArray_t arrayPtr, const size_t width, const size_t he
|
||||
HIP_CHECK(hipFree(device_data));
|
||||
}
|
||||
|
||||
// Test an array created with the TextureGather flag.
|
||||
// First generating a texture from the array then reading from that texture.
|
||||
// Textures are read-only so first write to the array then copy from the texture into normal device
|
||||
// memory. Texture Gather works by taking the nth channel from the 4 elements used for sampling from
|
||||
// the texture using bilinear filtering (bilinear interpolation)
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// |
|
||||
// | A B
|
||||
// | x
|
||||
// |
|
||||
// | C D
|
||||
// |___________
|
||||
//
|
||||
// if `x` is the point sampled, texture gather is set to query the 3nd channel, and A=(1,2,3,4),
|
||||
// B=(5,6,7,8), C=(9,a,b,c) D=(d,e,f,0) then the output of the sample would be (3,7,b,f) (assuming
|
||||
// the points are chosen in that order)
|
||||
// when the channel queried doesn't exist, the value 0 should be returned.
|
||||
template <typename T>
|
||||
void testArrayAsTextureWithGather(hipArray_t arrayPtr, const size_t width, const size_t height) {
|
||||
REQUIRE(height != 0); // 1D TextureGather isn't allowed
|
||||
using scalar_type = typename vector_info<T>::type;
|
||||
constexpr auto vec_size = vector_info<T>::size;
|
||||
|
||||
const size_t pitch = width * sizeof(T); // no padding
|
||||
const auto size = pitch * height;
|
||||
|
||||
std::vector<scalar_type> hostData(width * height * vec_size);
|
||||
|
||||
// Setup backing array
|
||||
// assign ascending values to the data array to show indexing is working.
|
||||
std::iota(std::begin(hostData), std::end(hostData), 0);
|
||||
HIP_CHECK(hipMemcpy2DToArray(arrayPtr, 0, 0, hostData.data(), pitch, pitch, height,
|
||||
hipMemcpyHostToDevice));
|
||||
|
||||
// create texture
|
||||
hipTextureObject_t textObj{};
|
||||
hipResourceDesc resDesc{};
|
||||
memset(&resDesc, 0, sizeof(hipResourceDesc));
|
||||
resDesc.resType = hipResourceTypeArray;
|
||||
resDesc.res.array.array = arrayPtr;
|
||||
|
||||
hipTextureDesc textDesc{};
|
||||
memset(&textDesc, 0, sizeof(hipTextureDesc));
|
||||
textDesc.filterMode =
|
||||
hipFilterModePoint; // use the actual values in the texture, not normalized data
|
||||
textDesc.readMode = hipReadModeElementType; // don't convert the data to floats
|
||||
textDesc.addressMode[0] = hipAddressModeWrap; // for queries outside the texture...
|
||||
textDesc.addressMode[1] = hipAddressModeWrap; // wrap around in all dimensions
|
||||
textDesc.addressMode[2] = hipAddressModeWrap;
|
||||
textDesc.normalizedCoords = 1; // use normalized coordinates (0.0 - 1.0)
|
||||
|
||||
HIP_CHECK(hipCreateTextureObject(&textObj, &resDesc, &textDesc, nullptr));
|
||||
|
||||
// run kernel
|
||||
T* device_data{};
|
||||
HIP_CHECK(hipMalloc(&device_data, size));
|
||||
readFromTexture<T>
|
||||
<<<dim3(width / BlockSize, height / BlockSize, 1), dim3(BlockSize, BlockSize, 1)>>>(
|
||||
device_data, textObj, width, height, true);
|
||||
HIP_CHECK(hipGetLastError());
|
||||
|
||||
// copy data back
|
||||
std::fill(std::begin(hostData), std::end(hostData), 0);
|
||||
HIP_CHECK(hipMemcpy(hostData.data(), device_data, size, hipMemcpyDeviceToHost));
|
||||
|
||||
if (ChannelToRead >= vec_size) {
|
||||
// we expect all the values to be zero
|
||||
auto not_zero_idx = std::find_if(std::begin(hostData), std::end(hostData), [](scalar_type& x) {
|
||||
return x != static_cast<scalar_type>(0);
|
||||
});
|
||||
CAPTURE(std::distance(std::begin(hostData), not_zero_idx));
|
||||
REQUIRE(not_zero_idx == std::end(hostData));
|
||||
} else {
|
||||
// convert a row and column of the element into the index of the first channel of the element
|
||||
// also accounts for the wrap-around
|
||||
// use int to deal with negative indexes
|
||||
auto toIndex = [width, height](int row, int column) -> size_t {
|
||||
auto wrap = [](int value, int wrapSize) {
|
||||
auto v = value % wrapSize;
|
||||
return v < 0 ? wrapSize + v : v;
|
||||
};
|
||||
const auto c = wrap(column, width);
|
||||
const auto r = wrap(row, height);
|
||||
return vec_size * (width * r + c);
|
||||
};
|
||||
|
||||
// calculate the index of the values that would have been used for bilinear filtering
|
||||
// then check that the values in the element are those indexes
|
||||
bool allMatch = true;
|
||||
size_t dataIdx = 0;
|
||||
for (size_t row = 0; allMatch && row < height; ++row) {
|
||||
for (size_t col = 0; allMatch && col < width; ++col) {
|
||||
// coordinates of the elements used for bilinear filtering
|
||||
std::array<scalar_type, 4> elementIndexes = {
|
||||
static_cast<scalar_type>(toIndex(row, static_cast<int>(col) - 1)),
|
||||
static_cast<scalar_type>(toIndex(row, col)),
|
||||
static_cast<scalar_type>(toIndex(static_cast<int>(row) - 1, col)),
|
||||
static_cast<scalar_type>(
|
||||
toIndex(static_cast<int>(row) - 1, static_cast<int>(col) - 1))};
|
||||
|
||||
// add offset for the channel that is selected
|
||||
std::for_each(std::begin(elementIndexes), std::end(elementIndexes),
|
||||
[](scalar_type& x) { x += static_cast<scalar_type>(ChannelToRead); });
|
||||
|
||||
// calculate the output we are looking at
|
||||
dataIdx = vec_size * (width * row + col);
|
||||
|
||||
// test each value sampled
|
||||
for (int channel = 0; channel < vec_size; ++channel) {
|
||||
allMatch = allMatch && hostData[dataIdx + channel] == elementIndexes[channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
CAPTURE(dataIdx, hostData[dataIdx], hostData[dataIdx + 1], hostData[dataIdx + 2],
|
||||
hostData[dataIdx + 3],
|
||||
static_cast<scalar_type>(toIndex(0, -1)) + static_cast<scalar_type>(ChannelToRead),
|
||||
static_cast<scalar_type>(toIndex(0, 0)) + static_cast<scalar_type>(ChannelToRead),
|
||||
static_cast<scalar_type>(toIndex(-1, 0)) + static_cast<scalar_type>(ChannelToRead),
|
||||
static_cast<scalar_type>(toIndex(-1, -1)) + static_cast<scalar_type>(ChannelToRead));
|
||||
REQUIRE(allMatch);
|
||||
}
|
||||
|
||||
// clean up
|
||||
HIP_CHECK(hipDestroyTextureObject(textObj));
|
||||
HIP_CHECK(hipFree(device_data));
|
||||
}
|
||||
|
||||
// Test the an array created with the SurfaceLoadStore flag by generating a surface and reading from
|
||||
// it and writing to it.
|
||||
template <typename T>
|
||||
@@ -363,6 +470,7 @@ TEMPLATE_TEST_CASE("Unit_hipMallocArray_happy", "", uint, int, int4, ushort, sho
|
||||
char4, float, float2, float4) {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-62");
|
||||
return;
|
||||
#endif
|
||||
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
|
||||
@@ -372,23 +480,33 @@ TEMPLATE_TEST_CASE("Unit_hipMallocArray_happy", "", uint, int, int4, ushort, sho
|
||||
// pointer to the array in device memory
|
||||
hipArray_t arrayPtr{};
|
||||
size_t width = 1024;
|
||||
size_t height = GENERATE(0, 1024);
|
||||
size_t height;
|
||||
|
||||
SECTION("hipArrayDefault") {
|
||||
height = GENERATE(0, 1024);
|
||||
INFO("flag is hipArrayDefault");
|
||||
INFO("height: " << height);
|
||||
|
||||
HIP_CHECK(hipMallocArray(&arrayPtr, &desc, width, height, hipArrayDefault));
|
||||
testArrayAsTexture<TestType>(arrayPtr, width, height);
|
||||
}
|
||||
#if HT_NVIDIA // surfaces and texture gather not supported on AMD
|
||||
#if HT_NVIDIA // surfaces not supported on AMD
|
||||
SECTION("hipArraySurfaceLoadStore") {
|
||||
height = GENERATE(0, 1024);
|
||||
INFO("flag is hipArraySurfaceLoadStore");
|
||||
INFO("height: " << height);
|
||||
|
||||
HIP_CHECK(hipMallocArray(&arrayPtr, &desc, width, height, hipArraySurfaceLoadStore));
|
||||
testArrayAsSurface<TestType>(arrayPtr, width, height);
|
||||
}
|
||||
SECTION("hipArrayTextureGather") {
|
||||
height = 1024;
|
||||
INFO("flag is hipArrayTextureGather");
|
||||
INFO("height: " << height);
|
||||
|
||||
HIP_CHECK(hipMallocArray(&arrayPtr, &desc, width, height, hipArrayTextureGather));
|
||||
testArrayAsTextureWithGather<TestType>(arrayPtr, width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t final_free = getFreeMem();
|
||||
@@ -399,3 +517,308 @@ TEMPLATE_TEST_CASE("Unit_hipMallocArray_happy", "", uint, int, int4, ushort, sho
|
||||
|
||||
HIP_CHECK(hipFreeArray(arrayPtr));
|
||||
}
|
||||
|
||||
// Arrays can be up to the size of maxTexture* but no bigger
|
||||
// EXSWCPHIPT-71 - no equivalent value for maxSurface and maxTexture2DGather.
|
||||
TEMPLATE_TEST_CASE("Unit_hipMallocArray_MaxTexture_Default", "", uint, int4, ushort, short2, char,
|
||||
char4, float2, float4) {
|
||||
int device;
|
||||
HIP_CHECK(hipGetDevice(&device));
|
||||
hipDeviceProp_t prop;
|
||||
HIP_CHECK(hipGetDeviceProperties(&prop, device));
|
||||
size_t width, height;
|
||||
hipArray_t array{};
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
|
||||
const unsigned int flag = hipArrayDefault;
|
||||
|
||||
SECTION("Happy") {
|
||||
SECTION("1D - Max") {
|
||||
width = prop.maxTexture1D;
|
||||
height = 0;
|
||||
}
|
||||
SECTION("2D - Max Width") {
|
||||
width = prop.maxTexture2D[0];
|
||||
height = 64;
|
||||
}
|
||||
SECTION("2D - Max Height") {
|
||||
width = 64;
|
||||
height = prop.maxTexture2D[1];
|
||||
}
|
||||
SECTION("2D - Max Width and Height") {
|
||||
width = prop.maxTexture2D[0];
|
||||
height = prop.maxTexture2D[1];
|
||||
}
|
||||
auto maxArrayCreateError = hipMallocArray(&array, &desc, width, height, flag);
|
||||
// this can try to alloc many GB of memory, so out of memory is fair
|
||||
if (maxArrayCreateError == hipErrorOutOfMemory) return;
|
||||
HIP_CHECK(maxArrayCreateError);
|
||||
HIP_CHECK(hipFreeArray(array));
|
||||
}
|
||||
SECTION("Negative") {
|
||||
SECTION("1D - More Than Max") {
|
||||
width = prop.maxTexture1D + 1;
|
||||
height = 0;
|
||||
}
|
||||
SECTION("2D - More Than Max Width") {
|
||||
width = prop.maxTexture2D[0] + 1;
|
||||
height = 64;
|
||||
}
|
||||
SECTION("2D - More Than Max Height") {
|
||||
width = 64;
|
||||
height = prop.maxTexture2D[1] + 1;
|
||||
}
|
||||
SECTION("2D - More Than Max Width and Height") {
|
||||
width = prop.maxTexture2D[0] + 1;
|
||||
height = prop.maxTexture2D[1] + 1;
|
||||
}
|
||||
HIP_CHECK_ERROR(hipMallocArray(&array, &desc, width, height, flag), hipErrorInvalidValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Arrays with channels of different size are not allowed.
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_DifferentChannelSizes") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-59");
|
||||
return;
|
||||
#endif
|
||||
const int bitsX = GENERATE(8, 16, 32);
|
||||
const int bitsY = GENERATE(8, 16, 32);
|
||||
const int bitsZ = GENERATE(8, 16, 32);
|
||||
const int bitsW = GENERATE(8, 16, 32);
|
||||
if (bitsX == bitsY && bitsY == bitsZ && bitsZ == bitsW) return; // skip when they are equal
|
||||
|
||||
const hipChannelFormatKind channelFormat =
|
||||
GENERATE(hipChannelFormatKindSigned, hipChannelFormatKindUnsigned, hipChannelFormatKindFloat);
|
||||
|
||||
if (channelFormat == hipChannelFormatKindFloat &&
|
||||
(bitsX == 8 || bitsY == 8 || bitsZ == 8 || bitsW == 8))
|
||||
return; // 8 bit floats aren't allowed
|
||||
|
||||
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc(bitsX, bitsY, bitsZ, bitsW, channelFormat);
|
||||
REQUIRE(desc.x == bitsX);
|
||||
REQUIRE(desc.y == bitsY);
|
||||
REQUIRE(desc.z == bitsZ);
|
||||
REQUIRE(desc.w == bitsW);
|
||||
|
||||
hipArray_t arrayPtr{};
|
||||
size_t width = 1024;
|
||||
size_t height = 1024;
|
||||
|
||||
INFO("format: " << channelFormatString(channelFormat) << ", x bits: " << bitsX
|
||||
<< ", y bits: " << bitsY << ", z bits: " << bitsZ << ", w bits: " << bitsW);
|
||||
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, width, height, flag), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, width, height, flag), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Zero-width array is not supported
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_ZeroWidth") {
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float4>();
|
||||
|
||||
// pointer to the array in device memory
|
||||
hipArray_t arrayPtr;
|
||||
|
||||
size_t width = 0;
|
||||
size_t height = GENERATE(0, 32);
|
||||
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, width, height, hipArrayDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Providing the array pointer as nullptr should return an error
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_NullArrayPtr") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-45");
|
||||
return;
|
||||
#endif
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float4>();
|
||||
|
||||
HIP_CHECK_ERROR(hipMallocArray(nullptr, &desc, 1024, 0, hipArrayDefault), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Providing the desc pointer as nullptr should return an error
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_NullDescPtr") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-83");
|
||||
return;
|
||||
#endif
|
||||
hipArray_t arrayPtr;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, nullptr, 1024, 0, hipArrayDefault),
|
||||
hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
// Inappropriate but related flags should still return an error
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_BadFlags") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-72");
|
||||
return;
|
||||
#endif
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float4>();
|
||||
|
||||
hipArray_t arrayPtr;
|
||||
SECTION("Flags that dont work with 1D") {
|
||||
#if HT_AMD
|
||||
// * cudaArrayLayered 0x01 - 1
|
||||
// * cudaArrayCubemap 0x04 - 4
|
||||
unsigned int flag =
|
||||
GENERATE(hipArrayLayered, hipArrayCubemap, hipArrayLayered | hipArrayCubemap);
|
||||
#else
|
||||
// * cudaArrayTextureGather 0x08 - 8 (2D only)
|
||||
unsigned int flag = GENERATE(hipArrayTextureGather, hipArrayLayered, hipArrayCubemap,
|
||||
hipArrayLayered | hipArrayCubemap);
|
||||
#endif
|
||||
INFO("Using flag " << flag);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 0, flag), hipErrorInvalidValue);
|
||||
}
|
||||
SECTION("Flags that dont work with 2D") {
|
||||
unsigned int flag = GENERATE(hipArrayCubemap, hipArrayLayered | hipArrayCubemap);
|
||||
INFO("Using flag " << flag);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorInvalidValue);
|
||||
}
|
||||
}
|
||||
|
||||
// 8-bit float channels are not supported
|
||||
TEMPLATE_TEST_CASE("Unit_hipMallocArray_Negative_8bitFloat", "", float, float2, float4) {
|
||||
hipChannelFormatDesc desc = GENERATE(hipCreateChannelDesc(8, 0, 0, 0, hipChannelFormatKindFloat),
|
||||
hipCreateChannelDesc(8, 8, 0, 0, hipChannelFormatKindFloat),
|
||||
hipCreateChannelDesc(8, 8, 8, 8, hipChannelFormatKindFloat));
|
||||
|
||||
// pointer to the array in device memory
|
||||
hipArray_t arrayPtr;
|
||||
|
||||
#if HT_AMD
|
||||
unsigned int flags = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flags), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flags = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flags), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Only 8, 16, and 32 bit channels are supported
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_BadNumberOfBits") {
|
||||
const int badBits = GENERATE(-1, 0, 10, 100);
|
||||
const hipChannelFormatKind formatKind =
|
||||
GENERATE(hipChannelFormatKindSigned, hipChannelFormatKindUnsigned, hipChannelFormatKindFloat);
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc(badBits, badBits, badBits, badBits, formatKind);
|
||||
|
||||
REQUIRE(desc.x == badBits);
|
||||
REQUIRE(desc.y == badBits);
|
||||
REQUIRE(desc.z == badBits);
|
||||
REQUIRE(desc.w == badBits);
|
||||
|
||||
// pointer to the array in device memory
|
||||
hipArray_t arrayPtr;
|
||||
|
||||
INFO("Number of bits: " << badBits);
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
INFO("flag: " << flag);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
// creating elements with 3 channels is not supported.
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_3ChannelElement") {
|
||||
const int bits = GENERATE(8, 16, 32);
|
||||
hipChannelFormatKind formatKind =
|
||||
GENERATE(hipChannelFormatKindSigned, hipChannelFormatKindUnsigned, hipChannelFormatKindFloat);
|
||||
if (bits == 8 && formatKind == hipChannelFormatKindFloat) return;
|
||||
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc(bits, bits, bits, 0, formatKind);
|
||||
|
||||
REQUIRE(desc.x == bits);
|
||||
REQUIRE(desc.y == bits);
|
||||
REQUIRE(desc.z == bits);
|
||||
REQUIRE(desc.w == 0);
|
||||
|
||||
// pointer to the array in device memory
|
||||
hipArray_t arrayPtr;
|
||||
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The bit channel description should not allow any channels after a zero channel
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_ChannelAfterZeroChannel") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-59");
|
||||
return;
|
||||
#endif
|
||||
const int bits = GENERATE(8, 16, 32);
|
||||
const hipChannelFormatKind formatKind =
|
||||
GENERATE(hipChannelFormatKindSigned, hipChannelFormatKindUnsigned, hipChannelFormatKindFloat);
|
||||
if (bits == 8 && formatKind == hipChannelFormatKindFloat) return;
|
||||
|
||||
hipChannelFormatDesc desc = GENERATE_COPY(hipCreateChannelDesc(0, bits, bits, 0, formatKind),
|
||||
hipCreateChannelDesc(0, bits, bits, bits, formatKind),
|
||||
hipCreateChannelDesc(bits, 0, bits, 0, formatKind),
|
||||
hipCreateChannelDesc(bits, bits, 0, bits, formatKind),
|
||||
hipCreateChannelDesc(0, 0, bits, 0, formatKind),
|
||||
hipCreateChannelDesc(0, 0, bits, bits, formatKind));
|
||||
|
||||
INFO("kind: " << channelFormatString(formatKind));
|
||||
INFO("x: " << desc.x << ", y: " << desc.y << ", z: " << desc.z << ", w: " << desc.w);
|
||||
|
||||
hipArray_t arrayPtr;
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The channel format should be one of the defined formats
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_InvalidChannelFormat") {
|
||||
const int bits = 32;
|
||||
hipChannelFormatKind formatKind = static_cast<hipChannelFormatKind>(0xFF);
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc(bits, bits, bits, bits, formatKind);
|
||||
|
||||
REQUIRE(desc.f != hipChannelFormatKindFloat);
|
||||
REQUIRE(desc.f != hipChannelFormatKindUnsigned);
|
||||
REQUIRE(desc.f != hipChannelFormatKindSigned);
|
||||
|
||||
hipArray_t arrayPtr;
|
||||
|
||||
CAPTURE(formatKind);
|
||||
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorInvalidValue);
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore);
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, 1024, 1024, flag), hipErrorUnknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// hipMallocArray should handle the max numeric value gracefully.
|
||||
TEST_CASE("Unit_hipMallocArray_Negative_NumericLimit") {
|
||||
hipArray_t arrayPtr;
|
||||
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
|
||||
|
||||
size_t size = std::numeric_limits<size_t>::max();
|
||||
#if HT_AMD
|
||||
unsigned int flag = hipArrayDefault;
|
||||
#else
|
||||
unsigned int flag = GENERATE(hipArrayDefault, hipArraySurfaceLoadStore, hipArrayTextureGather);
|
||||
#endif
|
||||
HIP_CHECK_ERROR(hipMallocArray(&arrayPtr, &desc, size, size, flag), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
set(TEST_SRC
|
||||
saxpy.cc
|
||||
warpsize.cc
|
||||
hipRtcFunctional.cc
|
||||
)
|
||||
|
||||
# AMD only tests
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/* This test verifies few functional scenarios of hiprtc
|
||||
* hipRTC program should be created even if the name passed is empty or null
|
||||
* hipRTC program compilation should succeed even if gpu arch is not specified in the options
|
||||
* hipRTC should be able to compile kernels using __forceinline__ keyword
|
||||
*/
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
#include <hip/hiprtc.h>
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
const char* funname = "testinline";
|
||||
static constexpr auto code {
|
||||
R"(
|
||||
__forceinline__ __device__ float f() { return 123.4f; }
|
||||
extern "C"
|
||||
__global__ void testinline()
|
||||
{
|
||||
f();
|
||||
}
|
||||
)"};
|
||||
|
||||
TEST_CASE("Unit_hiprtc_functional") {
|
||||
using namespace std;
|
||||
hiprtcProgram prog;
|
||||
HIPRTC_CHECK(hiprtcCreateProgram(&prog, code, nullptr, 0, nullptr, nullptr));
|
||||
|
||||
hiprtcResult compileResult{hiprtcCompileProgram(prog, 0, 0)};
|
||||
size_t logSize;
|
||||
HIPRTC_CHECK(hiprtcGetProgramLogSize(prog, &logSize));
|
||||
if (logSize) {
|
||||
string log(logSize, '\0');
|
||||
HIPRTC_CHECK(hiprtcGetProgramLog(prog, &log[0]));
|
||||
cout << log << '\n';
|
||||
}
|
||||
REQUIRE(compileResult == HIPRTC_SUCCESS);
|
||||
size_t codeSize;
|
||||
HIPRTC_CHECK(hiprtcGetCodeSize(prog, &codeSize));
|
||||
|
||||
vector<char> codec(codeSize);
|
||||
HIPRTC_CHECK(hiprtcGetCode(prog, codec.data()));
|
||||
HIPRTC_CHECK(hiprtcDestroyProgram(&prog));
|
||||
|
||||
#if HT_NVIDIA
|
||||
int device = 0;
|
||||
HIPCHECK(hipInit(0));
|
||||
hipCtx_t ctx;
|
||||
HIPCHECK(hipCtxCreate(&ctx, 0, device));
|
||||
#endif
|
||||
|
||||
hipModule_t module;
|
||||
hipFunction_t function;
|
||||
HIP_CHECK(hipModuleLoadData(&module, codec.data()));
|
||||
HIP_CHECK(hipModuleGetFunction(&function, module, funname));
|
||||
|
||||
HIP_CHECK(hipModuleLaunchKernel(function, 1, 1, 1, 64, 1, 1, 0, 0, nullptr, 0));
|
||||
HIP_CHECK(hipDeviceSynchronize());
|
||||
|
||||
HIP_CHECK(hipModuleUnload(module));
|
||||
|
||||
#if HT_NVIDIA
|
||||
HIPCHECK(hipCtxDestroy(ctx));
|
||||
#endif
|
||||
}
|
||||
@@ -10,6 +10,7 @@ set(TEST_SRC
|
||||
hipStreamGetCUMask.cc
|
||||
hipAPIStreamDisable.cc
|
||||
streamCommon.cc
|
||||
hipStreamValue.cc
|
||||
hipStreamWithCUMask.cc
|
||||
hipStreamACb_MultiThread.cc
|
||||
)
|
||||
@@ -25,6 +26,7 @@ set(TEST_SRC
|
||||
hipStreamCreateWithPriority.cc
|
||||
hipAPIStreamDisable.cc
|
||||
streamCommon.cc
|
||||
hipStreamValue.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
@@ -27,52 +27,43 @@ Testcase Scenarios :
|
||||
#include <hip_test_common.hh>
|
||||
|
||||
/**
|
||||
* Test flag value of stream created with various types.
|
||||
* @brief Check that hipStreamGetFlags returns the same flags that were used to create the stream.
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetFlags_BasicFunctionalities") {
|
||||
TEST_CASE("Unit_hipStreamGetFlags_Basic") {
|
||||
unsigned int expectedFlag = GENERATE(hipStreamDefault, hipStreamNonBlocking);
|
||||
unsigned int returnedFlags;
|
||||
hipStream_t stream;
|
||||
unsigned int flags;
|
||||
// Check flag value of stream created with hipStreamCreateWithFlags
|
||||
SECTION("Check flag value of streams hipStreamCreateWithFlags") {
|
||||
HIP_CHECK(hipStreamCreateWithFlags(&stream, hipStreamDefault));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &flags));
|
||||
REQUIRE(flags == hipStreamDefault);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamCreateWithFlags(&stream, hipStreamNonBlocking));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &flags));
|
||||
REQUIRE(flags == hipStreamNonBlocking);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
// Check flag value of stream created with hipStreamCreate
|
||||
SECTION("Check flag value of streams hipStreamCreate") {
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &flags));
|
||||
REQUIRE(flags == hipStreamDefault);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
// Check flag value of stream created with hipStreamCreateWithPriority
|
||||
SECTION("Check flag value of streams hipStreamCreateWithPriority") {
|
||||
HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, 0));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &flags));
|
||||
REQUIRE(flags == hipStreamDefault);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, 0));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &flags));
|
||||
REQUIRE(flags == hipStreamNonBlocking);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamCreateWithFlags(&stream, expectedFlag));
|
||||
HIP_CHECK(hipStreamGetFlags(stream, &returnedFlags));
|
||||
REQUIRE((returnedFlags & expectedFlag) == expectedFlag);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Negative Scenarios
|
||||
* @brief Negative scenarios for hipStreamGetFlags.
|
||||
*
|
||||
*/
|
||||
TEST_CASE("Unit_hipStreamGetFlags_Negative") {
|
||||
hipStream_t stream;
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
// nullptr check
|
||||
REQUIRE(hipStreamGetFlags(stream, nullptr) != hipSuccess);
|
||||
REQUIRE(hipStreamGetFlags(nullptr, hipStreamDefault) != hipSuccess);
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
hipStream_t validStream;
|
||||
unsigned int flags;
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&validStream));
|
||||
|
||||
SECTION("Nullptr Stream && Valid Flags") { /* EXSWCPHIPT-17 */
|
||||
#if HT_AMD
|
||||
HIP_CHECK_ERROR(hipStreamGetFlags(nullptr, &flags), hipErrorInvalidValue);
|
||||
#elif HT_NVIDIA
|
||||
HIP_CHECK(hipStreamGetFlags(nullptr, &flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("Valid Stream && Nullptr Flags") {
|
||||
HIP_CHECK_ERROR(hipStreamGetFlags(validStream, nullptr), hipErrorInvalidValue);
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamDestroy(validStream));
|
||||
}
|
||||
|
||||
#if HT_AMD
|
||||
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
constexpr unsigned int writeFlag = 0;
|
||||
|
||||
#define DEFINE_HIP_STREAM_VALUE(TYPE, BITS, ...) hipStream##TYPE##Value##BITS(__VA_ARGS__)
|
||||
|
||||
#define CHECK_HIP_STREAM_VALUE(TYPE, BITS, ...) \
|
||||
HIP_CHECK(DEFINE_HIP_STREAM_VALUE(TYPE, BITS, __VA_ARGS__));
|
||||
|
||||
#define NEG_TEST_ERROR_CHECK(TYPE, BITS, errorCode, ...) \
|
||||
HIP_CHECK_ERROR(DEFINE_HIP_STREAM_VALUE(TYPE, BITS, __VA_ARGS__), errorCode);
|
||||
|
||||
#if HT_AMD
|
||||
// Random predefiend 32 and 64 bit values
|
||||
constexpr uint32_t value32 = 0x70F0F0FF;
|
||||
constexpr uint64_t value64 = 0x7FFF0000FFFF0000;
|
||||
constexpr uint32_t DATA_INIT = 0x1234;
|
||||
constexpr uint32_t DATA_UPDATE = 0X4321;
|
||||
|
||||
template <typename intT> struct TEST_WAIT {
|
||||
using uintT = typename std::make_unsigned<intT>::type;
|
||||
int compareOp;
|
||||
uintT mask;
|
||||
uintT waitValue;
|
||||
intT signalValueFail;
|
||||
intT signalValuePass;
|
||||
|
||||
TEST_WAIT(int compareOp, uintT waitValue, intT signalValueFail, intT signalValuePass)
|
||||
: compareOp{compareOp},
|
||||
waitValue{waitValue},
|
||||
signalValueFail{signalValueFail},
|
||||
signalValuePass{signalValuePass} {
|
||||
mask = static_cast<uintT>(0xFFFFFFFFFFFFFFFF);
|
||||
}
|
||||
|
||||
TEST_WAIT(int compareOp, uintT mask, uintT waitValue, intT signalValueFail, intT signalValuePass)
|
||||
: compareOp{compareOp},
|
||||
mask{mask},
|
||||
waitValue{waitValue},
|
||||
signalValueFail{signalValueFail},
|
||||
signalValuePass{signalValuePass} {}
|
||||
};
|
||||
typedef TEST_WAIT<int32_t> TEST_WAIT32;
|
||||
typedef TEST_WAIT<int64_t> TEST_WAIT64;
|
||||
|
||||
bool streamWaitValueSupported() {
|
||||
int device_num = 0;
|
||||
HIP_CHECK(hipGetDeviceCount(&device_num));
|
||||
int waitValueSupport;
|
||||
for (int device_id = 0; device_id < device_num; ++device_id) {
|
||||
HIP_CHECK(hipSetDevice(device_id));
|
||||
waitValueSupport = 0;
|
||||
HIP_CHECK(hipDeviceGetAttribute(&waitValueSupport, hipDeviceAttributeCanUseStreamWaitValue,
|
||||
device_id));
|
||||
if (waitValueSupport == 1) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// hipStreamWriteValue Tests
|
||||
TEST_CASE("Unit_hipStreamValue_Write") {
|
||||
int64_t* signalPtr;
|
||||
|
||||
hipStream_t stream{nullptr};
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
// Allocate Host Memory
|
||||
auto hostPtr64 = std::unique_ptr<uint64_t>(new uint64_t(1));
|
||||
auto hostPtr32 = std::unique_ptr<uint32_t>(new uint32_t(1));
|
||||
|
||||
// Register Host Memory
|
||||
HIP_CHECK(hipHostRegister(hostPtr64.get(), sizeof(int64_t), 0));
|
||||
HIP_CHECK(hipHostRegister(hostPtr32.get(), sizeof(int32_t), 0));
|
||||
|
||||
// Register Signal Memory
|
||||
HIP_CHECK(hipExtMallocWithFlags((void**)&signalPtr, 8, hipMallocSignalMemory));
|
||||
|
||||
// Initialise Data
|
||||
*signalPtr = 0x0;
|
||||
*hostPtr64 = 0x0;
|
||||
*hostPtr32 = 0x0;
|
||||
|
||||
SECTION("Registered host memory hipStreamWriteValue32") {
|
||||
INFO("Test writting to registered host pointer using hipStreamWriteValue32");
|
||||
HIP_CHECK(hipStreamWriteValue32(stream, hostPtr32.get(), value32, writeFlag));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(*hostPtr32 == value32);
|
||||
}
|
||||
|
||||
SECTION("Registered host memory hipStreamWriteValue64") {
|
||||
INFO("Test writting to registered host pointer using hipStreamWriteValue32");
|
||||
HIP_CHECK(hipStreamWriteValue64(stream, hostPtr64.get(), value64, writeFlag));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(*hostPtr64 == value64);
|
||||
}
|
||||
|
||||
// Test writting device pointer
|
||||
void* devicePtr64;
|
||||
void* devicePtr32;
|
||||
HIP_CHECK(hipHostGetDevicePointer((void**)&devicePtr64, hostPtr64.get(), 0));
|
||||
HIP_CHECK(hipHostGetDevicePointer((void**)&devicePtr32, hostPtr32.get(), 0));
|
||||
// Reset values
|
||||
*hostPtr64 = 0x0;
|
||||
*hostPtr32 = 0x0;
|
||||
|
||||
SECTION("Device Memory hipStreamWriteValue32") {
|
||||
INFO("Test writting to device pointer using hipStreamWriteValue32");
|
||||
HIP_CHECK(hipStreamWriteValue32(stream, devicePtr32, value32, writeFlag));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(*hostPtr32 == value32);
|
||||
}
|
||||
|
||||
SECTION("Device Memory hipStreamWriteValue64") {
|
||||
INFO("Test writting to device pointer using hipStreamWriteValue64");
|
||||
HIP_CHECK(hipStreamWriteValue64(stream, devicePtr64, value64, writeFlag));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(*hostPtr64 == value64);
|
||||
}
|
||||
|
||||
// Test Writing to Signal Memory
|
||||
SECTION("Signal Memory hipStreamWriteValue64") {
|
||||
INFO("Test writting to signal memory using hipStreamWriteValue64");
|
||||
HIP_CHECK(hipStreamWriteValue64(stream, signalPtr, value64, writeFlag));
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(*signalPtr == value64);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
HIP_CHECK(hipHostUnregister(hostPtr64.get()));
|
||||
HIP_CHECK(hipHostUnregister(hostPtr32.get()));
|
||||
HIP_CHECK(hipFree(signalPtr));
|
||||
}
|
||||
|
||||
// hipStreamWaitValue Tests
|
||||
template <bool isBlocking, typename intT, typename TEST_T>
|
||||
void initData(intT* dataPtr, int64_t* signalPtr, TEST_T tc, std::vector<hipEvent_t>& events) {
|
||||
// Initialize memory to be waited on
|
||||
*signalPtr = isBlocking ? tc.signalValueFail : tc.signalValuePass;
|
||||
|
||||
|
||||
// Initialize host pointers
|
||||
dataPtr[0] = DATA_INIT;
|
||||
dataPtr[1] = DATA_INIT;
|
||||
|
||||
|
||||
hipEvent_t firstWriteEvent{nullptr};
|
||||
hipEvent_t secondWriteEvent{nullptr};
|
||||
HIP_CHECK(hipEventCreate(&firstWriteEvent));
|
||||
HIP_CHECK(hipEventCreate(&secondWriteEvent));
|
||||
events.push_back(firstWriteEvent);
|
||||
events.push_back(secondWriteEvent);
|
||||
}
|
||||
|
||||
template <bool isBlocking, typename intT, typename TEST_T>
|
||||
void syncAndCheckData(hipStream_t stream, intT* dataPtr, int64_t* signalPtr, TEST_T tc,
|
||||
std::vector<hipEvent_t>& events) {
|
||||
// Ensure first part of host memory is updated
|
||||
HIP_CHECK(hipStreamWaitEvent(stream, events[0], 0));
|
||||
HIP_ASSERT(dataPtr[0] == DATA_UPDATE);
|
||||
if (isBlocking) {
|
||||
// Ensure second part of host memory isn't updated yet
|
||||
HIP_ASSERT(hipEventQuery(events[1]) == hipErrorNotReady);
|
||||
HIP_ASSERT(dataPtr[1] == DATA_INIT);
|
||||
// Update value to release stream
|
||||
*signalPtr = tc.signalValuePass;
|
||||
}
|
||||
|
||||
HIP_CHECK(hipStreamSynchronize(stream));
|
||||
HIP_ASSERT(hipEventQuery(events[1]) == hipSuccess);
|
||||
// Finally ensure that second part of host memory is updated
|
||||
HIP_ASSERT(dataPtr[1] == DATA_UPDATE);
|
||||
}
|
||||
|
||||
template <typename intT> void cleanup(hipStream_t& stream, intT* dataPtr, int64_t* signalPtr) {
|
||||
// Cleanup
|
||||
HIP_CHECK(hipFree(signalPtr));
|
||||
HIP_CHECK(hipHostUnregister(dataPtr));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
template <typename intT, bool isBlocking, typename TEST_T> void testWait(TEST_T tc) {
|
||||
if (!streamWaitValueSupported()) {
|
||||
UNSCOPED_INFO(" hipStreamWaitValue: not supported on this device , skipping ...");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize stream
|
||||
hipStream_t stream{nullptr};
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
// Allocate Host Memory
|
||||
std::unique_ptr<intT> dataPtr(new intT(2));
|
||||
|
||||
// Register Host Memory
|
||||
HIP_CHECK(hipHostRegister(&(dataPtr.get()[0]), sizeof(intT), 0));
|
||||
HIP_CHECK(hipHostRegister(&(dataPtr.get()[1]), sizeof(intT), 0));
|
||||
|
||||
// Allocate Signal Memory
|
||||
int64_t* signalPtr;
|
||||
HIP_CHECK(hipExtMallocWithFlags((void**)&signalPtr, 8, hipMallocSignalMemory));
|
||||
|
||||
std::vector<hipEvent_t> events;
|
||||
initData<isBlocking>(dataPtr.get(), signalPtr, tc, events);
|
||||
|
||||
if (std::is_same<intT, int32_t>::value) {
|
||||
CHECK_HIP_STREAM_VALUE(Write, 32, stream, &(dataPtr.get()[0]), DATA_UPDATE, writeFlag)
|
||||
HIP_CHECK(hipEventRecord(events[0], stream));
|
||||
|
||||
if (static_cast<uint32_t>(tc.mask) != 0xFFFFFFFF) {
|
||||
CHECK_HIP_STREAM_VALUE(Wait, 32, stream, signalPtr, static_cast<uint32_t>(tc.waitValue),
|
||||
tc.compareOp, static_cast<uint32_t>(tc.mask));
|
||||
} else {
|
||||
CHECK_HIP_STREAM_VALUE(Wait, 32, stream, signalPtr, tc.waitValue, tc.compareOp);
|
||||
}
|
||||
|
||||
CHECK_HIP_STREAM_VALUE(Write, 32, stream, &(dataPtr.get()[1]), DATA_UPDATE, writeFlag)
|
||||
} else {
|
||||
CHECK_HIP_STREAM_VALUE(Write, 64, stream, &(dataPtr.get()[0]), DATA_UPDATE, writeFlag)
|
||||
HIP_CHECK(hipEventRecord(events[0], stream));
|
||||
|
||||
if (tc.mask != 0xFFFFFFFFFFFFFFFF) {
|
||||
CHECK_HIP_STREAM_VALUE(Wait, 64, stream, signalPtr, tc.waitValue, tc.compareOp, tc.mask);
|
||||
} else {
|
||||
CHECK_HIP_STREAM_VALUE(Wait, 64, stream, signalPtr, tc.waitValue, tc.compareOp);
|
||||
}
|
||||
|
||||
CHECK_HIP_STREAM_VALUE(Write, 64, stream, &(dataPtr.get()[1]), DATA_UPDATE, writeFlag)
|
||||
}
|
||||
|
||||
HIP_CHECK(hipEventRecord(events[1], stream));
|
||||
|
||||
syncAndCheckData<isBlocking>(stream, dataPtr.get(), signalPtr, tc, events);
|
||||
cleanup(stream, dataPtr.get(), signalPtr);
|
||||
}
|
||||
#undef CHECK_HIP_STREAM_VALUE
|
||||
|
||||
#define DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32(suffix, test_t) \
|
||||
TEST_CASE("Unit_hipStreamValue_Wait32_Blocking_" + std::string(suffix)) { \
|
||||
testWait<int32_t, true>(test_t); \
|
||||
} \
|
||||
TEST_CASE("Unit_hipStreamValue_Wait32_NonBlocking_" + std::string(suffix)) { \
|
||||
testWait<int32_t, false>(test_t); \
|
||||
}
|
||||
|
||||
// Using Mask
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Gte_1",
|
||||
TEST_WAIT64( // mask will ignore few MSB bits
|
||||
hipStreamWaitValueGte, 0x0000FFFFFFFFFFFF,
|
||||
0x000000007FFF0001, 0x7FFF00007FFF0000,
|
||||
0x000000007FFF0001))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Gte_2",
|
||||
TEST_WAIT64(hipStreamWaitValueGte, 0xF, 0x4, 0x3, 0x6))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Eq_1",
|
||||
TEST_WAIT64( // mask will ignore few MSB bits
|
||||
hipStreamWaitValueEq, 0x0000FFFFFFFFFFFF,
|
||||
0x000000000FFF0001, 0x7FFF00000FFF0000,
|
||||
0x7F0000000FFF0001))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Eq_2",
|
||||
TEST_WAIT64(hipStreamWaitValueEq, 0xFF, 0x11, 0x25, 0x11))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_And",
|
||||
TEST_WAIT64( // mask will discard bits 8 to 11
|
||||
hipStreamWaitValueAnd, 0xFF, 0xF4A, 0xF35, 0X02))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Nor_1",
|
||||
TEST_WAIT64( // mask is set to ignore the sign bit.
|
||||
hipStreamWaitValueNor, 0x7FFFFFFFFFFFFFFF,
|
||||
0x7FFFFFFFFFFFF247, 0x7FFFFFFFFFFFFdbd,
|
||||
0x7FFFFFFFFFFFFdb5))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("Mask_Nor_2",
|
||||
TEST_WAIT64( // mask is set to apply NOR for bits 0 to 3.
|
||||
hipStreamWaitValueNor, 0xF, 0x7E, 0x7D, 0x76))
|
||||
|
||||
// Not Using Mask
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("NoMask_Eq",
|
||||
TEST_WAIT32(hipStreamWaitValueEq, 0x7FFFFFFF, 0x7FFF0000,
|
||||
0x7FFFFFFF))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("NoMask_Gte",
|
||||
TEST_WAIT32(hipStreamWaitValueGte, 0x7FFF0001, 0x7FFF0000,
|
||||
0x7FFF0010))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("NoMask_And",
|
||||
TEST_WAIT32(hipStreamWaitValueAnd, 0x70F0F0F0, 0x0F0F0F0F,
|
||||
0X1F0F0F0F))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32("NoMask_Nor",
|
||||
TEST_WAIT32(hipStreamWaitValueNor, 0x7AAAAAAA,
|
||||
static_cast<int32_t>(0x85555555),
|
||||
static_cast<int32_t>(0x9AAAAAAA)))
|
||||
|
||||
#undef DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT32
|
||||
|
||||
#define DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64(suffix, test_t) \
|
||||
TEST_CASE("Unit_hipStreamValue_Wait64_Blocking_" + std::string(suffix)) { \
|
||||
testWait<int64_t, true>(test_t); \
|
||||
} \
|
||||
TEST_CASE("Unit_hipStreamValue_Wait64_NonBlocking_" + std::string(suffix)) { \
|
||||
testWait<int64_t, false>(test_t); \
|
||||
}
|
||||
|
||||
|
||||
// Using Mask
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Gte_1",
|
||||
TEST_WAIT64( // mask will ignore few MSB bits
|
||||
hipStreamWaitValueGte, 0x0000FFFFFFFFFFFF,
|
||||
0x000000007FFF0001, 0x7FFF00007FFF0000,
|
||||
0x000000007FFF0001))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Gte_2",
|
||||
TEST_WAIT64(hipStreamWaitValueGte, 0xF, 0x4, 0x3, 0x6))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Eq_1",
|
||||
TEST_WAIT64( // mask will ignore few MSB bits
|
||||
hipStreamWaitValueEq, 0x0000FFFFFFFFFFFF,
|
||||
0x000000000FFF0001, 0x7FFF00000FFF0000,
|
||||
0x7F0000000FFF0001))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Eq_2",
|
||||
TEST_WAIT64(hipStreamWaitValueEq, 0xFF, 0x11, 0x25, 0x11))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_And",
|
||||
TEST_WAIT64( // mask will discard bits 8 to 11
|
||||
hipStreamWaitValueAnd, 0xFF, 0xF4A, 0xF35, 0X02))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Nor_1",
|
||||
TEST_WAIT64( // mask is set to ignore the sign bit.
|
||||
hipStreamWaitValueNor, 0x7FFFFFFFFFFFFFFF,
|
||||
0x7FFFFFFFFFFFF247, 0x7FFFFFFFFFFFFdbd,
|
||||
0x7FFFFFFFFFFFFdb5))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("Mask_Nor_2",
|
||||
TEST_WAIT64( // mask is set to apply NOR for bits 0 to 3.
|
||||
hipStreamWaitValueNor, 0xF, 0x7E, 0x7D, 0x76))
|
||||
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("NoMask_Gte",
|
||||
TEST_WAIT64(hipStreamWaitValueGte, 0x7FFFFFFFFFFF0001,
|
||||
0x7FFFFFFFFFFF0000, 0x7FFFFFFFFFFF0001))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("NoMask_Eq",
|
||||
TEST_WAIT64(hipStreamWaitValueEq, 0x7FFFFFFFFFFFFFFF,
|
||||
0x7FFFFFFF0FFF0000, 0x7FFFFFFFFFFFFFFF))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("NoMask_And",
|
||||
TEST_WAIT64(hipStreamWaitValueAnd, 0x70F0F0F0F0F0F0F0,
|
||||
0x0F0F0F0F0F0F0F0F, 0X1F0F0F0F0F0F0F0F))
|
||||
DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64("NoMask_Nor",
|
||||
TEST_WAIT64(hipStreamWaitValueNor, 0x4724724747247247,
|
||||
static_cast<int64_t>(0xbddbddbdbddbddbd),
|
||||
static_cast<int64_t>(0xbddbddbdbddbddb3)))
|
||||
#undef DEFINE_STREAM_WAIT_VAL_TEST_CASES_INT64
|
||||
|
||||
#endif
|
||||
|
||||
// Negative Tests
|
||||
TEST_CASE("Unit_hipStreamValue_Negative_InvalidMemory") {
|
||||
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-96");
|
||||
return;
|
||||
#endif
|
||||
|
||||
hipStream_t stream{nullptr};
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
REQUIRE(stream != nullptr);
|
||||
|
||||
// Allocate Host Memory
|
||||
auto hostPtr32 = std::unique_ptr<uint32_t>(new uint32_t(1));
|
||||
auto hostPtr64 = std::unique_ptr<uint64_t>(new uint64_t(1));
|
||||
|
||||
// Register Host Memory
|
||||
HIP_CHECK(hipHostRegister(hostPtr32.get(), sizeof(int32_t), 0));
|
||||
HIP_CHECK(hipHostRegister(hostPtr64.get(), sizeof(int64_t), 0));
|
||||
|
||||
// Set dummy data
|
||||
*hostPtr64 = 0x0;
|
||||
*hostPtr32 = 0x0;
|
||||
|
||||
auto compareOp = hipStreamWaitValueGte;
|
||||
|
||||
// Memory pointer negative tests
|
||||
|
||||
INFO("Testing Invalid Memory Pointer for hipStreamWriteValue32");
|
||||
NEG_TEST_ERROR_CHECK(Write, 32, hipErrorNotSupported, stream, nullptr, 0, writeFlag)
|
||||
|
||||
INFO("Testing Invalid Memory Pointer for hipStreamWriteValue64");
|
||||
NEG_TEST_ERROR_CHECK(Write, 64, hipErrorNotSupported, stream, nullptr, 0, writeFlag)
|
||||
|
||||
INFO("Testing Invalid Memory Pointer for hipStreamWaitValue32");
|
||||
NEG_TEST_ERROR_CHECK(Wait, 32, hipErrorNotSupported, stream, nullptr, 0, compareOp)
|
||||
|
||||
INFO("Testing Invalid Memory Pointer for hipStreamWaitValue64");
|
||||
NEG_TEST_ERROR_CHECK(Wait, 64, hipErrorNotSupported, stream, nullptr, 0, compareOp)
|
||||
|
||||
// Cleanup
|
||||
HIP_CHECK(hipHostUnregister(hostPtr32.get()));
|
||||
HIP_CHECK(hipHostUnregister(hostPtr64.get()));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
TEST_CASE("Unit_hipStreamWaitValue_Negative_InvalidFlag") {
|
||||
#if HT_AMD
|
||||
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-96");
|
||||
return;
|
||||
#endif
|
||||
|
||||
hipStream_t stream{nullptr};
|
||||
|
||||
HIP_CHECK(hipStreamCreate(&stream));
|
||||
|
||||
REQUIRE(stream != nullptr);
|
||||
|
||||
// Allocate Host Memory
|
||||
auto hostPtr32 = std::unique_ptr<uint32_t>(new uint32_t(1));
|
||||
auto hostPtr64 = std::unique_ptr<uint64_t>(new uint64_t(1));
|
||||
|
||||
// Register Host Memory
|
||||
HIP_CHECK(hipHostRegister(hostPtr32.get(), sizeof(int32_t), 0));
|
||||
HIP_CHECK(hipHostRegister(hostPtr64.get(), sizeof(int64_t), 0));
|
||||
|
||||
// Set dummy data
|
||||
*hostPtr64 = 0x0;
|
||||
*hostPtr32 = 0x0;
|
||||
|
||||
/* EXSWCPHIPT-96 */
|
||||
INFO("Testing Invalid flag for hipStreamWaitValue32");
|
||||
NEG_TEST_ERROR_CHECK(Wait, 32, hipErrorNotSupported, stream, hostPtr32.get(), 0, -1)
|
||||
INFO("Testing Invalid flag for hipStreamWaitValue64");
|
||||
NEG_TEST_ERROR_CHECK(Wait, 64, hipErrorNotSupported, stream, hostPtr64.get(), 0, -1)
|
||||
|
||||
// Cleanup
|
||||
HIP_CHECK(hipHostUnregister(hostPtr32.get()));
|
||||
HIP_CHECK(hipHostUnregister(hostPtr64.get()));
|
||||
HIP_CHECK(hipStreamDestroy(stream));
|
||||
}
|
||||
|
||||
#undef NEG_TEST_ERROR_CHECK
|
||||
@@ -23,21 +23,16 @@ THE SOFTWARE.
|
||||
std::vector<unsigned int> hw_vector = {2048, 1024, 512, 256, 64};
|
||||
std::vector<unsigned int> mip_vector = {8, 4, 2, 1};
|
||||
|
||||
__global__ void tex2DKernel(float* outputData,
|
||||
hipTextureObject_t textureObject,
|
||||
int width, float level) {
|
||||
#ifndef __gfx90a__
|
||||
#if !defined(__HIP_NO_IMAGE_SUPPORT) || !__HIP_NO_IMAGE_SUPPORT
|
||||
// MipMap is currently supported only on windows
|
||||
#if (defined(_WIN32) && !defined(__HIP_NO_IMAGE_SUPPORT))
|
||||
__global__ void tex2DKernel(float* outputData, hipTextureObject_t textureObject, int width,
|
||||
float level) {
|
||||
int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
outputData[y * width + x] = tex2DLod<float>(textureObject, x, y, level);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32 // MipMap is currently supported only on windows
|
||||
static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
unsigned int mipmap_level) {
|
||||
static void runMipMapTest(unsigned int width, unsigned int height, unsigned int mipmap_level) {
|
||||
INFO("Width: " << width << "Height: " << height << "mip: " << mipmap_level);
|
||||
|
||||
// Create new width & height to be tested
|
||||
@@ -57,26 +52,23 @@ static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
}
|
||||
}
|
||||
|
||||
hipChannelFormatDesc channelDesc = hipCreateChannelDesc(32, 0, 0, 0,
|
||||
hipChannelFormatKindFloat);
|
||||
hipChannelFormatDesc channelDesc = hipCreateChannelDesc(32, 0, 0, 0, hipChannelFormatKindFloat);
|
||||
HIP_ARRAY3D_DESCRIPTOR mipmapped_array_desc;
|
||||
memset(&mipmapped_array_desc, 0x00, sizeof(HIP_ARRAY3D_DESCRIPTOR));
|
||||
mipmapped_array_desc.Width = orig_width;
|
||||
mipmapped_array_desc.Height = orig_height;
|
||||
mipmapped_array_desc.Depth = 0;
|
||||
mipmapped_array_desc.Format = HIP_AD_FORMAT_FLOAT;
|
||||
mipmapped_array_desc.NumChannels = ((channelDesc.x != 0) +
|
||||
(channelDesc.y != 0) + (channelDesc.z != 0) + (channelDesc.w != 0));
|
||||
mipmapped_array_desc.NumChannels =
|
||||
((channelDesc.x != 0) + (channelDesc.y != 0) + (channelDesc.z != 0) + (channelDesc.w != 0));
|
||||
mipmapped_array_desc.Flags = 0;
|
||||
|
||||
hipMipmappedArray* mip_array_ptr;
|
||||
HIP_CHECK(hipMipmappedArrayCreate(&mip_array_ptr, &mipmapped_array_desc,
|
||||
2 * mipmap_level));
|
||||
HIP_CHECK(hipMipmappedArrayCreate(&mip_array_ptr, &mipmapped_array_desc, 2 * mipmap_level));
|
||||
|
||||
hipArray *hipArray = nullptr;
|
||||
hipArray* hipArray = nullptr;
|
||||
HIP_CHECK(hipMipmappedArrayGetLevel(&hipArray, mip_array_ptr, mipmap_level));
|
||||
HIP_CHECK(hipMemcpyToArray(hipArray, 0, 0, hData, size,
|
||||
hipMemcpyHostToDevice));
|
||||
HIP_CHECK(hipMemcpyToArray(hipArray, 0, 0, hData, size, hipMemcpyHostToDevice));
|
||||
|
||||
hipResourceDesc resDesc;
|
||||
memset(&resDesc, 0, sizeof(resDesc));
|
||||
@@ -94,8 +86,7 @@ static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
|
||||
// Create texture object
|
||||
hipTextureObject_t textureObject = 0;
|
||||
HIP_CHECK(hipCreateTextureObject(&textureObject, &resDesc,
|
||||
&texDesc, nullptr));
|
||||
HIP_CHECK(hipCreateTextureObject(&textureObject, &resDesc, &texDesc, nullptr));
|
||||
|
||||
float* dData = nullptr;
|
||||
HIP_CHECK(hipMalloc(&dData, size));
|
||||
@@ -104,8 +95,8 @@ static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
dim3 dimBlock(16, 16, 1);
|
||||
dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1);
|
||||
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData,
|
||||
textureObject, width, (2 * mipmap_level));
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, textureObject, width,
|
||||
(2 * mipmap_level));
|
||||
hipDeviceSynchronize();
|
||||
|
||||
float* hOutputData = reinterpret_cast<float*>(malloc(size));
|
||||
@@ -116,8 +107,8 @@ static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
if (hData[i * width + j] != hOutputData[i * width + j]) {
|
||||
INFO("Difference found at [ " << i << j << " ]: " <<
|
||||
hData[i * width + j] << hOutputData[i * width + j]);
|
||||
INFO("Difference found at [ " << i << j << " ]: " << hData[i * width + j]
|
||||
<< hOutputData[i * width + j]);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
@@ -132,8 +123,7 @@ static void runMipMapTest(unsigned int width, unsigned int height,
|
||||
TEST_CASE("Unit_hipTextureMipmapObj2D_Check") {
|
||||
#if HT_AMD
|
||||
int imageSupport{};
|
||||
HIP_CHECK(hipDeviceGetAttribute(&imageSupport,
|
||||
hipDeviceAttributeImageSupport, 0));
|
||||
HIP_CHECK(hipDeviceGetAttribute(&imageSupport, hipDeviceAttributeImageSupport, 0));
|
||||
if (!imageSupport) {
|
||||
INFO("Texture is not supported on the device. Test is skipped");
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/* Copyright (c) 2021 - 2021 Advanced Micro Devices, Inc.
|
||||
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>
|
||||
#include <chrono>
|
||||
#include <test_common.h>
|
||||
#include <vector>
|
||||
/* HIT_START
|
||||
* BUILD: %t %s ../../test_common.cpp
|
||||
* TEST: %t
|
||||
* HIT_END
|
||||
*/
|
||||
#define THREADS_PER_BLOCK 512
|
||||
#define GRAPH_LAUNCH_ITERATIONS 100
|
||||
__global__ void reduce(float* d_in, double* d_out, size_t inputSize, size_t outputSize) {
|
||||
int myId = threadIdx.x + blockDim.x * blockIdx.x;
|
||||
int tid = threadIdx.x;
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (tid < s) {
|
||||
d_in[myId] += d_in[myId + s];
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
if (tid == 0) {
|
||||
d_out[blockIdx.x] = d_in[myId];
|
||||
}
|
||||
}
|
||||
__global__ void reduceFinal(double* d_in, double* d_out, size_t inputSize) {
|
||||
int myId = threadIdx.x + blockDim.x * blockIdx.x;
|
||||
int tid = threadIdx.x;
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (tid < s) {
|
||||
d_in[myId] += d_in[myId + s];
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
if (tid == 0) {
|
||||
*d_out = d_in[myId];
|
||||
}
|
||||
}
|
||||
void init_input(float* a, size_t size) {
|
||||
for (size_t i = 0; i < size; i++) a[i] = (rand() & 0xFF) / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d, double* result_d,
|
||||
size_t inputSize, size_t numOfBlocks) {
|
||||
hipStream_t streamForGraph;
|
||||
hipGraph_t graph, childgraph;
|
||||
std::vector<hipGraphNode_t> nodeDependencies;
|
||||
hipGraphNode_t memcpyNode, kernelNode, memsetNode1, memsetNode2, childGraphNode;
|
||||
double result_h = 0.0;
|
||||
HIPCHECK(hipStreamCreate(&streamForGraph));
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
hipKernelNodeParams kernelNodeParams = {0};
|
||||
hipMemsetParams memsetParams = {0};
|
||||
memsetParams.dst = (void*)outputVec_d;
|
||||
memsetParams.value = 0;
|
||||
memsetParams.pitch = 0;
|
||||
memsetParams.elementSize = sizeof(float);
|
||||
memsetParams.width = numOfBlocks * 2;
|
||||
memsetParams.height = 1;
|
||||
HIPCHECK(hipGraphCreate(&graph, 0));
|
||||
HIPCHECK(hipGraphCreate(&childgraph, 0));
|
||||
HIPCHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, inputVec_d, inputVec_h,
|
||||
sizeof(float) * inputSize, hipMemcpyHostToDevice));
|
||||
HIPCHECK(hipGraphAddMemsetNode(&memsetNode1, graph, NULL, 0, &memsetParams));
|
||||
|
||||
void* kernelArgs[4] = {(void*)&inputVec_d, (void*)&outputVec_d, &inputSize, &numOfBlocks};
|
||||
kernelNodeParams.func = (void*)reduce;
|
||||
kernelNodeParams.gridDim = dim3(inputSize / THREADS_PER_BLOCK, 1, 1);
|
||||
kernelNodeParams.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
kernelNodeParams.kernelParams = (void**)kernelArgs;
|
||||
kernelNodeParams.extra = NULL;
|
||||
HIPCHECK(hipGraphAddKernelNode(&kernelNode, childgraph, NULL, 0, &kernelNodeParams));
|
||||
nodeDependencies.clear();
|
||||
nodeDependencies.push_back(kernelNode);
|
||||
memset(&memsetParams, 0, sizeof(memsetParams));
|
||||
memsetParams.dst = result_d;
|
||||
memsetParams.value = 0;
|
||||
memsetParams.elementSize = sizeof(float);
|
||||
memsetParams.width = 2;
|
||||
memsetParams.height = 1;
|
||||
HIPCHECK(hipGraphAddMemsetNode(&memsetNode2, childgraph, NULL, 0, &memsetParams));
|
||||
nodeDependencies.push_back(memsetNode2);
|
||||
memset(&kernelNodeParams, 0, sizeof(kernelNodeParams));
|
||||
kernelNodeParams.func = (void*)reduceFinal;
|
||||
kernelNodeParams.gridDim = dim3(1, 1, 1);
|
||||
kernelNodeParams.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
|
||||
kernelNodeParams.sharedMemBytes = 0;
|
||||
void* kernelArgs2[3] = {(void*)&outputVec_d, (void*)&result_d, &numOfBlocks};
|
||||
kernelNodeParams.kernelParams = kernelArgs2;
|
||||
kernelNodeParams.extra = NULL;
|
||||
HIPCHECK(hipGraphAddKernelNode(&kernelNode, childgraph, nodeDependencies.data(),
|
||||
nodeDependencies.size(), &kernelNodeParams));
|
||||
nodeDependencies.clear();
|
||||
nodeDependencies.push_back(memcpyNode);
|
||||
nodeDependencies.push_back(memsetNode1);
|
||||
HIPCHECK(hipGraphAddChildGraphNode(&childGraphNode, graph, nodeDependencies.data(),
|
||||
nodeDependencies.size(), childgraph));
|
||||
nodeDependencies.clear();
|
||||
nodeDependencies.push_back(childGraphNode);
|
||||
HIPCHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, nodeDependencies.data(),
|
||||
nodeDependencies.size(), &result_h, result_d, sizeof(double),
|
||||
hipMemcpyDeviceToHost));
|
||||
|
||||
hipGraphExec_t graphExec;
|
||||
HIPCHECK(hipGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
|
||||
|
||||
auto start1 = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
|
||||
HIPCHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
}
|
||||
HIPCHECK(hipStreamSynchronize(streamForGraph));
|
||||
double result_h_cpu = 0.0;
|
||||
for (int i = 0; i < inputSize; i++) {
|
||||
result_h_cpu += inputVec_h[i];
|
||||
}
|
||||
if (result_h_cpu != result_h) {
|
||||
printf("Final reduced sum = %lf %lf\n", result_h_cpu, result_h);
|
||||
return false;
|
||||
}
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
auto resultWithInit = std::chrono::duration<double, std::milli>(stop - start);
|
||||
auto resultWithoutInit = std::chrono::duration<double, std::milli>(stop - start1);
|
||||
std::cout << "Time taken for hipGraphsManual with Init: "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(resultWithInit).count()
|
||||
<< " milliseconds without Init:"
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(resultWithoutInit).count()
|
||||
<< " milliseconds " << std::endl;
|
||||
|
||||
hipGraph_t clonedGraph;
|
||||
hipGraphExec_t clonedGraphExec;
|
||||
HIPCHECK(hipGraphClone(&clonedGraph, graph));
|
||||
|
||||
HIPCHECK(hipGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0));
|
||||
|
||||
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
|
||||
HIPCHECK(hipGraphLaunch(clonedGraphExec, streamForGraph));
|
||||
}
|
||||
HIPCHECK(hipStreamSynchronize(streamForGraph));
|
||||
if (result_h_cpu != result_h) {
|
||||
printf("Cloned graph final reduced sum = %lf %lf\n", result_h_cpu, result_h);
|
||||
return false;
|
||||
}
|
||||
|
||||
HIPCHECK(hipGraphExecDestroy(graphExec));
|
||||
HIPCHECK(hipGraphExecDestroy(clonedGraphExec));
|
||||
HIPCHECK(hipGraphDestroy(graph));
|
||||
HIPCHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
size_t size = 1 << 12;
|
||||
size_t maxBlocks = 512;
|
||||
hipSetDevice(0);
|
||||
printf("%zu elements\n", size);
|
||||
printf("threads per block = %d\n", THREADS_PER_BLOCK);
|
||||
printf("Graph Launch iterations = %d\n", GRAPH_LAUNCH_ITERATIONS);
|
||||
float *inputVec_d = NULL, *inputVec_h = NULL;
|
||||
double *outputVec_d = NULL, *result_d;
|
||||
inputVec_h = (float*)malloc(sizeof(float) * size);
|
||||
HIPCHECK(hipMalloc(&inputVec_d, sizeof(float) * size));
|
||||
HIPCHECK(hipMalloc(&outputVec_d, sizeof(double) * maxBlocks));
|
||||
HIPCHECK(hipMalloc(&result_d, sizeof(double)));
|
||||
init_input(inputVec_h, size);
|
||||
bool status = hipGraphsManual(inputVec_h, inputVec_d, outputVec_d, result_d, size, maxBlocks);
|
||||
HIPCHECK(hipFree(inputVec_d));
|
||||
HIPCHECK(hipFree(outputVec_d));
|
||||
HIPCHECK(hipFree(result_d));
|
||||
if (!status) {
|
||||
failed("Failed during hip graph manual\n");
|
||||
}
|
||||
passed();
|
||||
}
|
||||
@@ -36,7 +36,6 @@ __global__ void reduce(float* d_in, double* d_out, size_t inputSize, size_t outp
|
||||
__syncthreads();
|
||||
}
|
||||
if (tid == 0) {
|
||||
int blkx = blockIdx.x;
|
||||
d_out[blockIdx.x] = d_in[myId];
|
||||
}
|
||||
}
|
||||
@@ -255,6 +254,7 @@ bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d,
|
||||
hipMemcpyDeviceToHost));
|
||||
nodeDependencies.clear();
|
||||
nodeDependencies.push_back(memcpyNode);
|
||||
|
||||
hipGraphNode_t hostNode;
|
||||
hipHostNodeParams hostParams = {0};
|
||||
hostParams.fn = myHostNodeCallback;
|
||||
@@ -274,6 +274,13 @@ bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d,
|
||||
HIPCHECK(hipGraphGetRootNodes(graph, nodes, &numNodes));
|
||||
printf("Num of root nodes in the graph created using hipGraphsManual API = %zu\n", numNodes);
|
||||
HIPCHECK(hipGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
|
||||
|
||||
hipGraph_t clonedGraph;
|
||||
hipGraphExec_t clonedGraphExec;
|
||||
HIPCHECK(hipGraphClone(&clonedGraph, graph));
|
||||
|
||||
HIPCHECK(hipGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0));
|
||||
|
||||
auto start1 = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
|
||||
HIPCHECK(hipGraphLaunch(graphExec, streamForGraph));
|
||||
@@ -288,6 +295,22 @@ bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d,
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(resultWithoutInit).count()
|
||||
<< " milliseconds " << std::endl;
|
||||
|
||||
printf("\n\nCloned Graph Output.. \n");
|
||||
|
||||
hipGraphNode_t clonedNode;
|
||||
hipGraphNodeFindInClone(&clonedNode, memcpyNode, clonedGraph);
|
||||
|
||||
hipGraphNodeType clonedNodeType, origNodeType;
|
||||
hipGraphNodeGetType(clonedNode, &clonedNodeType);
|
||||
hipGraphNodeGetType(memcpyNode, &origNodeType);
|
||||
|
||||
std::cout << "Original node type:" << origNodeType << " cloned node type:" << clonedNodeType
|
||||
<< std::endl;
|
||||
|
||||
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
|
||||
HIPCHECK(hipGraphLaunch(clonedGraphExec, streamForGraph));
|
||||
}
|
||||
HIPCHECK(hipStreamSynchronize(streamForGraph));
|
||||
HIPCHECK(hipGraphExecDestroy(graphExec));
|
||||
HIPCHECK(hipGraphDestroy(graph));
|
||||
HIPCHECK(hipStreamDestroy(streamForGraph));
|
||||
|
||||
مرجع در شماره جدید
Block a user