SWDEV-299127 - Merge 'develop' into 'amd-staging'

Change-Id: I9b17091d0113e2cceedec0c12390578b062ee55b
This commit is contained in:
Jenkins
2022-06-10 07:10:43 -04:00
کامیت 1dfaa6d463
65فایلهای تغییر یافته به همراه2410 افزوده شده و 301 حذف شده
فروخته شده
+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
+2 -7
مشاهده پرونده
@@ -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
+19 -5
مشاهده پرونده
@@ -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(&copyParam, 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(&copyParam));
hip_Memcpy2D copyParam;
memset(&copyParam, 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(&copyParam));
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));