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

Change-Id: I35862740e33def19512bc82122da3a6c31f47a85
Этот коммит содержится в:
Sai Keerthana
2022-02-25 07:16:36 -05:00
родитель 5cb7fe5df7 5eade5cfa1
Коммит 55442f70b5
47 изменённых файлов: 5988 добавлений и 349 удалений
+1 -1
Просмотреть файл
@@ -1,2 +1,2 @@
@IF DEFINED HIP_PATH (set HIPCC="%HIP_PATH%/bin/hipcc") ELSE (set HIPCC="%~dp0/hipcc")
set HIPCC="%~dp0/hipcc"
@perl %HIPCC% %*
+1 -1
Просмотреть файл
@@ -1,2 +1,2 @@
@IF DEFINED HIP_PATH (set HIPCONFIG="%HIP_PATH%/bin/hipconfig") ELSE (set HIPCONFIG="%~dp0/hipconfig")
set HIPCONFIG="%~dp0/hipconfig"
@perl %HIPCONFIG% %*
+7 -3
Просмотреть файл
@@ -50,8 +50,8 @@ mark_as_advanced(HIP_HOST_COMPILATION_CPP)
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../" REALPATH)
# HIP is supported on Linux only
if(UNIX AND NOT APPLE AND NOT CYGWIN)
# HIP is currently not supported for apple
if(NOT APPLE)
# Search for HIP installation
if(NOT HIP_ROOT_DIR)
# Search in user specified path first
@@ -94,7 +94,6 @@ if(UNIX AND NOT APPLE AND NOT CYGWIN)
# Now search in default paths
find_program(HIP_HIPCC_EXECUTABLE hipcc)
endif()
mark_as_advanced(HIP_HIPCC_EXECUTABLE)
# Find HIPCONFIG executable
find_program(
@@ -113,7 +112,12 @@ if(UNIX AND NOT APPLE AND NOT CYGWIN)
# Now search in default paths
find_program(HIP_HIPCONFIG_EXECUTABLE hipconfig)
endif()
if(NOT UNIX)
set(HIP_HIPCONFIG_EXECUTABLE "${HIP_HIPCONFIG_EXECUTABLE}.bat")
set(HIP_HIPCC_EXECUTABLE "${HIP_HIPCC_EXECUTABLE}.bat")
endif()
mark_as_advanced(HIP_HIPCONFIG_EXECUTABLE)
mark_as_advanced(HIP_HIPCC_EXECUTABLE)
# Find HIPCC_CMAKE_LINKER_HELPER executable
find_program(
+1 -1
Просмотреть файл
@@ -56,7 +56,7 @@ struct hip_bfloat16
enum truncate_t
{
truncate
truncate_0
};
__host__ __device__ hip_bfloat16() = default;
+32
Просмотреть файл
@@ -445,6 +445,8 @@ typedef enum hipDeviceAttribute_t {
///< hipStreamWaitValue64(), '0' otherwise.
hipDeviceAttributeImageSupport, ///< '1' if Device supports image, '0' otherwise.
hipDeviceAttributeMultiprocessorBoostCount, ///< All available boost compute units for the device
hipDeviceAttributeAmdSpecificEnd = 19999,
hipDeviceAttributeVendorSpecificBegin = 20000,
// Extended attributes for vendors
@@ -4302,6 +4304,11 @@ typedef enum hipStreamUpdateCaptureDependenciesFlags {
hipStreamSetCaptureDependencies, ///< Replace the dependency set with the new nodes
} hipStreamUpdateCaptureDependenciesFlags;
typedef enum hipGraphInstantiateFlags {
hipGraphInstantiateFlagAutoFreeOnLaunch =
1, ///< Automatically free memory allocated in a graph before relaunching.
} hipGraphInstantiateFlags;
/**
* @brief Begins graph capture on a stream.
*
@@ -4399,6 +4406,31 @@ hipError_t hipStreamUpdateCaptureDependencies(hipStream_t stream, hipGraphNode_t
size_t numDependencies,
unsigned int flags __dparm(0));
/**
* @brief Enqueues a host function call in a stream.
*
* @param [in] stream - stream to enqueue work to.
* @param [in] fn - function to call once operations enqueued preceeding are complete.
* @param [in] userData - User-specified data to be passed to the function.
* @returns #hipSuccess, #hipErrorInvalidResourceHandle, #hipErrorInvalidValue,
* #hipErrorNotSupported
* @warning : This API is marked as beta, meaning, while this is feature complete,
* it is still open to changes and may have outstanding issues.
*/
hipError_t hipLaunchHostFunc(hipStream_t stream, hipHostFn_t fn, void* userData);
/**
* @brief Swaps the stream capture mode of a thread.
*
* @param [in] mode - Pointer to mode value to swap with the current mode
* @returns #hipSuccess, #hipErrorInvalidValue
*
* @warning : This API is marked as beta, meaning, while this is feature complete,
* it is still open to changes and may have outstanding issues.
*
*/
hipError_t hipThreadExchangeStreamCaptureMode(hipStreamCaptureMode* mode);
/**
* @brief Creates a graph
*
-3
Просмотреть файл
@@ -69,9 +69,6 @@ int main() {
HIP_CHECK(hipModuleLoad(&Module, fileName));
HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name));
uint32_t len = LEN;
uint32_t one = 1;
struct {
void* _Ad;
void* _Bd;
+1 -1
Просмотреть файл
@@ -401,7 +401,6 @@ void ResultDatabase::DumpCsv(string fileName) {
// ****************************************************************************
bool ResultDatabase::IsFileEmpty(string fileName) {
bool fileEmpty;
ifstream file(fileName.c_str());
@@ -409,6 +408,7 @@ bool ResultDatabase::IsFileEmpty(string fileName) {
if (!file.good()) {
return true;
} else {
bool fileEmpty;
fileEmpty = (bool)(file.peek() == ifstream::traits_type::eof());
file.close();
+2 -2
Просмотреть файл
@@ -252,9 +252,9 @@ void RunBenchmark_H2D(ResultDatabase& resultDB) {
case MallocUnpinned:
if (p_alignedhost) {
delete[] hostMem;
} else {
free(hostMem);
} else {
delete[] hostMem;
}
break;
+1 -1
Просмотреть файл
@@ -393,7 +393,6 @@ void ResultDatabase::DumpCsv(string fileName) {
// ****************************************************************************
bool ResultDatabase::IsFileEmpty(string fileName) {
bool fileEmpty;
ifstream file(fileName.c_str());
@@ -401,6 +400,7 @@ bool ResultDatabase::IsFileEmpty(string fileName) {
if (!file.good()) {
return true;
} else {
bool fileEmpty;
fileEmpty = (bool)(file.peek() == ifstream::traits_type::eof());
file.close();
+6 -6
Просмотреть файл
@@ -282,7 +282,7 @@ class Command {
// HCC optimizes away fully NULL kernel calls, so run one that is nearly null:
class ModuleKernelCommand : public Command {
public:
ModuleKernelCommand(CommandStream* cmdStream, const std::vector<std::string> args)
ModuleKernelCommand(CommandStream* cmdStream, const std::vector<std::string>& args)
: Command(cmdStream, args), _stream(cmdStream->currentStream()) {
hipModule_t module;
HIPCHECK(hipModuleLoad(&module, FILENAME));
@@ -316,7 +316,7 @@ class ModuleKernelCommand : public Command {
class KernelCommand : public Command {
public:
enum Type { Null, VectorAdd };
KernelCommand(CommandStream* cmdStream, const std::vector<std::string> args, Type kind)
KernelCommand(CommandStream* cmdStream, const std::vector<std::string>& args, Type kind)
: Command(cmdStream, args), _kind(kind), _stream(cmdStream->currentStream()){};
~KernelCommand(){};
@@ -390,7 +390,7 @@ class CopyCommand : public Command {
};
void dealloc(void* p, MemType memType) {
static void dealloc(void* p, MemType memType) {
if (memType == Device) {
HIPCHECK(hipFree(p));
} else if (memType == PinnedHost) {
@@ -433,7 +433,7 @@ class StreamSyncCommand : public Command {
StreamSyncCommand(CommandStream* cmdStream, const std::vector<std::string>& args)
: Command(cmdStream, args), _stream(cmdStream->currentStream()){};
const char* help() { return "synchronizes the current stream"; };
static const char* help() { return "synchronizes the current stream"; };
void run() override { HIPCHECK(hipStreamSynchronize(_stream)); };
@@ -537,8 +537,8 @@ CopyCommand::CopyCommand(CommandStream* cmdStream, const std::vector<std::string
hipMemcpyKind kind, bool isAsync, bool isPinnedHost)
: Command(cmdStream, args),
_isAsync(isAsync),
_kind(kind),
_stream(cmdStream->currentStream()) {
_stream(cmdStream->currentStream()),
_kind(kind) {
switch (kind) {
case hipMemcpyDeviceToHost:
_srcType = Device;
+4 -7
Просмотреть файл
@@ -48,17 +48,14 @@ __global__ void incrementKernel(int32_t* in, int32_t* out, int32_t value, size_t
int main() {
int32_t incrementValue = 10;
// Host pointers
int32_t* hInput = nullptr;
int32_t* hOutput = nullptr;
// Device pointers
int32_t* dInput = nullptr;
int32_t* dOutput = nullptr;
size_t NBytes = SIZE * sizeof(int32_t);
hInput = static_cast<int32_t*>(malloc(NBytes));
hOutput = static_cast<int32_t*>(malloc(NBytes));
// Host pointers
int32_t* hInput = static_cast<int32_t*>(malloc(NBytes));
int32_t* hOutput = static_cast<int32_t*>(malloc(NBytes));
HIP_STATUS_CHECK(hipMalloc(&dInput, NBytes));
HIP_STATUS_CHECK(hipMalloc(&dOutput, NBytes));
@@ -95,4 +92,4 @@ int main() {
std::cout << "success\n";
}
return 0;
}
}
+2 -2
Просмотреть файл
@@ -58,8 +58,8 @@ void run_test2() {
HIP_ASSERT(hipFree(A_d));
HIP_ASSERT(hipFree(B_d));
free(A_h);
free(B_h);
delete [] A_h;
delete [] B_h;
std::cout << "Test Passed!\n";
}
+226 -1
Просмотреть файл
@@ -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
@@ -19,6 +19,15 @@
// The following test case allocation, host access, device access of HMM
// memory from size 1 to 10KB
/* Test Case Description:
1) Testing allocation, host access, device access of HMM
memory from size 1 to 10KB
2) The following test case tests the behavior of kernel with a HMM memory
and hipMalloc memory
3) The following test case tests when the same Hmm memory is used for
launching multiple different kernels will results in any issue
4) Testing the allocation of/scenarios around max possible memory
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
@@ -35,6 +44,86 @@ __global__ void KrnlWth2MemTypesC(unsigned char *Hmm, unsigned char *Dptr,
}
static bool IfTestPassed = true;
// Kernel functions
__global__ void KrnlWth2MemTypes(int *Hmm, int *Dptr, size_t n) {
size_t index = blockIdx.x * blockDim.x + threadIdx.x;
for (size_t i = index; i < n; i++) {
Hmm[i] = Dptr[i] + 10;
}
}
__global__ void KernelMulAdd_MngdMem(int *Hmm, size_t n) {
size_t index = blockIdx.x * blockDim.x + threadIdx.x;
size_t stride = blockDim.x * gridDim.x;
for (size_t i = index; i < n; i += stride) {
Hmm[i] = Hmm[i] * 2 + 10;
}
}
__global__ void KernelMul_MngdMem(int *Hmm, int *Dptr, size_t n) {
size_t index = blockIdx.x * blockDim.x + threadIdx.x;
size_t stride = blockDim.x * gridDim.x;
for (size_t i = index; i < n; i += stride) {
Hmm[i] = Dptr[i] * 10;
}
}
static bool IfTestPassed = true;
static void LaunchKrnl4(size_t NumElms, int InitVal) {
int *Hmm = NULL, *Dptr = NULL, blockSize = 64, DataMismatch = 0;
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMallocManaged(&Hmm, (sizeof(int) * NumElms)));
HIP_CHECK(hipMalloc(&Dptr, (sizeof(int) * NumElms)));
int *Hstptr = reinterpret_cast<int*>(new int[NumElms]);
for (size_t i = 0; i < NumElms; ++i) {
Hstptr[i] = InitVal;
}
HIP_CHECK(hipMemcpy(Dptr, Hstptr, (NumElms * sizeof(int)),
hipMemcpyHostToDevice));
dim3 dimBlock(blockSize, 1, 1);
dim3 dimGrid((NumElms + blockSize -1)/blockSize, 1, 1);
KrnlWth2MemTypes<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observed after the Kernel: KrnlWth2MemTypes!!\n");
REQUIRE(false);
}
DataMismatch = 0;
KernelMul_MngdMem<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the result
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal * 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observedafter the Kernel: KernelMul_MngdMem!!\n");
REQUIRE(false);
}
DataMismatch = 0;
KernelMulAdd_MngdMem<<<dimGrid, dimBlock, 0, strm>>>(Hmm, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the result
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal * 10 * 2 + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observedafter the Kernel: KernelMul_MngdMem!!\n");
REQUIRE(false);
}
delete[] Hstptr;
}
static int HmmAttrPrint() {
int managed = 0;
INFO("The following are the attribute values related to HMM for"
@@ -104,3 +193,139 @@ TEST_CASE("Unit_hipMallocManaged_MultiSize") {
}
}
// The following test case tests the behavior of kernel with a HMM memory and
// hipMalloc memory
TEST_CASE("Unit_hipMallocManaged_KrnlWth2MemTypes") {
IfTestPassed = true;
int *Hmm = NULL, *Dptr = NULL, InitVal = 123;
size_t NumElms = (1024 * 1024);
int *Hptr = new int[NumElms], blockSize = 64, DataMismatch = 0;
int managed = HmmAttrPrint();
if (managed == 1) {
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMallocManaged(&Hmm, sizeof(int) * NumElms));
HIP_CHECK(hipMalloc(&Dptr, sizeof(int) * NumElms));
for (size_t i = 0; i < NumElms; ++i) {
Hmm[i] = 0;
Hptr[i] = InitVal;
}
HIP_CHECK(hipMemcpy(Dptr, Hptr, sizeof(int) * NumElms,
hipMemcpyHostToDevice));
dim3 dimBlock(blockSize, 1, 1);
dim3 dimGrid((NumElms + blockSize -1)/blockSize, 1, 1);
KrnlWth2MemTypes<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the results
for (size_t k = 0; k < NumElms; ++k) {
if (Hmm[k] != (InitVal + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
WARN("DataMismatch observed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(Hmm));
HIP_CHECK(hipFree(Dptr));
delete[] Hptr;
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
// The following test case tests when the same Hmm memory is used for
// launching multiple different kernels will results in any issue
TEST_CASE("Unit_hipMallocManaged_MultiKrnlHmmAccess") {
int managed = HmmAttrPrint();
if (managed) {
int InitVal = 123, NumElms = (1024 * 1024);
LaunchKrnl4(NumElms, InitVal);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
// Testing the allocation of/scenarios around max possible memory
TEST_CASE("Unit_hipMallocManaged_ExtremeSizes") {
int managed = HmmAttrPrint();
if (managed == 1) {
bool IfTestPassed = true;
hipError_t err;
void *Hmm = NULL;
size_t totalDevMem = 0, freeDevMem = 0;
int NumDevs = 0;
HIP_CHECK(hipGetDeviceCount(&NumDevs));
// Testing allocation of extreme and unusual mem values
for (int i = 0; i < NumDevs; i++) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemGetInfo(&freeDevMem, &totalDevMem));
err = hipMallocManaged(&Hmm, 1, hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating memory on GPU: " << i);
WARN(" size 1 with");
WARN(" hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, freeDevMem, hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max free memory on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, (freeDevMem - 1), hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max (free - 1) memory on ");
WARN("GPU: " << i);
WARN(" using hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, 1, hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating memory size 1 on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, freeDevMem, hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max free memory on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, (freeDevMem - 1), hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max (freeDevMem - 1) memory"
" on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
}
REQUIRE(IfTestPassed);
} else {
SUCCEED("Gpu doesnt support HMM! Hence skipping the test with PASS result");
}
}
+1
Просмотреть файл
@@ -10,6 +10,7 @@ set(TEST_SRC
popc.cc
ldg.cc
threadfence_system.cc
hipTestDeviceSymbol.cc
)
# skipped for windows compiler issue - Illegal instruction detected
+141
Просмотреть файл
@@ -0,0 +1,141 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description: Calling hipMemcpyTo/FromSymbolAsync() using user
declared stream obj and hipStreamPerThread*/
#include <hip_test_common.hh>
#define NUM 1024
#define SIZE 1024 * 4
__device__ int globalIn[NUM];
__device__ int globalOut[NUM];
__global__ void Assign(int* Out) {
int tid = threadIdx.x + blockIdx.x * blockDim.x;
Out[tid] = globalIn[tid];
globalOut[tid] = globalIn[tid];
}
__device__ __constant__ int globalConst[NUM];
__global__ void checkAddress(int* addr, bool* out) {
*out = (globalConst == addr);
}
TEST_CASE("Unit_hipMemcpyToSymbolAsync_ToNFrom") {
int *A, *Am, *B, *Ad, *C, *Cm;
A = new int[NUM];
B = new int[NUM];
C = new int[NUM];
for (int i = 0; i < NUM; i++) {
A[i] = -1 * i;
B[i] = 0;
C[i] = 0;
}
HIP_CHECK(hipMalloc((void**)&Ad, SIZE));
HIP_CHECK(hipHostMalloc((void**)&Am, SIZE));
HIP_CHECK(hipHostMalloc((void**)&Cm, SIZE));
for (int i = 0; i < NUM; i++) {
Am[i] = -1 * i;
Cm[i] = 0;
}
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpyToSymbolAsync(HIP_SYMBOL(globalIn), Am, SIZE, 0,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
hipLaunchKernelGGL(Assign, dim3(1, 1, 1), dim3(NUM, 1, 1), 0, 0, Ad);
HIP_CHECK(hipMemcpy(B, Ad, SIZE, hipMemcpyDeviceToHost));
HIP_CHECK(hipMemcpyFromSymbolAsync(Cm, HIP_SYMBOL(globalOut), SIZE, 0,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
for (int i = 0; i < NUM; i++) {
assert(Am[i] == B[i]);
assert(Am[i] == Cm[i]);
}
for (int i = 0; i < NUM; i++) {
A[i] = -2 * i;
B[i] = 0;
}
HIP_CHECK(hipMemcpyToSymbol(HIP_SYMBOL(globalIn), A, SIZE, 0,
hipMemcpyHostToDevice));
hipLaunchKernelGGL(Assign, dim3(1, 1, 1), dim3(NUM, 1, 1), 0, 0, Ad);
HIP_CHECK(hipMemcpy(B, Ad, SIZE, hipMemcpyDeviceToHost));
HIP_CHECK(hipMemcpyFromSymbol(C, HIP_SYMBOL(globalOut), SIZE, 0,
hipMemcpyDeviceToHost));
for (int i = 0; i < NUM; i++) {
assert(A[i] == B[i]);
assert(A[i] == C[i]);
}
for (int i = 0; i < NUM; i++) {
A[i] = -3 * i;
B[i] = 0;
}
SECTION("Calling hipMemcpyTo/FromSymbol using user declared stream obj") {
HIP_CHECK(hipMemcpyToSymbolAsync(HIP_SYMBOL(globalIn), A, SIZE, 0,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
hipLaunchKernelGGL(Assign, dim3(1, 1, 1), dim3(NUM, 1, 1), 0, 0, Ad);
HIP_CHECK(hipMemcpy(B, Ad, SIZE, hipMemcpyDeviceToHost));
HIP_CHECK(hipMemcpyFromSymbolAsync(C, HIP_SYMBOL(globalOut), SIZE, 0,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpyTo/FromSymbol using hipStreamPerThread") {
HIP_CHECK(hipMemcpyToSymbolAsync(HIP_SYMBOL(globalIn), A, SIZE, 0,
hipMemcpyHostToDevice, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
hipLaunchKernelGGL(Assign, dim3(1, 1, 1), dim3(NUM, 1, 1), 0, 0, Ad);
HIP_CHECK(hipMemcpy(B, Ad, SIZE, hipMemcpyDeviceToHost));
HIP_CHECK(hipMemcpyFromSymbolAsync(C, HIP_SYMBOL(globalOut), SIZE, 0,
hipMemcpyDeviceToHost, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
for (int i = 0; i < NUM; i++) {
assert(A[i] == B[i]);
assert(A[i] == C[i]);
}
bool *checkOkD;
bool checkOk = false;
size_t symbolSize = 0;
int *symbolAddress;
HIP_CHECK(hipGetSymbolSize(&symbolSize, HIP_SYMBOL(globalConst)));
HIP_CHECK(hipGetSymbolAddress((void**) &symbolAddress, HIP_SYMBOL(globalConst)));
HIP_CHECK(hipMalloc((void**)&checkOkD, sizeof(bool)));
hipLaunchKernelGGL(checkAddress, dim3(1, 1, 1), dim3(1, 1, 1), 0, 0, symbolAddress, checkOkD);
HIP_CHECK(hipMemcpy(&checkOk, checkOkD, sizeof(bool), hipMemcpyDeviceToHost));
HIP_CHECK(hipFree(checkOkD));
HIP_ASSERT(checkOk);
HIP_ASSERT((symbolSize == SIZE));
HIP_CHECK(hipHostFree(Am));
HIP_CHECK(hipHostFree(Cm));
HIP_CHECK(hipFree(Ad));
delete[] A;
delete[] B;
delete[] C;
}
+14 -1
Просмотреть файл
@@ -1,4 +1,4 @@
# 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
@@ -25,6 +25,19 @@ set(TEST_SRC
hipGraph.cc
hipSimpleGraphWithKernel.cc
hipGraphAddMemcpyNode.cc
hipGraphClone.cc
hipGraphInstantiateWithFlags.cc
hipGraphAddHostNode.cc
hipGraphAddMemcpyNodeFromSymbol.cc
hipGraphChildGraphNodeGetGraph.cc
hipGraphNodeFindInClone.cc
hipGraphExecHostNodeSetParams.cc
hipGraphAddMemcpyNodeToSymbol.cc
hipGraphExecMemsetNodeSetParams.cc
hipGraphMemcpyNodeSetParamsToSymbol.cc
hipGraphDestroyNode.cc
hipGraphGetNodes.cc
hipGraphGetRootNodes.cc
)
hip_add_exe_to_target(NAME GraphsTest
+312
Просмотреть файл
@@ -0,0 +1,312 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios of hipGraphAddHostNode API:
Functional:
1. Creates graph, Adds HostNode which updates the variable and validates the result
2. Create graph, Add Graphnodes and clones the graph. Add Hostnode to the cloned graph
and validate the result
3. Creates graph which performs the square of number in the kernel function and the result
is validated in the callback function of hipGraphAddHostNode API
Negative:
1) Pass pGraphNode as nullptr and verify api doesnt crash, returns error code.
2) Pass graph as nullptr and verify api doesnt crash, returns error code.
3) Pass pNodeParams as nullptr and verify api doesnt crash, returns error code.
4) Pass hipHostNodeParams::hipHostFn_t as nullptr and verify api doesn't crash, returns error code.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#define SIZE 1024
static int *B_h;
static int *D_h;
static void callbackfunc(void *A_h) {
int *A = reinterpret_cast<int *>(A_h);
for (int i = 0; i < SIZE; i++) {
A[i] = i;
}
}
static void __global__ vector_square(int *B_d, int *D_d) {
for (int i = 0; i < SIZE; i++) {
D_d[i] = B_d[i] * B_d[i];
}
}
static void vectorsquare_callback(void* ptr) {
// The callback func is not working with zero parameters
// Temporary fix for adding the below 2 lines and ticket
// has been raised for the same.
int *A = reinterpret_cast<int *>(ptr);
A++;
for (int i = 0; i < SIZE; i++) {
if (D_h[i] != B_h[i] * B_h[i]) {
INFO("Validation failed " << D_h[i] << B_h[i]);
REQUIRE(false);
}
}
}
/*
This testcase verifies the negative scenarios of
hipGraphAddHostNode API
*/
TEST_CASE("Unit_hipGraphAddHostNode_Negative") {
constexpr size_t N = 1024;
hipGraph_t graph;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
SECTION("Passing nullptr to graph node") {
REQUIRE(hipGraphAddHostNode(nullptr, graph,
nullptr,
0, &hostParams) == hipErrorInvalidValue);
}
SECTION("Passing nullptr to graph") {
REQUIRE(hipGraphAddHostNode(&hostNode, nullptr,
nullptr,
0, &hostParams) == hipErrorInvalidValue);
}
#if HT_NVIDIA
SECTION("Passing nullptr to host params") {
REQUIRE(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, nullptr) == hipErrorInvalidValue);
}
#endif
SECTION("Passing nullptr to host func") {
hostParams.fn = nullptr;
REQUIRE(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, &hostParams) == hipErrorInvalidValue);
}
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This testcase verifies hipGraphAddHostNode API in cloned graph
Creates graph, Add graph nodes and clone the graph
Add HostNode to the cloned graph and validate the result
*/
TEST_CASE("Unit_hipGraphAddHostNode_ClonedGraphwithHostNode") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyH2D_C,
memcpyD2H_AC;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_C, graph, nullptr,
0, C_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_AC, graph, nullptr,
0, A_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
hipGraph_t clonedgraph;
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
HIP_CHECK(hipGraphAddHostNode(&hostNode, clonedgraph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
&memcpyD2H_AC, 1));
// Instantiate and launch the cloned graph
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify execution result
for (size_t i = 0; i < N; i++) {
if (A_h[i] != static_cast<int>(i)) {
INFO("Validation failed i " << i << "C_h[i] "<< C_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, C_d, A_h, nullptr, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipGraphDestroy(clonedgraph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This testcase verifies the square of number by
creating graph, Add kernel node which does the square
of number and the result is validated byhipGrahAddHostNode API
*/
TEST_CASE("Unit_hipGraphAddHostNode_VectorSquare") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *A_h{nullptr}, *B_d{nullptr}, *D_d{nullptr};
int *param = reinterpret_cast<int *>(sizeof(int));;
HipTest::initArrays<int>(&A_d, &B_d, &D_d,
&A_h, &B_h, &D_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_B, memcpyH2D_D, memcpyD2H_D, kernel_vecAdd;
hipKernelNodeParams kernelNodeParams{};
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = vectorsquare_callback;
hostParams.userData = param;
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, graph, nullptr,
0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_D, graph, nullptr,
0, D_d, D_h,
Nbytes, hipMemcpyHostToDevice));
void* kernelArgs2[] = {&B_d, &D_d};
kernelNodeParams.func = reinterpret_cast<void *>(vector_square);
kernelNodeParams.gridDim = dim3(1);
kernelNodeParams.blockDim = dim3(1);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_D, graph, nullptr,
0, D_h, D_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B, &kernel_vecAdd,
1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_D, &kernel_vecAdd,
1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd,
&memcpyD2H_D, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2H_D,
&hostNode, 1));
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
HipTest::freeArrays<int>(A_d, B_d, D_d, A_h, B_h, D_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This testcase verifies the following scenario
Create graph, calls the host function and updates
the parameters in the callback function and
validates it.
*/
TEST_CASE("Unit_hipGraphAddHostNode_BasicFunc") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyD2H_AC, memcpyH2D_C;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_C, graph, nullptr,
0, C_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_AC, graph, nullptr,
0, A_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
HIP_CHECK(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2H_AC,
&hostNode, 1));
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify execution result
for (size_t i = 0; i < N; i++) {
if (A_h[i] != static_cast<int>(i)) {
INFO("Validation failed i " << i << "A_h[i] "<< A_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, C_d, A_h, nullptr, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
+262 -8
Просмотреть файл
@@ -19,18 +19,22 @@ THE SOFTWARE.
/**
Testcase Scenarios :
1) Add multiple Memcpy nodes to graph and verify node execution is
working as expected.
1) Add 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) Perform memcpy operation for 1D, 2D and 3D arrays on default device and verify the results.
3) Add 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 Peer device.
4) Perform memcpy operation for 1D, 2D and 3D arrays on Peer device and verify the results.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
/**
* Functional Test adds memcpy nodes of types H2D, D2D and D2H to graph
* and verifies execution sequence by launching graph.
*/
TEST_CASE("Unit_hipGraphAddMemcpyNode_Functional") {
#define ZSIZE 32
#define YSIZE 32
#define XSIZE 32
void validateMemcpyNode3DArray(bool peerAccess = false) {
constexpr int width{10}, height{10}, depth{10};
hipArray *devArray1, *devArray2;
hipChannelFormatKind formatKind = hipChannelFormatKindSigned;
@@ -42,6 +46,7 @@ TEST_CASE("Unit_hipGraphAddMemcpyNode_Functional") {
hipStream_t streamForGraph;
hipGraphExec_t graphExec;
HIP_CHECK(hipSetDevice(0));
int *hData = reinterpret_cast<int*>(malloc(size));
int *hOutputData = reinterpret_cast<int *>(malloc(size));
@@ -69,6 +74,12 @@ TEST_CASE("Unit_hipGraphAddMemcpyNode_Functional") {
make_hipExtent(width, height, depth), hipArrayDefault));
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
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
@@ -79,7 +90,6 @@ TEST_CASE("Unit_hipGraphAddMemcpyNode_Functional") {
myparams.dstArray = devArray1;
myparams.kind = hipMemcpyHostToDevice;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, nullptr, 0, &myparams));
dependencies.push_back(memcpyNode);
@@ -126,3 +136,247 @@ TEST_CASE("Unit_hipGraphAddMemcpyNode_Functional") {
free(hData);
free(hOutputData);
}
void validateMemcpyNode2DArray(bool peerAccess = false) {
int harray2D[YSIZE][XSIZE]{};
int harray2Dres[YSIZE][XSIZE]{};
constexpr int width{XSIZE}, height{YSIZE};
hipArray *devArray1, *devArray2;
hipChannelFormatKind formatKind = hipChannelFormatKindSigned;
hipMemcpy3DParms myparams;
hipGraph_t graph;
hipGraphNode_t memcpyNode;
std::vector<hipGraphNode_t> dependencies;
hipStream_t streamForGraph;
hipGraphExec_t graphExec;
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&streamForGraph));
// Initialize 2D object
for (int i = 0; i < YSIZE; i++) {
for (int j = 0; j < XSIZE; j++) {
harray2D[i][j] = i + j + 1;
}
}
hipChannelFormatDesc channelDesc = hipCreateChannelDesc(sizeof(int)*8,
0, 0, 0, formatKind);
// Allocate 2D device array by passing depth(0)
HIP_CHECK(hipMalloc3DArray(&devArray1, &channelDesc,
make_hipExtent(width, height, 0), hipArrayDefault));
HIP_CHECK(hipMalloc3DArray(&devArray2, &channelDesc,
make_hipExtent(width, height, 0), hipArrayDefault));
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
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.extent = make_hipExtent(width, height, 1);
myparams.srcPtr = make_hipPitchedPtr(harray2D, width * sizeof(int),
width, height);
myparams.dstArray = devArray1;
myparams.kind = hipMemcpyHostToDevice;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, nullptr, 0, &myparams));
dependencies.push_back(memcpyNode);
// Device to Device
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.srcArray = devArray1;
myparams.dstArray = devArray2;
myparams.extent = make_hipExtent(width, height, 1);
myparams.kind = hipMemcpyDeviceToDevice;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, dependencies.data(),
dependencies.size(), &myparams));
dependencies.clear();
dependencies.push_back(memcpyNode);
// Device to host
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.extent = make_hipExtent(width, height, 1);
myparams.dstPtr = make_hipPitchedPtr(harray2Dres, width * sizeof(int),
width, height);
myparams.srcArray = devArray2;
myparams.kind = hipMemcpyDeviceToHost;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, dependencies.data(),
dependencies.size(), &myparams));
// 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 < YSIZE; i++) {
for (int j = 0; j < XSIZE; j++) {
if (harray2D[i][j] != harray2Dres[i][j]) {
INFO("harray2D: " << harray2D[i][j] << "harray2Dres: "
<< harray2Dres[i][j] << " mismatch at (i,j) : " << i << j);
REQUIRE(false);
}
}
}
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
hipFreeArray(devArray1);
hipFreeArray(devArray2);
}
void validateMemcpyNode1DArray(bool peerAccess = false) {
int harray1D[XSIZE]{};
int harray1Dres[XSIZE]{};
constexpr int width{XSIZE};
hipArray *devArray1, *devArray2;
hipChannelFormatKind formatKind = hipChannelFormatKindSigned;
hipMemcpy3DParms myparams;
hipGraph_t graph;
hipGraphNode_t memcpyNode;
std::vector<hipGraphNode_t> dependencies;
hipStream_t streamForGraph;
hipGraphExec_t graphExec;
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipStreamCreate(&streamForGraph));
// Initialize 1D object
for (int i = 0; i < XSIZE; i++) {
harray1D[i] = i + 1;
}
hipChannelFormatDesc channelDesc = hipCreateChannelDesc(sizeof(int)*8,
0, 0, 0, formatKind);
// Allocate 1D device array by passing depth(0), height(0)
HIP_CHECK(hipMalloc3DArray(&devArray1, &channelDesc,
make_hipExtent(width, 0, 0), hipArrayDefault));
HIP_CHECK(hipMalloc3DArray(&devArray2, &channelDesc,
make_hipExtent(width, 0, 0), hipArrayDefault));
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
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.extent = make_hipExtent(width, 1, 1);
myparams.srcPtr = make_hipPitchedPtr(harray1D, width * sizeof(int),
width, 1);
myparams.dstArray = devArray1;
myparams.kind = hipMemcpyHostToDevice;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, nullptr, 0, &myparams));
dependencies.push_back(memcpyNode);
// Device to Device
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.srcArray = devArray1;
myparams.dstArray = devArray2;
myparams.extent = make_hipExtent(width, 1, 1);
myparams.kind = hipMemcpyDeviceToDevice;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, dependencies.data(),
dependencies.size(), &myparams));
dependencies.clear();
dependencies.push_back(memcpyNode);
// Device to host
memset(&myparams, 0x0, sizeof(hipMemcpy3DParms));
myparams.srcPos = make_hipPos(0, 0, 0);
myparams.dstPos = make_hipPos(0, 0, 0);
myparams.extent = make_hipExtent(width, 1, 1);
myparams.dstPtr = make_hipPitchedPtr(harray1Dres, width * sizeof(int),
width, 1);
myparams.srcArray = devArray2;
myparams.kind = hipMemcpyDeviceToHost;
HIP_CHECK(hipGraphAddMemcpyNode(&memcpyNode, graph, dependencies.data(),
dependencies.size(), &myparams));
// 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 < XSIZE; 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));
hipFreeArray(devArray1);
hipFreeArray(devArray2);
}
/**
* Basic Functional Tests adds memcpy nodes of types H2D, D2D and D2H to graph
* and verifies execution sequence by launching graph on default device.
* Tests also verify memcpy node addition with 1D, 2D and 3D objects.
*/
TEST_CASE("Unit_hipGraphAddMemcpyNode_BasicFunctional") {
SECTION("Memcpy with 3D array on default device") {
validateMemcpyNode3DArray();
}
SECTION("Memcpy with 2D array on default device") {
validateMemcpyNode2DArray();
}
SECTION("Memcpy with 1D array on default device") {
validateMemcpyNode1DArray();
}
}
/**
* Peer access tests adds and assigns memcpy nodes of types H2D, D2D and D2H
* to peer device. Memory allocations happen on device(0) and memcpy operations
* are performed from device(1).
* Tests also verify memcpy node addition with 1D, 2D and 3D objects.
*/
TEST_CASE("Unit_hipGraphAddMemcpyNode_PeerAccessFunctional") {
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;
}
SECTION("Memcpy with 3D array on peer device") {
validateMemcpyNode3DArray(true);
}
SECTION("Memcpy with 2D array on peer device") {
validateMemcpyNode2DArray(true);
}
SECTION("Memcpy with 1D array on peer device") {
validateMemcpyNode1DArray(true);
}
}
+435
Просмотреть файл
@@ -0,0 +1,435 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios of hipGraphAddMemcpyNodeFromSymbol API:
Functional :
1. Allocate global symbol memory, add the MemcpyNodeFromSymbol
node to the graph and verify for different memory kinds
2. Allocate const memory add the MemcpyNodeFromSymbol node to
the graph and verify for different memory kinds
3. Allocate global symbol memory and device memory in GPU-0
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
4. Allocate const symbol memory and device memory in GPU-0
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
5. Allocate global memory, Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
the behaviour
Negative :
1) Pass nullptr to graph node
2) Pass nullptr to graph
3) Pass nullptr to dependencies
4) Pass invalid numDependencies
5) Pass nullptr to dst
6) Pass nullptr to symbol
7) Pass invalid count
8) Pass offset+count greater than allocated size
9) Pass unintialized graph
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <limits>
#define SIZE 256
__device__ int globalIn[SIZE];
__device__ int globalOut[SIZE];
__device__ __constant__ int globalConst[SIZE];
__global__ void MemcpyFromSymbolKernel(int* B_d) {
for (int i = 0 ; i < SIZE; i++) {
globalIn[i] = B_d[i];
}
}
/* This testcase verifies negative scenarios of
hipGraphAddMemcpyNodeFromSymbol API */
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_Negative") {
constexpr size_t Nbytes = SIZE * sizeof(int);
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
// Adding MemcpyNodeToSymbol
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
dependencies.clear();
dependencies.push_back(memcpyToSymbolNode);
#if HT_NVIDIA
hipGraphNode_t memcpyFromSymbolNode;
SECTION("Passing nullptr to graph") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, nullptr,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to graph node") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(nullptr, graph,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing size > 1 and dependencies as nullptr") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
nullptr,
1,
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing invalid dependencies size") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
10,
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to dst") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
nullptr,
HIP_SYMBOL(globalIn), Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to source") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_d,
nullptr, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidSymbol);
}
SECTION("Passing offset+size > max size") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 10,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing Max count") {
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
std::numeric_limits<int>::max(), 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Pass Unintialized graph") {
hipGraph_t unint_graph;
REQUIRE(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, unint_graph,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
#endif
HipTest::freeArrays<int>(A_d, B_d, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This function is used to verify the following scenarios
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
hipGraphAddMemcpyNodeFromSymbol API in GPU-1 and validate the result
*/
void hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(bool device_ctxchg = false,
bool const_device_var =
false) {
constexpr size_t Nbytes = SIZE * sizeof(int);
int *A_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphExec_t graphExec;
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
if (device_ctxchg) {
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
}
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
// Adding MemcpyNodeToSymbol
if (const_device_var) {
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalConst),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
} else {
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
}
dependencies.clear();
dependencies.push_back(memcpyToSymbolNode);
// Adding MemcpyNodeFromSymbol
if (const_device_var) {
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_h,
HIP_SYMBOL(globalConst),
Nbytes, 0,
hipMemcpyDeviceToHost));
} else {
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_h,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToHost));
}
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
// Validating the result
for (int i = 0; i < SIZE; i++) {
if (B_h[i] != A_h[i]) {
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This testcase verifies allocating global symbol memory,
add the MemcpyNodeFromSymbol node to the graph and
erifying the result
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemory") {
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, false);
}
/*
This testcase verifies allocating global const symbol memory,
add the MemcpyNodeFromSymbol node to the graph and
verifying the result
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemory") {
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(false, true);
}
/*
This testcase verifies allocating global symbol memory and device variables
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
verifying the result in GPU-1
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryPeerDevice") {
int numDevices = 0;
int canAccessPeer = 0;
if (numDevices > 1) {
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, false);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
/*
This testcase verifies allocating global const symbol memory and device variables
in GPU-0 and add the MemcpyNodeFromSymbol node to the graph and
verifying the result in GPU-1
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalConstMemoryPeerDevice") {
int numDevices = 0;
int canAccessPeer = 0;
if (numDevices > 1) {
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
hipGraphAddMemcpyNodeFromSymbol_GlobalMemory(true, true);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
#endif
/*
This testcaser verifies allocating global memory,
Add MemcpyFromSymbolNode,KernelNode and memcpynode and validating
the behaviour
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeFromSymbol_GlobalMemoryWithKernel") {
constexpr size_t Nbytes = SIZE * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
hipGraphNode_t memcpyfromsymbolkernel, memcpyD2H_B;
hipKernelNodeParams kernelNodeParams{};
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphExec_t graphExec;
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
dependencies.clear();
dependencies.push_back(memcpyToSymbolNode);
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_d,
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice));
dependencies.clear();
dependencies.push_back(memcpyFromSymbolNode);
// Adding Kernel node
void* kernelArgs1[] = {&B_d};
kernelNodeParams.func =
reinterpret_cast<void *>(MemcpyFromSymbolKernel);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&memcpyfromsymbolkernel, graph,
dependencies.data(), dependencies.size(),
&kernelNodeParams));
dependencies.clear();
dependencies.push_back(memcpyfromsymbolkernel);
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
dependencies.size(), B_h, B_d,
Nbytes, hipMemcpyDeviceToHost));
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
// Validating the result
for (int i = 0; i < SIZE; i++) {
if (B_h[i] != A_h[i]) {
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, B_d, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
}
+400
Просмотреть файл
@@ -0,0 +1,400 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios of hipGraphAddMemcpyNodeToSymbol API:
Functional :
1. Allocate global symbol memory, add the MemcpyNodeToSymbol
node to the graph and verify for different memory kinds
2. Allocate const memory add the MemcpyNodeToSymbol node to
the graph and verify for different memory kinds
3. Allocate global symbol memory and device memory in GPU-0
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
4. Allocate const symbol memory and device memory in GPU-0
and perform MemcpyToSymbol from peer GPU by adding it to the graph node.
5. Allocate global memory, Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
the behaviour
Negative :
1) Pass nullptr to graph node
2) Pass nullptr to graph
3) Pass nullptr to dependencies
4) Pass invalid numDependencies
5) Pass nullptr to dst
6) Pass nullptr to symbol
7) Pass invalid count
8) Pass offset+count greater than allocated size
9) Pass unintialized graph
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <limits>
#define SIZE 256
__device__ int globalIn[SIZE];
__device__ __constant__ int globalConst[SIZE];
__global__ void MemcpyToSymbolKernel(int* B_d) {
for (int i = 0 ; i < SIZE; i++) {
B_d[i] = globalIn[i];
}
}
/* This testcase verifies negative scenarios of
hipGraphAddMemcpyNodeToSymbol API */
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_Negative") {
constexpr size_t Nbytes = SIZE * sizeof(int);
int *A_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphNode_t memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
#if HT_NVIDIA
hipGraphNode_t memcpyToSymbolNode;
SECTION("Passing nullptr to graph") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, nullptr,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_h, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to graph node") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(nullptr, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing size > 1 and dependencies as nullptr") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
nullptr,
1,
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing invalid dependencies size") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
10,
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to dst") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
nullptr,
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidSymbol);
}
SECTION("Passing nullptr to source") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
nullptr, Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing offset+size > max size") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 10,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Passing Max count") {
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d,
std::numeric_limits<int>::max(), 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
SECTION("Pass Unintialized graph") {
hipGraph_t unint_graph;
REQUIRE(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, unint_graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d,
Nbytes, 0,
hipMemcpyDeviceToDevice)
== hipErrorInvalidValue);
}
#endif
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This function is used to verify the following scenarios
1. Create global variable, allocate Memory in GPU-0 and create dependency graph of
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
2. Allocate global memory, Create dependency graph and validate the result on GPU-0
3. Allocate global const memory, Create dependency graph and validate the result on GPU-0
4. Create global const variable, allocate Memory in GPU-0 and create dependency graph of
hipGraphAddMemcpyNodeToSymbol API in GPU-1 and validate the result
*/
void hipGraphAddMemcpyNodeToSymbol_GlobalMemory(bool device_ctxchg = false,
bool const_device_var = false) {
constexpr size_t Nbytes = SIZE * sizeof(int);
int *A_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphExec_t graphExec;
hipGraphNode_t memcpyToSymbolNode, memcpyFromSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
if (device_ctxchg) {
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
}
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
// Adding MemcpyNodeToSymbol
if (const_device_var) {
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalConst),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
} else {
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
}
dependencies.clear();
dependencies.push_back(memcpyToSymbolNode);
// Adding MemcpyNodeFromSymbol
if (const_device_var) {
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_h,
HIP_SYMBOL(globalConst),
Nbytes, 0, hipMemcpyDeviceToHost));
} else {
HIP_CHECK(hipGraphAddMemcpyNodeFromSymbol(&memcpyFromSymbolNode, graph,
dependencies.data(),
dependencies.size(),
B_h,
HIP_SYMBOL(globalIn),
Nbytes, 0, hipMemcpyDeviceToHost));
}
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
// Validating the result
for (int i = 0; i < SIZE; i++) {
if (B_h[i] != A_h[i]) {
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This testcase verifies allocating global symbol memory,
add the MemcpyNodeToSymbol node to the graph and
erifying the result
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemory") {
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, false);
}
/*
This testcase verifies allocating global const symbol memory,
add the MemcpyNodeToSymbol node to the graph and
verifying the result
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemory") {
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(false, true);
}
#if HT_NVIDIA
/*
This testcase verifies allocating global symbol memory and device variables
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
verifying the result in GPU-1
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalMemoryPeerDevice") {
int numDevices = 0;
int canAccessPeer = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
if (canAccessPeer) {
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, false);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
/*
This testcase verifies allocating global const symbol memory and device variables
in GPU-0 and add the MemcpyNodeToSymbol node to the graph and
verifying the result in GPU-1
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_GlobalConstMemoryPeerDevice") {
int numDevices = 0;
int canAccessPeer = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
hipDeviceCanAccessPeer(&canAccessPeer, 0, 1);
if (canAccessPeer) {
hipGraphAddMemcpyNodeToSymbol_GlobalMemory(true, true);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
#endif
/*
This testcaser verifies allocating global memory,
Add MemcpyToSymbolNode,KernelNode and memcpynode and validating
the behaviour
*/
TEST_CASE("Unit_hipGraphAddMemcpyNodeToSymbol_MemcpyToSymbolNodeWithKernel") {
constexpr size_t Nbytes = SIZE * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, SIZE);
hipGraphNode_t memcpytosymbolkernel, memcpyD2H_B;
hipKernelNodeParams kernelNodeParams{};
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipGraphExec_t graphExec;
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
dependencies.clear();
dependencies.push_back(memcpyToSymbolNode);
// Adding Kernel node
void* kernelArgs1[] = {&B_d};
kernelNodeParams.func =
reinterpret_cast<void *>(MemcpyToSymbolKernel);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&memcpytosymbolkernel, graph,
dependencies.data(), dependencies.size(),
&kernelNodeParams));
dependencies.clear();
dependencies.push_back(memcpytosymbolkernel);
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_B, graph, dependencies.data(),
dependencies.size(), B_h, B_d,
Nbytes, hipMemcpyDeviceToHost));
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
// Validating the result
for (int i = 0; i < SIZE; i++) {
if (B_h[i] != A_h[i]) {
WARN("Validation failed B_h[i] " << B_h[i] << "A_h[i] " << A_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, B_d, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
}
+163
Просмотреть файл
@@ -0,0 +1,163 @@
/*Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios of hipGraphChildGraphNodeGetGraph API:
Functional Scenarios:
1. Get the child graph node from the original graph and execute it
Negative Scenarios:
1. Pass nullptr to graph
2. Pass nullptr to graphnode
3. Pass uninitialized graph node
4. Pass orginial graph node instead of child graph node
**/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
/*
This testcase verifies the following scenario
Create graph, add multiple child nodes and gets the
graph of one of the child nodes using hipGraphChildGraphNodeGetGraph API
executes it and validates the results
*/
TEST_CASE("Unit_hipGraphChildGraphNodeGetGraph_Functional") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
size_t NElem{N};
constexpr auto threadsPerBlock = 256;
hipGraph_t graph, childgraph1, childgraph2;
hipGraphExec_t graphExec;
hipKernelNodeParams kernelNodeParams{};
hipGraphNode_t kernel_vecAdd;
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyH2D_B, childGraphNode1,
childGraphNode2, memcpyD2H_C;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphCreate(&childgraph1, 0));
HIP_CHECK(hipGraphCreate(&childgraph2, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, childgraph1, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, childgraph2, nullptr,
0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddChildGraphNode(&childGraphNode1, graph,
nullptr, 0, childgraph1));
HIP_CHECK(hipGraphAddChildGraphNode(&childGraphNode2, graph,
nullptr, 0, childgraph2));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C, graph, nullptr,
0, C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
void* kernelArgs2[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
HIP_CHECK(hipGraphAddDependencies(graph, &childGraphNode1,
&childGraphNode2, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &childGraphNode2,
&kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2H_C, 1));
hipGraph_t Getgraph;
HIP_CHECK(hipGraphChildGraphNodeGetGraph(childGraphNode1, &Getgraph));
// Instantiate and launch the child graph
HIP_CHECK(hipGraphInstantiate(&graphExec, Getgraph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify child graph execution result
HIP_CHECK(hipMemcpy(C_h, A_d, Nbytes, hipMemcpyDeviceToHost));
for (size_t i = 0; i < N; i++) {
if (A_h[i] != C_h[i]) {
INFO("Validation failed " << A_h[i] << C_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(childgraph2));
HIP_CHECK(hipGraphDestroy(childgraph1));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This testcase verifies the negative scenarios
of hipGraphChildGraphNodeGetGraph API
*/
TEST_CASE("Unit_hipGraphChildGraphNodeGetGraph_Negative") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph, childgraph1;
int *A_d{nullptr}, *B_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr}, *C_h{nullptr};
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, childGraphNode1;
HIP_CHECK(hipGraphCreate(&childgraph1, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, childgraph1, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddChildGraphNode(&childGraphNode1, graph,
nullptr, 0, childgraph1));
hipGraph_t Getgraph;
SECTION("nullptr to child node") {
REQUIRE((hipGraphChildGraphNodeGetGraph(nullptr, &Getgraph))
== hipErrorInvalidValue);
}
#if HT_NVIDIA
SECTION("nullptr to graph") {
REQUIRE((hipGraphChildGraphNodeGetGraph(childGraphNode1, nullptr))
== hipErrorInvalidValue);
}
SECTION("Passing parent instead of child graph node") {
REQUIRE((hipGraphChildGraphNodeGetGraph(memcpyH2D_A, &Getgraph))
== hipErrorInvalidValue);
}
SECTION("Passing unintialized node") {
hipGraphNode_t unint_node;
REQUIRE((hipGraphChildGraphNodeGetGraph(unint_node, &Getgraph))
== hipErrorInvalidValue);
}
#endif
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphDestroy(childgraph1));
}
+319
Просмотреть файл
@@ -0,0 +1,319 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Testcase Scenarios of hipGraphClone API:
Negative:
1. Pass nullptr to cloned graph
2. pass nullptr to original graph
Functional:
1. Clone the graph,Instantiate and execute the cloned graph
2. Clone the graph and modify the original graph and ensure that the
cloned graph is not modified
3. Create graph on one GPU device and clone it from peer GPU device
4. Create graph in one thread and clone it from multiple threads.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
#define NUM_THREADS 10
/* This test covers the negative scenarios of
hipGraphClone API */
TEST_CASE("Unit_hipGraphClone_Negative") {
SECTION("Passing nullptr to Cloned graph") {
hipGraph_t graph;
HIP_CHECK(hipGraphCreate(&graph, 0));
REQUIRE(hipGraphClone(nullptr, graph) == hipErrorInvalidValue);
HIP_CHECK(hipGraphDestroy(graph));
}
SECTION("Passing nullptr to original graph") {
hipGraph_t clonedGraph;
REQUIRE(hipGraphClone(&clonedGraph, nullptr) == hipErrorInvalidValue);
}
}
/*
This function creates the graph with dependencies
then performs device context change and clones the cloned graph
Executes the cloned graph and validates the result
*/
void hipGraphClone_DeviceContextChange() {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph, clonedgraph;
hipGraphExec_t graphExec;
hipStream_t streamForGraph;
hipGraphNode_t memcpyH2D_A, memcpyD2H_A;
int *A_d{nullptr}, *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_A, graph, nullptr, 0, B_h, A_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &memcpyD2H_A, 1));
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
// Instantiate and launch the original graph
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
for (size_t i = 0; i < N; i++) {
if (A_h[i] != B_h[i]) {
INFO("Validation failed A_h[i] " << A_h[i] << " B_h[i] " << B_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, nullptr, A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipGraphDestroy(clonedgraph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This function does the following
1. Creates the graph with multiple dependencies
clones the graph and validates the result.
2. Creates the graph, clones the graph and modifies
the existing graph and execute the cloned graph
to ensure that cloned graph is not modified
*/
void hipGraphClone_Func(bool ModifyOrigGraph = false) {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
hipGraph_t graph, clonedgraph;
hipGraphNode_t memset_A, memset_B, memsetKer_C;
hipGraphNode_t memcpyH2D_A, memcpyH2D_B, memcpyD2H_C, memcpyD2D_C,
memcpyD2H_C_new;
hipGraphNode_t kernel_vecAdd;
hipKernelNodeParams kernelNodeParams{};
hipStream_t streamForGraph;
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
hipGraphExec_t graphExec;
hipMemsetParams memsetParams{};
int memsetVal{};
size_t NElem{N};
HIP_CHECK(hipStreamCreate(&streamForGraph));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(A_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_A, graph, nullptr, 0,
&memsetParams));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(B_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_B, graph, nullptr, 0,
&memsetParams));
void* kernelArgs1[] = {&C_d, &memsetVal, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func =
reinterpret_cast<void *>(HipTest::memsetReverse<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&memsetKer_C, graph, nullptr, 0,
&kernelNodeParams));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, graph, nullptr, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C, graph, nullptr, 0, C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
void* kernelArgs2[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
// Create dependencies
HIP_CHECK(hipGraphAddDependencies(graph, &memset_A, &memcpyH2D_A, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memset_B, &memcpyH2D_B, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memsetKer_C, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2H_C, 1));
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
if (ModifyOrigGraph) {
// Modify Original graph by adding new dependency
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2D_C, graph, nullptr, 0,
C_d, B_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C_new, graph, nullptr, 0,
C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2D_C, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2D_C,
&memcpyD2H_C_new, 1));
// Instantiate and launch the original graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
for (size_t i= 0; i < NElem; i++) {
if (C_h[i] != B_h[i]) {
INFO("Validation failed C_h is " << C_h[i] <<
"B_h is " << B_h[i]);
REQUIRE(false);
}
}
}
// Instantiate and launch the cloned graph
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify graph execution result
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipGraphDestroy(clonedgraph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This testcase verifies following scenarios
1. Clones the graph and verify the result
2. Clones the graph, Modify the original graph and
validate the result of the cloned graph
3. Device context change for cloned graph
*/
TEST_CASE("Unit_hipGraphClone_Functional") {
SECTION("hipGraphClone Basic Functionality") {
hipGraphClone_Func();
}
SECTION("hipGraphClone Modify Original graph") {
hipGraphClone_Func(true);
}
SECTION("hipGraphClone Device context change") {
int numDevices = 0;
int canAccessPeer = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
hipGraphClone_DeviceContextChange();
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
}
/*
This testcase creates the graph with dependencies
then creates multiple threads and clones the graph
in each thread and executes the cloned graph
hipGraphClone is failing in CUDA in multi threaded
scenario so excluded for nvidia
*/
#if HT_AMD
TEST_CASE("Unit_hipGraphClone_MultiThreaded") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphNode_t memcpyH2D_A, memcpyD2H_A;
int *A_d{nullptr}, *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, nullptr,
&A_h, &B_h, nullptr, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_A, graph, nullptr, 0, B_h, A_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &memcpyD2H_A, 1));
std::vector<std::thread> threads;
auto lambdaFunc = [&](){
hipGraph_t clonedgraph;
hipGraphExec_t graphExec;
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
// Instantiate and launch the cloned graph
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr,
nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
for (size_t i = 0; i < N; i++) {
if (A_h[i] != B_h[i]) {
INFO("Validation failed A_h[i] " << A_h[i] << " B_h[i] " << B_h[i]);
REQUIRE(false);
}
}
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(clonedgraph));
};
for (int i = 0; i < NUM_THREADS; i++) {
std::thread t(lambdaFunc);
threads.push_back(std::move(t));
}
for (auto &t : threads) {
t.join();
}
HipTest::freeArrays<int>(A_d, nullptr, nullptr, A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphDestroy(graph));
}
#endif
+139
Просмотреть файл
@@ -0,0 +1,139 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Testcase Scenarios of hipGraphDestroyNode API:
Negative ::
1) Pass nullptr to graph node
Functional ::
1) Create Node and destroy the node
2) Create graph with dependencies and destroy one of the dependency node
before executing the graph.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
/* This test covers the negative scenarios of
hipGraphDestroyNode API */
TEST_CASE("Unit_hipGraphDestroyNode_Negative") {
SECTION("Passing nullptr to graph Node") {
REQUIRE(hipGraphDestroyNode(nullptr) == hipErrorInvalidValue);
}
}
/* This test covers the basic functionality of
hipGraphDestroyNode API where we create and destroy
the node
*/
TEST_CASE("Unit_hipGraphDestroyNode_BasicFunctionality") {
char *pOutBuff_d{};
constexpr size_t size = 1024;
hipGraph_t graph{};
hipGraphNode_t memsetNode{};
HIP_CHECK(hipMalloc(&pOutBuff_d, size));
hipMemsetParams memsetParams{};
memsetParams.dst = reinterpret_cast<void*>(pOutBuff_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = size * sizeof(char);
memsetParams.height = 1;
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
&memsetParams));
REQUIRE(hipGraphDestroyNode(memsetNode) == hipSuccess);
HIP_CHECK(hipFree(pOutBuff_d));
}
/*
This testcase verifies the following scenario where
graph is created with dependencies and one of the dependency is
destroyed before execute the graph
*/
TEST_CASE("Unit_hipGraphDestroyNode_DestroyDependencyNode") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
hipGraph_t graph;
hipGraphNode_t memcpyH2D_A, memcpyH2D_B, memcpyH2D_B2Copies, memcpyD2H_C;
hipGraphNode_t kernel_vecAdd;
hipKernelNodeParams kernelNodeParams{};
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
hipGraphExec_t graphExec;
size_t NElem{N};
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, graph, nullptr, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B2Copies, graph, nullptr,
0, B_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C, graph, nullptr, 0, B_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
void* kernelArgs2[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
// Create dependencies
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B2Copies, &kernel_vecAdd,
1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2H_C, 1));
// Destroy one of the dependency node
HIP_CHECK(hipGraphDestroyNode(memcpyH2D_B));
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify graph execution result
HipTest::checkVectorADD(A_h, C_h, B_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipStreamDestroy(streamForGraph));
HIP_CHECK(hipGraphDestroy(graph));
}
+276
Просмотреть файл
@@ -0,0 +1,276 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios of hipGraphExecHostNodeSetParams API:
Functional:
1. Creates graph, Adds HostNode, update hostNode params using hipGraphExecHostNodeSetParams API
and validates the result
2. Create graph, Add Graphnodes and clones the graph. Add Hostnode to the cloned graph, update
hostNode params using hipGraphExecHostNodeSetParams API and validate the result
Negative:
1) Pass hGraphExec as nullptr and verify api doen't crash, returns error code.
2) Pass node as nullptr and verify api doen't crash, returns error code.
3) Pass pNodeParams as nullptr and verify api doesn't crash, returns error code.
3) Pass hipHostNodeParams::hipHostFn_t as nullptr and verify api doesn't crash, returns error code.
4) Pass unintialized host params and verify api doesn't crash, returns error code.
5) Pass unintialized graph and verify api doesn't crash, returns error code.
6) Pass nullptr to hostfunc and verify api doesn't crash, returns error code.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#define SIZE 1024
void callbackfunc(void *A_h) {
int *A = reinterpret_cast<int *>(A_h);
for (int i = 0; i < SIZE; i++) {
A[i] = i;
}
}
void callbackfunc_setparams(void *B_h) {
int *B = reinterpret_cast<int *>(B_h);
for (int i = 0; i < SIZE; i++) {
B[i] = i * i;
}
}
/*
This testcase verifies the negative scenarios of
hipGraphExecHostNodeSetParams API
*/
TEST_CASE("Unit_hipGraphExecHostNodeSetParams_Negative") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyD2H_AC, memcpyH2D_C;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_C, graph, nullptr,
0, C_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_AC, graph, nullptr,
0, A_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
HIP_CHECK(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2H_AC,
&hostNode, 1));
hipHostNodeParams sethostParams = {0, 0};
sethostParams.fn = callbackfunc_setparams;
sethostParams.userData = C_h;
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
#if HT_NVIDIA
SECTION("Passing nullptr to graphExec") {
REQUIRE(hipGraphExecHostNodeSetParams(nullptr, hostNode, &sethostParams)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to hostParams") {
REQUIRE(hipGraphExecHostNodeSetParams(graphExec, hostNode, nullptr)
== hipErrorInvalidValue);
}
#endif
SECTION("Passing nullptr to graph") {
REQUIRE(hipGraphExecHostNodeSetParams(graphExec, nullptr, &sethostParams)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to host func") {
sethostParams.fn = nullptr;
REQUIRE(hipGraphExecHostNodeSetParams(graphExec, hostNode, &sethostParams)
== hipErrorInvalidValue);
}
SECTION("Passing unintialized hostParams") {
hipHostNodeParams unintParams = {0, 0};
REQUIRE(hipGraphExecHostNodeSetParams(graphExec, hostNode, &unintParams)
== hipErrorInvalidValue);
}
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This testcase verifies hipGraphExecHostNodeSetParams API in cloned graph
Creates graph, Add graph nodes and clone the graph
Add HostNode to the cloned graph,update the host params using
hipGraphExecHostNodeSetParams API and validates the result
*/
TEST_CASE("Unit_hipGraphExecHostNodeSetParams_ClonedGraphwithHostNode") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyH2D_C,
memcpyD2H_AC;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_C, graph, nullptr,
0, C_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_AC, graph, nullptr,
0, A_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
hipGraph_t clonedgraph;
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
HIP_CHECK(hipGraphAddHostNode(&hostNode, clonedgraph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
&memcpyD2H_AC, 1));
hipHostNodeParams sethostParams = {0, 0};
sethostParams.fn = callbackfunc_setparams;
sethostParams.userData = C_h;
// Instantiate and launch the cloned graph
HIP_CHECK(hipGraphInstantiate(&graphExec, clonedgraph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphExecHostNodeSetParams(graphExec, hostNode, &sethostParams));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify execution result
for (size_t i = 0; i < N; i++) {
if (C_h[i] != static_cast<int>(i * i)) {
INFO("Validation failed i " << i << "C_h[i] "<< C_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, C_d, A_h, nullptr, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/*
This testcase verifies the following scenario
Create graph, Adds host node to the graph,
updates the host params using hipGraphExecHostNodeSetParams API
and validates the result
*/
TEST_CASE("Unit_hipGraphExecHostNodeSetParams_BasicFunc") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
hipGraph_t graph;
hipGraphExec_t graphExec;
int *A_d{nullptr}, *C_d{nullptr};
int *A_h{nullptr}, *C_h{nullptr};
HipTest::initArrays<int>(&A_d, nullptr, &C_d,
&A_h, nullptr, &C_h, N, false);
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphNode_t memcpyH2D_A, memcpyD2H_AC, memcpyH2D_C;
hipStream_t streamForGraph;
HIP_CHECK(hipStreamCreate(&streamForGraph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr,
0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_C, graph, nullptr,
0, C_d, C_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_AC, graph, nullptr,
0, A_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0, 0};
hostParams.fn = callbackfunc;
hostParams.userData = A_h;
HIP_CHECK(hipGraphAddHostNode(&hostNode, graph,
nullptr,
0, &hostParams));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_C,
&memcpyD2H_AC, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2H_AC,
&hostNode, 1));
hipHostNodeParams sethostParams = {0, 0};
sethostParams.fn = callbackfunc_setparams;
sethostParams.userData = C_h;
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
HIP_CHECK(hipGraphExecHostNodeSetParams(graphExec, hostNode, &sethostParams));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify execution result
for (size_t i = 0; i < N; i++) {
if (C_h[i] != static_cast<int >(i * i)) {
INFO("Validation failed i " << i << "C_h[i] "<< C_h[i]);
REQUIRE(false);
}
}
HipTest::freeArrays<int>(A_d, nullptr, C_d, A_h, nullptr, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
+201
Просмотреть файл
@@ -0,0 +1,201 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios :
Functional-
1) Instantiate a graph with memset node, obtain executable graph and update the
hipMemsetParams node params with set. Make sure they are taking effect.
Negative-
1) Pass hGraphExec as nullptr and verify api returns error code.
2) Pass graph node as nullptr and verify api returns error code.
3) Pass different hipGraphNode_t which was not used in graphExec and verify api returns error code.
4) Pass Pass different Graph which was not used in graphExec and verify api returns error code.
5) Pass pNodeParams as nullptr and verify api returns error code.
6) Pass pNodeParams as empty structure object and verify api returns error code.
7) Pass hipMemsetParams::dst as nullptr, api should return error code.
8) Pass hipMemsetParams::element size other than 1, 2, or 4 and check api should return error code.
9) Pass hipMemsetParams::height as zero and check api should return error code.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
/* Test verifies hipGraphExecMemsetNodeSetParams API Negative scenarios.
*/
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Negative") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(char);
constexpr size_t val = 0;
char *devData, *hOutputData;
HIP_CHECK(hipMalloc(&devData, Nbytes));
hOutputData = reinterpret_cast<char *>(malloc(Nbytes));
REQUIRE(hOutputData != nullptr);
memset(hOutputData, 0, Nbytes);
hipGraph_t graph;
hipError_t ret;
hipGraphExec_t graphExec;
hipStream_t streamForGraph;
hipGraphNode_t memsetNode;
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipStreamCreate(&streamForGraph));
hipMemsetParams mParams{};
memset(&mParams, 0, sizeof(mParams));
mParams.dst = reinterpret_cast<void*>(devData);
mParams.value = val;
mParams.pitch = 0;
mParams.elementSize = sizeof(char);
mParams.width = Nbytes;
mParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0, &mParams));
std::vector<hipGraphNode_t> dependencies;
dependencies.push_back(memsetNode);
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
SECTION("Pass hGraphExec as nullptr") {
ret = hipGraphExecMemsetNodeSetParams(nullptr, memsetNode, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass hGraphNode as nullptr") {
ret = hipGraphExecMemsetNodeSetParams(graphExec, nullptr, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass different hGraphNode which was not used in graphExec") {
hipGraphNode_t memsetNode1{};
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode1, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass different Graph which was not used in graphExec") {
hipGraph_t graph1;
HIP_CHECK(hipGraphCreate(&graph1, 0));
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph1, nullptr, 0, &mParams));
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
HIP_CHECK(hipGraphDestroy(graph1));
}
SECTION("Pass pNodeParams as nullptr") {
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, nullptr);
REQUIRE(hipErrorInvalidValue == ret);
}
#if HT_NVIDIA
SECTION("Pass pNodeParams as empty structure object") {
hipMemsetParams mParmTemp{};
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParmTemp);
REQUIRE(hipErrorInvalidValue == ret);
}
#endif
SECTION("Pass hipMemsetParams::dst as nullptr") {
mParams.dst = nullptr;
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
#if HT_NVIDIA
SECTION("Pass hipMemsetParams::element size other than 1, 2, or 4") {
mParams.dst = reinterpret_cast<void*>(devData);
mParams.elementSize = 9;
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass hipMemsetParams::height as zero") {
mParams.elementSize = sizeof(char);
mParams.height = 0;
ret = hipGraphExecMemsetNodeSetParams(graphExec, memsetNode, &mParams);
REQUIRE(hipErrorInvalidValue == ret);
}
#endif
free(hOutputData);
HIP_CHECK(hipFree(devData));
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
/* Test verifies hipGraphExecMemsetNodeSetParams API Functional scenarios.
*/
TEST_CASE("Unit_hipGraphExecMemsetNodeSetParams_Functional") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(char);
constexpr size_t val = 0;
constexpr size_t updateVal = 2;
char *devData, *devData1, *hOutputData, *hOutputData1;
HIP_CHECK(hipMalloc(&devData, Nbytes));
HIP_CHECK(hipMalloc(&devData1, Nbytes));
hOutputData = reinterpret_cast<char *>(malloc(Nbytes));
REQUIRE(hOutputData != nullptr);
memset(hOutputData, updateVal, Nbytes);
hOutputData1 = reinterpret_cast<char *>(malloc(Nbytes));
REQUIRE(hOutputData1 != nullptr);
memset(hOutputData1, 0, Nbytes);
hipGraph_t graph;
hipGraphExec_t graphExec;
hipStream_t streamForGraph;
hipGraphNode_t memsetNode;
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipStreamCreate(&streamForGraph));
hipMemsetParams memsetParams{};
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(devData);
memsetParams.value = val;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memsetNode, graph, nullptr, 0,
&memsetParams));
std::vector<hipGraphNode_t> dependencies;
dependencies.push_back(memsetNode);
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, nullptr, nullptr, 0));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(devData1);
memsetParams.value = updateVal;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
REQUIRE(hipSuccess == hipGraphExecMemsetNodeSetParams(graphExec, memsetNode,
&memsetParams));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
HIP_CHECK(hipMemcpy(hOutputData1, devData1, Nbytes, hipMemcpyDeviceToHost));
HipTest::checkArray(hOutputData, hOutputData1, Nbytes, 1);
free(hOutputData);
free(hOutputData1);
HIP_CHECK(hipFree(devData));
HIP_CHECK(hipFree(devData1));
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
}
+219
Просмотреть файл
@@ -0,0 +1,219 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios
------------------
Functional ::
1) Add nodes to graph and get nodes. Verify the added nodes are present in returned list.
2) Pass nodes as nullptr and verify numNodes returns actual number of nodes added to graph.
3) If numNodes passed is greater than the actual number of nodes, the remaining entries in nodes
will be set to NULL, and the number of nodes actually obtained will be returned in numNodes.
Argument Validation ::
1) Pass graph as nullptr and verify api returns error code.
2) Pass numNodes as nullptr and other params as valid values. Expect api to return error code.
3) When there are no nodes in graph, expect numNodes to be set to zero.
4) Pass numNodes less than actual number of nodes. Expect api to populate requested number of node entries
and does update numNodes.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
/**
* Functional Test for hipGraphGetNodes API fetching node list
*/
TEST_CASE("Unit_hipGraphGetNodes_Functional") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
constexpr auto addlEntries = 4;
hipGraph_t graph;
hipGraphNode_t memcpyNode, kernelNode;
hipKernelNodeParams kernelNodeParams{};
hipStream_t streamForGraph;
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
std::vector<hipGraphNode_t> dependencies, nodelist;
hipGraphExec_t graphExec;
size_t NElem{N};
HIP_CHECK(hipStreamCreate(&streamForGraph));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
nodelist.push_back(memcpyNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
nodelist.push_back(memcpyNode);
void* kernelArgs[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernelNode, graph, dependencies.data(),
dependencies.size(), &kernelNodeParams));
dependencies.clear();
dependencies.push_back(kernelNode);
nodelist.push_back(kernelNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, dependencies.data(),
dependencies.size(), C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
nodelist.push_back(memcpyNode);
// Get numNodes by passing nodes as nullptr.
// verify : numNodes is set to actual number of nodes added
size_t numNodes{};
HIP_CHECK(hipGraphGetNodes(graph, nullptr, &numNodes));
INFO("Num of nodes returned by GetNodes : " << numNodes);
REQUIRE(numNodes == nodelist.size());
// Request for extra/additional nodes.
// verify : totNodes is reset to actual number of nodes
// verify : additional entries in nodes are set to nullptr
size_t totNodes = numNodes + addlEntries;
int numBytes = sizeof(hipGraphNode_t) * totNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
REQUIRE(nodes != nullptr);
HIP_CHECK(hipGraphGetNodes(graph, nodes, &totNodes));
REQUIRE(totNodes == nodelist.size());
for (auto i = numNodes; i < numNodes + addlEntries; i++) {
REQUIRE(nodes[i] == nullptr);
}
// Verify added nodes are present in the node entries returned
for (auto Node : nodelist) {
bool found = false;
for (size_t i = 0; i < numNodes; i++) {
if (Node == nodes[i]) {
found = true;
break;
}
}
if (!found) {
INFO("Added node " << Node << " not present in returned list");
REQUIRE(false);
}
}
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify graph execution result
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
free(nodes);
}
/**
* Test performs api parameter validation by passing various values
* as input and output parameters and validates the behavior.
* Test will include both negative and positive scenarios.
*/
TEST_CASE("Unit_hipGraphGetNodes_ParamValidation") {
hipStream_t stream{nullptr};
hipGraph_t graph{nullptr};
constexpr unsigned blocks = 512;
constexpr unsigned threadsPerBlock = 256;
constexpr size_t N = 1000000;
size_t Nbytes = N * sizeof(float), numNodes{};
float *A_d, *C_d;
float *A_h, *C_h;
A_h = reinterpret_cast<float*>(malloc(Nbytes));
C_h = reinterpret_cast<float*>(malloc(Nbytes));
REQUIRE(A_h != nullptr);
REQUIRE(C_h != nullptr);
HIP_CHECK(hipMalloc(&A_d, Nbytes));
HIP_CHECK(hipMalloc(&C_d, Nbytes));
REQUIRE(A_d != nullptr);
REQUIRE(C_d != nullptr);
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamEndCapture(stream, &graph));
HIP_CHECK(hipGraphGetNodes(graph, nullptr, &numNodes));
INFO("Num of nodes returned by GetNodes : " << numNodes);
int numBytes = sizeof(hipGraphNode_t) * numNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
REQUIRE(nodes != nullptr);
SECTION("graph as nullptr") {
hipError_t ret = hipGraphGetNodes(nullptr, nodes, &numNodes);
REQUIRE(ret == hipErrorInvalidValue);
}
SECTION("numNodes as nullptr") {
hipError_t ret = hipGraphGetNodes(graph, nodes, nullptr);
REQUIRE(ret == hipErrorInvalidValue);
}
SECTION("no nodes in graph") {
hipGraph_t emptyGraph{};
HIP_CHECK(hipGraphCreate(&emptyGraph, 0));
HIP_CHECK(hipGraphGetNodes(emptyGraph, nullptr, &numNodes));
REQUIRE(numNodes == 0);
}
SECTION("numNodes less than actual number of nodes") {
size_t numPartNodes = numNodes - 1;
hipGraphNodeType nodeType;
HIP_CHECK(hipGraphGetNodes(graph, nodes, &numPartNodes));
// verify numPartNodes is unchanged
REQUIRE(numPartNodes == numNodes - 1);
// verify partial node list returned has valid nodes
for (size_t i = 0; i < numPartNodes; i++) {
HIP_CHECK(hipGraphNodeGetType(nodes[i], &nodeType));
REQUIRE(nodeType >= 0);
REQUIRE(nodeType < hipGraphNodeTypeCount);
}
}
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(stream));
free(A_h);
free(C_h);
free(nodes);
HIP_CHECK(hipFree(A_d));
HIP_CHECK(hipFree(C_d));
}
+239
Просмотреть файл
@@ -0,0 +1,239 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios
------------------
Functional ::
1) Add nodes to graph with and without dependencies, verify the api returns list of
root nodes (i.e., nodes without dependencies).
2) Pass nodes as nullptr and verify api returns actual number of root nodes added to graph.
3) If NumRootNodes passed is greater than the actual number of root nodes, the remaining entries in
nodes list will be set to NULL, and the number of nodes actually obtained will be returned in NumRootNodes.
Argument Validation ::
1) Pass graph as nullptr and verify api returns error code.
2) Pass numRootNodes as nullptr and other params as valid values. Expect api to return error code.
3) When there are no nodes in graph, expect numRootNodes to be set to zero.
4) Pass numRootNodes less than actual number of nodes. Expect api to populate requested number of node entries
and does update numRootNodes.
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
/**
* Functional Test for API fetching root node list
*/
TEST_CASE("Unit_hipGraphGetRootNodes_Functional") {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
constexpr auto addlEntries = 5;
hipGraph_t graph;
hipGraphNode_t memcpyNode, kernelNode;
hipKernelNodeParams kernelNodeParams{};
hipStream_t streamForGraph;
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
std::vector<hipGraphNode_t> dependencies, rootnodelist;
hipGraphExec_t graphExec;
size_t NElem{N};
HIP_CHECK(hipStreamCreate(&streamForGraph));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
rootnodelist.push_back(memcpyNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, NULL, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyNode);
rootnodelist.push_back(memcpyNode);
void* kernelArgs[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernelNode, graph, dependencies.data(),
dependencies.size(), &kernelNodeParams));
dependencies.clear();
dependencies.push_back(kernelNode);
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyNode, graph, dependencies.data(),
dependencies.size(), C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
// Get numRootNodes by passing rootnodes list as nullptr.
// verify : numRootNodes is set to actual number of root nodes added
size_t numRootNodes{};
HIP_CHECK(hipGraphGetRootNodes(graph, nullptr, &numRootNodes));
INFO("Num of nodes returned by GetRootNodes : " << numRootNodes);
REQUIRE(numRootNodes == rootnodelist.size());
// Request for extra/additional nodes.
// verify : totNodes is reset to actual number of root nodes present
// verify : additional entries in rootnodes list are set to nullptr
size_t totNodes = numRootNodes + addlEntries;
int numBytes = sizeof(hipGraphNode_t) * totNodes;
hipGraphNode_t* rootnodes =
reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
REQUIRE(rootnodes != nullptr);
HIP_CHECK(hipGraphGetRootNodes(graph, rootnodes, &totNodes));
REQUIRE(totNodes == rootnodelist.size());
for (auto i = numRootNodes; i < numRootNodes + addlEntries; i++) {
REQUIRE(rootnodes[i] == nullptr);
}
// Verify added nodes(without dependencies) are present
// in the root nodes fetched.
for (auto Node : rootnodelist) {
bool found = false;
for (size_t i = 0; i < numRootNodes; i++) {
if (Node == rootnodes[i]) {
found = true;
break;
}
}
if (!found) {
INFO("Returned root node " << Node << " not present in added list");
REQUIRE(false);
}
}
// Instantiate and launch the graph
HIP_CHECK(hipGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
HIP_CHECK(hipGraphLaunch(graphExec, streamForGraph));
HIP_CHECK(hipStreamSynchronize(streamForGraph));
// Verify graph execution result
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(streamForGraph));
free(rootnodes);
}
/**
* Test performs api parameter validation by passing various values
* as input and output parameters and validates the behavior.
* Test will include both negative and positive scenarios.
*/
TEST_CASE("Unit_hipGraphGetRootNodes_ParamValidation") {
hipStream_t stream1{nullptr}, stream2{nullptr}, mstream{nullptr};
hipEvent_t memsetEvent1, memsetEvent2, forkStreamEvent;
hipGraph_t graph{nullptr};
constexpr unsigned blocks = 512;
constexpr unsigned threadsPerBlock = 256;
constexpr size_t N = 1000000;
size_t Nbytes = N * sizeof(float), numRootNodes{};
float *A_d, *C_d;
float *A_h, *C_h;
A_h = reinterpret_cast<float*>(malloc(Nbytes));
C_h = reinterpret_cast<float*>(malloc(Nbytes));
REQUIRE(A_h != nullptr);
REQUIRE(C_h != nullptr);
HIP_CHECK(hipMalloc(&A_d, Nbytes));
HIP_CHECK(hipMalloc(&C_d, Nbytes));
REQUIRE(A_d != nullptr);
REQUIRE(C_d != nullptr);
HIP_CHECK(hipStreamCreate(&stream1));
HIP_CHECK(hipStreamCreate(&stream2));
HIP_CHECK(hipStreamCreate(&mstream));
HIP_CHECK(hipEventCreate(&memsetEvent1));
HIP_CHECK(hipEventCreate(&memsetEvent2));
HIP_CHECK(hipEventCreate(&forkStreamEvent));
HIP_CHECK(hipStreamBeginCapture(mstream, hipStreamCaptureModeGlobal));
HIP_CHECK(hipEventRecord(forkStreamEvent, mstream));
HIP_CHECK(hipStreamWaitEvent(stream1, forkStreamEvent, 0));
HIP_CHECK(hipStreamWaitEvent(stream2, forkStreamEvent, 0));
HIP_CHECK(hipMemsetAsync(A_d, 0, Nbytes, stream1));
HIP_CHECK(hipEventRecord(memsetEvent1, stream1));
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream2));
HIP_CHECK(hipEventRecord(memsetEvent2, stream2));
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent1, 0));
HIP_CHECK(hipStreamWaitEvent(mstream, memsetEvent2, 0));
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, mstream));
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, mstream, A_d, C_d, N);
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, mstream));
HIP_CHECK(hipStreamEndCapture(mstream, &graph));
HIP_CHECK(hipGraphGetRootNodes(graph, nullptr, &numRootNodes));
INFO("Num of nodes returned by GetRootNodes : " << numRootNodes);
int numBytes = sizeof(hipGraphNode_t) * numRootNodes;
hipGraphNode_t* nodes = reinterpret_cast<hipGraphNode_t *>(malloc(numBytes));
REQUIRE(nodes != nullptr);
SECTION("graph as nullptr") {
hipError_t ret = hipGraphGetRootNodes(nullptr, nodes, &numRootNodes);
REQUIRE(ret == hipErrorInvalidValue);
}
SECTION("numRootNodes as nullptr") {
hipError_t ret = hipGraphGetRootNodes(graph, nodes, nullptr);
REQUIRE(ret == hipErrorInvalidValue);
}
SECTION("no nodes in graph") {
hipGraph_t emptyGraph{};
HIP_CHECK(hipGraphCreate(&emptyGraph, 0));
HIP_CHECK(hipGraphGetRootNodes(emptyGraph, nullptr, &numRootNodes));
REQUIRE(numRootNodes == 0);
}
SECTION("numRootNodes less than actual number of nodes") {
size_t numPartNodes = numRootNodes - 1;
hipGraphNodeType nodeType;
HIP_CHECK(hipGraphGetRootNodes(graph, nodes, &numPartNodes));
// verify numPartNodes is unchanged
REQUIRE(numPartNodes == numRootNodes - 1);
// verify partial node list returned has valid nodes
for (size_t i = 0; i < numPartNodes; i++) {
HIP_CHECK(hipGraphNodeGetType(nodes[i], &nodeType));
REQUIRE(nodeType >= 0);
REQUIRE(nodeType < hipGraphNodeTypeCount);
}
}
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipStreamDestroy(mstream));
HIP_CHECK(hipStreamDestroy(stream1));
HIP_CHECK(hipStreamDestroy(stream2));
HIP_CHECK(hipEventDestroy(forkStreamEvent));
HIP_CHECK(hipEventDestroy(memsetEvent1));
HIP_CHECK(hipEventDestroy(memsetEvent2));
free(A_h);
free(C_h);
free(nodes);
HIP_CHECK(hipFree(A_d));
HIP_CHECK(hipFree(C_d));
}
+304
Просмотреть файл
@@ -0,0 +1,304 @@
/*
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.
*/
/*
hipGraphInstantiateWithFlags(hipGraphExec_t* pGraphExec, hipGraph_t graph, unsigned long long flags);
Testcase Scenarios of hipGraphInstantiateWithFlags API:
Negative:
1) Pass nullptr to pGraphExec
2) Pass nullptr to graph
4) Pass invalid flag
Functional:
1) Create dependencies graph and instantiate the graph
2) Create graph in one GPU device and instantiate, launch in peer GPU device
3) Create stream capture graph and instantite the graph
4) Create stream capture graph in one GPU device and instantite the graph launch
in peer GPU device
Mapping is missing for NVIDIA platform hence skipping the testcases
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
constexpr size_t N = 1000000;
#if HT_AMD
/* This test covers the negative scenarios of
hipGraphInstantiateWithFlags API */
TEST_CASE("Unit_hipGraphInstantiateWithFlags_Negative") {
#if HT_NVIDIA
SECTION("Passing nullptr pGraphExec") {
hipGraph_t graph;
HIP_CHECK(hipGraphCreate(&graph, 0));
REQUIRE(hipGraphInstantiateWithFlags(nullptr,
graph, 0) == hipErrorInvalidValue);
}
SECTION("Passing nullptr to graph") {
hipGraphExec_t graphExec;
REQUIRE(hipGraphInstantiateWithFlags(&graphExec,
nullptr, 0) == hipErrorInvalidValue);
}
SECTION("Passing Invalid flag") {
hipGraph_t graph;
HIP_CHECK(hipGraphCreate(&graph, 0));
hipGraphExec_t graphExec;
REQUIRE(hipGraphInstantiateWithFlags(&graphExec, graph, 10) != hipSuccess);
}
#endif
}
/*
This function verifies the following scenarios
1. Creates dependency graph, Instantiates the graph with flags and verifies it
2. Creates graph on one GPU-1 device and instantiates the graph on peer GPU device
*/
void GraphInstantiateWithFlags_DependencyGraph(bool ctxt_change = false) {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
hipGraph_t graph;
hipGraphNode_t memset_A, memset_B, memsetKer_C;
hipGraphNode_t memcpyH2D_A, memcpyH2D_B, memcpyD2H_C;
hipGraphNode_t kernel_vecAdd;
hipKernelNodeParams kernelNodeParams{};
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
hipGraphExec_t graphExec;
hipMemsetParams memsetParams{};
int memsetVal{};
size_t NElem{N};
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(A_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_A, graph, nullptr, 0,
&memsetParams));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(B_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_B, graph, nullptr, 0,
&memsetParams));
void* kernelArgs1[] = {&C_d, &memsetVal, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func =
reinterpret_cast<void *>(HipTest::memsetReverse<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&memsetKer_C, graph, nullptr, 0,
&kernelNodeParams));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, graph, nullptr, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C, graph, nullptr, 0, C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
void* kernelArgs2[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
// Create dependencies
HIP_CHECK(hipGraphAddDependencies(graph, &memset_A, &memcpyH2D_A, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memset_B, &memcpyH2D_B, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memsetKer_C, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2H_C, 1));
if (ctxt_change) {
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
}
// Instantiate and launch the cloned graph
HIP_CHECK(hipGraphInstantiateWithFlags(&graphExec, graph, 0));
HIP_CHECK(hipGraphLaunch(graphExec, 0));
// Verify graph execution result
HipTest::checkVectorADD(A_h, B_h, C_h, N);
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphExecDestroy(graphExec));
HIP_CHECK(hipGraphDestroy(graph));
}
/*
This function verifies the following scenarios
1. Creates stream capture graph, Instantiates the graph with flags and verifies it
2. Creates graph on one GPU-1 device and instantiates the graph on peer GPU device
*/
void GraphInstantiateWithFlags_StreamCapture(bool deviceContextChg = false) {
float *A_d, *C_d;
float *A_h, *C_h;
size_t Nbytes = N * sizeof(float);
hipStream_t stream;
hipGraph_t graph{nullptr};
hipGraphExec_t graphExec{nullptr};
A_h = reinterpret_cast<float*>(malloc(Nbytes));
C_h = reinterpret_cast<float*>(malloc(Nbytes));
REQUIRE(A_h != nullptr);
REQUIRE(C_h != nullptr);
// Fill with Phi + i
for (size_t i = 0; i < N; i++) {
A_h[i] = 1.618f + i;
}
HIP_CHECK(hipMalloc(&A_d, Nbytes));
HIP_CHECK(hipMalloc(&C_d, Nbytes));
REQUIRE(A_d != nullptr);
REQUIRE(C_d != nullptr);
HIP_CHECK(hipGraphCreate(&graph, 0));
HIP_CHECK(hipStreamCreate(&stream));
constexpr unsigned blocks = 512;
constexpr unsigned threadsPerBlock = 256;
HIP_CHECK(hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal));
HIP_CHECK(hipMemcpyAsync(A_d, A_h, Nbytes, hipMemcpyHostToDevice, stream));
HIP_CHECK(hipMemsetAsync(C_d, 0, Nbytes, stream));
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, A_d, C_d, N);
HIP_CHECK(hipMemcpyAsync(C_h, C_d, Nbytes, hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamEndCapture(stream, &graph));
if (deviceContextChg) {
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipDeviceEnablePeerAccess(0, 0));
}
// Validate end capture is successful
REQUIRE(graph != nullptr);
HIP_CHECK(hipGraphInstantiateWithFlags(&graphExec, graph, 0));
REQUIRE(graphExec != nullptr);
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);
REQUIRE(false);
}
}
HIP_CHECK(hipStreamDestroy(stream));
free(A_h);
free(C_h);
HIP_CHECK(hipFree(A_d));
HIP_CHECK(hipFree(C_d));
}
/*
This testcase verifies hipGraphInstantiateWithFlags API
by creating dependency graph and instantiate, launching and verifying
the result
*/
TEST_CASE("Unit_hipGraphInstantiateWithFlags_DependencyGraph") {
GraphInstantiateWithFlags_DependencyGraph();
}
/*
This testcase verifies hipGraphInstantiateWithFlags API
by creating dependency graph on GPU-0 and instantiate, launching and verifying
the result on GPU-1
*/
#if HT_NVIDIA
TEST_CASE("Unit_hipGraphInstantiateWithFlags_DependencyGraphDeviceCtxtChg") {
int numDevices = 0;
int canAccessPeer = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
GraphInstantiateWithFlags_DependencyGraph(true);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
#endif
/*
This testcase verifies hipGraphInstantiateWithFlags API
by creating capture graph and instantiate, launching and verifying
the result
*/
TEST_CASE("Unit_hipGraphInstantiateWithFlags_StreamCapture") {
GraphInstantiateWithFlags_StreamCapture();
}
/*
This testcase verifies hipGraphInstantiateWithFlags API
by creating capture graph on GPU-0 and instantiate, launching and verifying
the result on GPU-1
*/
TEST_CASE("Unit_hipGraphInstantiateWithFlags_StreamCaptureDeviceContextChg") {
int numDevices = 0;
int canAccessPeer = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
GraphInstantiateWithFlags_StreamCapture(true);
} else {
SUCCEED("Machine does not seem to have P2P");
}
} else {
SUCCEED("skipped the testcase as no of devices is less than 2");
}
}
#endif
+107
Просмотреть файл
@@ -0,0 +1,107 @@
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <limits>
#define SIZE 256
__device__ int globalIn[SIZE], globalOut[SIZE];
__device__ __constant__ int globalConst[SIZE];
/* This testcase verifies negative scenarios of
hipGraphMemcpyNodeSetParamsToSymbol API */
TEST_CASE("Unit_hipGraphMemcpyNodeSetParamsToSymbol_Negative") {
constexpr size_t Nbytes = SIZE * sizeof(int);
int *A_d{nullptr}, *B_d{nullptr};
int *A_h{nullptr}, *B_h{nullptr};
HipTest::initArrays<int>(&A_d, &B_d, nullptr,
&A_h, &B_h, nullptr, SIZE, false);
hipGraph_t graph;
hipError_t ret;
hipGraphNode_t memcpyToSymbolNode, memcpyH2D_A;
std::vector<hipGraphNode_t> dependencies;
HIP_CHECK(hipGraphCreate(&graph, 0));
// Adding MemcpyNode
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
dependencies.push_back(memcpyH2D_A);
HIP_CHECK(hipGraphAddMemcpyNodeToSymbol(&memcpyToSymbolNode, graph,
dependencies.data(),
dependencies.size(),
HIP_SYMBOL(globalIn),
A_d, Nbytes, 0,
hipMemcpyDeviceToDevice));
SECTION("Pass GraphNode as nullptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(nullptr,
HIP_SYMBOL(globalIn),
B_d, Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass symbol ptr as nullptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
nullptr,
B_d, Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidSymbol == ret);
}
SECTION("Pass src ptr as nullptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
nullptr, Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass count as zero") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
B_d, 0, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass count more than allocated size for source and dstn ptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
B_d, Nbytes+8, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass offset+count greater than allocated size") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
B_d, Nbytes, 10,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass same symbol pointer as source ptr and destination ptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
HIP_SYMBOL(globalIn),
Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Pass 2 different symbol pointer as source ptr and dstn ptr") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
HIP_SYMBOL(globalOut),
Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
SECTION("Copy from host ptr to device ptr but pass kind as different") {
ret = hipGraphMemcpyNodeSetParamsToSymbol(memcpyToSymbolNode,
HIP_SYMBOL(globalIn),
A_h,
Nbytes, 0,
hipMemcpyDeviceToDevice);
REQUIRE(hipErrorInvalidValue == ret);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr, A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphDestroy(graph));
}
+241
Просмотреть файл
@@ -0,0 +1,241 @@
/*
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Testcase Scenarios of hipGraphNodeFindInClone API:
Negative:
1) Pass nullptr to graph node
2) pass nullptr to original graph node
3) pass nullptr to clonedGraph
4) Pass original graph in place of the cloned graph
5) Pass invalid originalNode
6) Destroy the graph node in the original graph
and try to get the deleted graph node
from the cloned graph
7) Clone the graph,Add node to Original graph
and try to find the original node in the cloned graph
Functional:
1) Get the graph node from the cloned graph corresponding to the original node
2) Create and clone the graph, modify the original graph and clone the graph again,
then try to find the newly added graph node from the cloned graph
*/
#include<hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
/* This test covers the negative scenarios of
hipGraphNodeFindInClone API */
TEST_CASE("Unit_hipGraphNodeFindInClone_Negative") {
hipGraph_t graph;
hipGraph_t clonedgraph;
hipGraphNode_t graphnode, newnode;
hipGraphNode_t clonedgraphnode;
HIP_CHECK(hipGraphCreate(&graph, 0));
int *A_d, *A_h, *B_d, *B_h;
HipTest::initArrays<int>(&A_d, &B_d, nullptr, &A_h,
&B_h, nullptr, 1024, false);
HIP_CHECK(hipGraphAddMemcpyNode1D(&graphnode, graph, nullptr, 0, A_d, A_h,
1024, hipMemcpyHostToDevice));
// Cloned the graph
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
HIP_CHECK(hipGraphAddMemcpyNode1D(&newnode, graph, nullptr, 0, B_d, B_h,
1024, hipMemcpyHostToDevice));
SECTION("Passing nullptr to Cloned graph") {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, graphnode, nullptr)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to original graph") {
REQUIRE(hipGraphNodeFindInClone(nullptr, graphnode, clonedgraph)
== hipErrorInvalidValue);
}
SECTION("Passing nullptr to graph node") {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, nullptr, clonedgraph)
== hipErrorInvalidValue);
}
#if HT_NVIDIA
SECTION("Pass uncloned graph") {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, graphnode, graph)
== hipErrorInvalidValue);
}
SECTION("Destroy the graph node and find in cloned graph") {
HIP_CHECK(hipGraphDestroyNode(graphnode));
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, graphnode,
clonedgraph)
== hipErrorInvalidValue);
}
#endif
SECTION("Pass invalid original graphnode") {
hipGraphNode_t unintialized_graphnode{nullptr};
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, unintialized_graphnode,
graph)
== hipErrorInvalidValue);
}
SECTION("Find node in cloned graph which is only present in original graph") {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode, newnode,
clonedgraph) == hipErrorInvalidValue);
}
HipTest::freeArrays<int>(A_d, B_d, nullptr,
A_h, B_h, nullptr, false);
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipGraphDestroy(clonedgraph));
}
void hipGraphNodeFindInClone_Func(bool ModifyOrigGraph = false) {
constexpr size_t N = 1024;
constexpr size_t Nbytes = N * sizeof(int);
constexpr auto blocksPerCU = 6; // to hide latency
constexpr auto threadsPerBlock = 256;
hipGraph_t graph, clonedgraph;
hipGraphNode_t memset_A, memset_B, memsetKer_C;
hipGraphNode_t memcpyH2D_A, memcpyH2D_B, memcpyD2H_C, memcpyD2D_C,
memcpyD2H_C_new;
hipGraphNode_t kernel_vecAdd;
hipKernelNodeParams kernelNodeParams{};
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
hipMemsetParams memsetParams{};
int memsetVal{};
size_t NElem{N};
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipGraphCreate(&graph, 0));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(A_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_A, graph, nullptr, 0,
&memsetParams));
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = reinterpret_cast<void*>(B_d);
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(char);
memsetParams.width = Nbytes;
memsetParams.height = 1;
HIP_CHECK(hipGraphAddMemsetNode(&memset_B, graph, nullptr, 0,
&memsetParams));
void* kernelArgs1[] = {&C_d, &memsetVal, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func =
reinterpret_cast<void *>(HipTest::memsetReverse<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs1);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&memsetKer_C, graph, nullptr, 0,
&kernelNodeParams));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_A, graph, nullptr, 0, A_d, A_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyH2D_B, graph, nullptr, 0, B_d, B_h,
Nbytes, hipMemcpyHostToDevice));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C, graph, nullptr, 0, C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
void* kernelArgs2[] = {&A_d, &B_d, &C_d, reinterpret_cast<void *>(&NElem)};
kernelNodeParams.func = reinterpret_cast<void *>(HipTest::vectorADD<int>);
kernelNodeParams.gridDim = dim3(blocks);
kernelNodeParams.blockDim = dim3(threadsPerBlock);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = reinterpret_cast<void**>(kernelArgs2);
kernelNodeParams.extra = nullptr;
HIP_CHECK(hipGraphAddKernelNode(&kernel_vecAdd, graph, nullptr, 0,
&kernelNodeParams));
// Create dependencies
HIP_CHECK(hipGraphAddDependencies(graph, &memset_A, &memcpyH2D_A, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memset_B, &memcpyH2D_B, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_A, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyH2D_B, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memsetKer_C, &kernel_vecAdd, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2H_C, 1));
if (ModifyOrigGraph) {
// Cloned the graph
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
// Modify Original graph by adding new dependency
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2D_C, graph, nullptr, 0,
C_d, B_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddMemcpyNode1D(&memcpyD2H_C_new, graph, nullptr, 0,
C_h, C_d,
Nbytes, hipMemcpyDeviceToHost));
HIP_CHECK(hipGraphAddDependencies(graph, &kernel_vecAdd, &memcpyD2D_C, 1));
HIP_CHECK(hipGraphAddDependencies(graph, &memcpyD2D_C,
&memcpyD2H_C_new, 1));
}
// Cloned the graph
HIP_CHECK(hipGraphClone(&clonedgraph, graph));
hipGraphNode_t clonedgraphnode;
if (ModifyOrigGraph) {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode,
memcpyD2H_C_new, clonedgraph)
== hipSuccess);
} else {
REQUIRE(hipGraphNodeFindInClone(&clonedgraphnode,
memcpyH2D_A, clonedgraph)
== hipSuccess);
}
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIP_CHECK(hipGraphDestroy(graph));
HIP_CHECK(hipGraphDestroy(clonedgraph));
}
TEST_CASE("Unit_hipGraphNodeFindInClone_Functional") {
SECTION("hipGraphNodeFindInClone Basic Functionality") {
hipGraphNodeFindInClone_Func();
}
SECTION("hipGraphNodeFindInClone Modify Original graph") {
hipGraphNodeFindInClone_Func(true);
}
}
+6
Просмотреть файл
@@ -35,6 +35,9 @@ set(TEST_SRC
hipMemPrefetchAsyncExtTsts.cc
hipMemAdviseMmap.cc
hipMemCoherencyTst.cc
hipMallocManaged.cc
hipMemRangeGetAttribute.cc
hipHmmOvrSubscriptionTst.cc
)
else()
set(TEST_SRC
@@ -69,6 +72,9 @@ set(TEST_SRC
hipMallocManagedFlagsTst.cc
hipMemPrefetchAsyncExtTsts.cc
hipMemAdviseMmap.cc
hipMallocManaged.cc
hipMemRangeGetAttribute.cc
hipHmmOvrSubscriptionTst.cc
)
endif()
+213
Просмотреть файл
@@ -0,0 +1,213 @@
/*
Copyright (c) 2021-Present Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description: This test case tests the working of OverSubscription
feature which is part of HMM.*/
#include <hip_test_common.hh>
#ifdef __linux__
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#endif
#include <list>
#define INIT_VAL 2.5
#define NUM_ELMS 268435456 // 268435456 * 4 = 1GB
#define ITERATIONS 10
#define ONE_GB 1024 * 1024 * 1024
static void GetTotGpuMem(int *TotMem);
static void DisplayHmmFlgs(int *Signal);
// Kernel function
__global__ void Square(int n, float *x) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
for (int i = index; i < n; i += stride) {
x[i] = x[i] + 10;
}
}
static void OneGBMemTest(int dev) {
int DataMismatch = 0;
float *HmmAG = nullptr;
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
// Testing hipMemAttachGlobal Flag
HIP_CHECK(hipMallocManaged(&HmmAG, NUM_ELMS * sizeof(float),
hipMemAttachGlobal));
// Initializing HmmAG memory
for (int i = 0; i < NUM_ELMS; i++) {
HmmAG[i] = INIT_VAL;
}
int blockSize = 256;
int numBlocks = (NUM_ELMS + blockSize - 1) / blockSize;
dim3 dimGrid(numBlocks, 1, 1);
dim3 dimBlock(blockSize, 1, 1);
HIP_CHECK(hipSetDevice(dev));
for (int i = 0; i < ITERATIONS; ++i) {
Square<<<dimGrid, dimBlock, 0, strm>>>(NUM_ELMS, HmmAG);
}
HIP_CHECK(hipStreamSynchronize(strm));
for (int j = 0; j < NUM_ELMS; ++j) {
if (HmmAG[j] != (INIT_VAL + ITERATIONS * 10)) {
DataMismatch++;
break;
}
}
if (DataMismatch != 0) {
WARN("Data Mismatch observed when kernel launched on device: " << dev);
REQUIRE(false);
}
HIP_CHECK(hipFree(HmmAG));
HIP_CHECK(hipStreamDestroy(strm));
}
static void GetTotGpuMem(int *TotMem) {
size_t FreeMem, TotGpuMem;
HIP_CHECK(hipMemGetInfo(&FreeMem, &TotGpuMem));
TotMem[0] = (TotGpuMem/(ONE_GB));
TotMem[1] = 1;
}
static void DisplayHmmFlgs(int *Signal) {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
// Checking for Vega20 or MI100
hipDeviceProp_t prop;
HIP_CHECK(hipGetDeviceProperties(&prop, 0));
char *p = NULL;
p = strstr(prop.gcnArchName, "gfx906");
if (p) {
WARN("This system has MI60 gpu hence OverSubscription test will be");
WARN(" skipped");
Signal[2] = 1;
}
p = strstr(prop.gcnArchName, "gfx908");
if (p) {
WARN("This system has MI100 gpu hence OverSubscription test will be");
WARN(" skipped");
Signal[2] = 1;
}
Signal[1] = managed;
Signal[0] = 1;
}
TEST_CASE("Unit_HMM_OverSubscriptionTst") {
int HmmEnabled = 0;
// The following Shared Mem is to get Max GPU Mem
// The size requested is for three ints
// 1) To get Max GPU Mem in GB
// 2) To Signal parent that req. info is available to consume
// 3) To know if MI60 or MI100 gpu are there in the system
key_t key = ftok("shmTotMem", 66);
int shmid = shmget(key, (3 * sizeof(int)), 0666|IPC_CREAT);
int *TotGpuMem = reinterpret_cast<int*>(shmat(shmid, NULL, 0));
TotGpuMem[0] = 0; TotGpuMem[1] = 0;
// The following function DisplayHmmFlgs() displays the flag values related
// to HMM and also sends us ManagedMemory attribute value
if (fork() == 0) {
DisplayHmmFlgs(TotGpuMem);
exit(1);
}
while (TotGpuMem[0] == 0) {
sleep(2);
}
// The following if block will skip test if either of MI60 or MI100 is found
if (TotGpuMem[2] == 1) {
SUCCEED("Test is skipped!!");
REQUIRE(true);
} else {
HmmEnabled = TotGpuMem[1];
// Re-setting the shared memory values for further usage
TotGpuMem[0] = 0;
TotGpuMem[1] = 0;
std::list<pid_t> PidLst;
// The following function gets the MaxGpu memory in GBs and also launches
// OverSubscription test
if (HmmEnabled) {
if ((setenv("HSA_XNACK", "1", 1)) != 0) {
WARN("Unable to turn on HSA_XNACK, hence terminating the Test case!");
REQUIRE(false);
}
if (fork() == 0) {
GetTotGpuMem(TotGpuMem);
}
while (TotGpuMem[1] == 0) {
sleep(2);
}
int NumGB = TotGpuMem[0], TotalThreads = (NumGB + 10);
WARN("Launching " << TotalThreads);
WARN(" processes to test OverSubscription.");
pid_t pid;
for (int k = 0; k < TotalThreads; ++k) {
pid = fork();
PidLst.push_back(pid);
if (pid == 0) {
OneGBMemTest(0);
exit(10);
}
}
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
int status;
for (pid_t pd : PidLst) {
waitpid(pd, &status, 0);
if (!(WIFEXITED(status))) {
REQUIRE(false);
}
}
}
shmdt(TotGpuMem);
shmctl(shmid, IPC_RMID, NULL);
}
+5 -172
Просмотреть файл
@@ -17,12 +17,11 @@
THE SOFTWARE.
*/
/*
List of Test cases:
1) Unit_hipMallocManaged_Basic
2) Unit_hipMallocManaged_MultiSize
3) Unit_hipMallocManaged_MultiKrnlHmmAccess
4) Unit_hipMallocManaged_KrnlWth2MemTypes
/* Test Case Description:
1) This testcase verifies the hipMallocManaged basic scenario - supported on
all devices
2) This testcase verifies the hipMallocManaged basic scenario - supported
only on HMM enabled devices
*/
#include <hip_test_common.hh>
@@ -32,12 +31,6 @@
// Kernel functions
__global__ void KrnlWth2MemTypes(int *Hmm, int *Dptr, size_t n) {
size_t index = blockIdx.x * blockDim.x + threadIdx.x;
for (size_t i = index; i < n; i++) {
Hmm[i] = Dptr[i] + 10;
}
}
__global__ void KernelMul_MngdMem(int *Hmm, int *Dptr, size_t n) {
size_t index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -64,9 +57,6 @@ __global__ void KrnlWth2MemTypesC(unsigned char *Hmm, unsigned char *Dptr,
}
}
// The following variable will be used to get the result of computation
// from multiple threads
static bool IfTestPassed = true;
static int HmmAttrPrint() {
int managed = 0;
@@ -93,62 +83,6 @@ static int HmmAttrPrint() {
}
static void LaunchKrnl4(size_t NumElms, int InitVal) {
int *Hmm = NULL, *Dptr = NULL, blockSize = 64, DataMismatch = 0;
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMallocManaged(&Hmm, (sizeof(int) * NumElms)));
HIP_CHECK(hipMalloc(&Dptr, (sizeof(int) * NumElms)));
int *Hstptr = reinterpret_cast<int*>(new int[NumElms]);
for (size_t i = 0; i < NumElms; ++i) {
Hstptr[i] = InitVal;
}
HIP_CHECK(hipMemcpy(Dptr, Hstptr, (NumElms * sizeof(int)),
hipMemcpyHostToDevice));
dim3 dimBlock(blockSize, 1, 1);
dim3 dimGrid((NumElms + blockSize -1)/blockSize, 1, 1);
KrnlWth2MemTypes<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observed after the Kernel: KrnlWth2MemTypes!!\n");
REQUIRE(false);
}
DataMismatch = 0;
KernelMul_MngdMem<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the result
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal * 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observedafter the Kernel: KernelMul_MngdMem!!\n");
REQUIRE(false);
}
DataMismatch = 0;
KernelMulAdd_MngdMem<<<dimGrid, dimBlock, 0, strm>>>(Hmm, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the result
for (size_t i = 0; i < NumElms; ++i) {
if (Hmm[i] != (InitVal * 10 * 2 + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
INFO("Data Mismatch observedafter the Kernel: KernelMul_MngdMem!!\n");
REQUIRE(false);
}
delete[] Hstptr;
}
static size_t N{4 * 1024 * 1024};
static unsigned blocksPerCU{6};
@@ -241,104 +175,3 @@ TEST_CASE("Unit_hipMallocManaged_Advanced") {
}
}
// The following test case tests the behavior of kernel with a HMM memory and
// hipMalloc memory
TEST_CASE("Unit_hipMallocManaged_KrnlWth2MemTypes") {
IfTestPassed = true;
int *Hmm = NULL, *Dptr = NULL, InitVal = 123;
size_t NumElms = (1024 * 1024);
int *Hptr = new int[NumElms], blockSize = 64, DataMismatch = 0;
int managed = HmmAttrPrint();
if (managed == 1) {
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMallocManaged(&Hmm, sizeof(int) * NumElms));
HIP_CHECK(hipMalloc(&Dptr, sizeof(int) * NumElms));
for (size_t i = 0; i < NumElms; ++i) {
Hmm[i] = 0;
Hptr[i] = InitVal;
}
HIP_CHECK(hipMemcpy(Dptr, Hptr, sizeof(int) * NumElms,
hipMemcpyHostToDevice));
dim3 dimBlock(blockSize, 1, 1);
dim3 dimGrid((NumElms + blockSize -1)/blockSize, 1, 1);
KrnlWth2MemTypes<<<dimGrid, dimBlock, 0, strm>>>(Hmm, Dptr, NumElms);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the results
for (size_t k = 0; k < NumElms; ++k) {
if (Hmm[k] != (InitVal + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
WARN("DataMismatch observed!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(Hmm));
HIP_CHECK(hipFree(Dptr));
delete[] Hptr;
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
// The following test case tests when the same Hmm memory is used for
// launching multiple different kernels will results in any issue
TEST_CASE("Unit_hipMallocManaged_MultiKrnlHmmAccess") {
int managed = HmmAttrPrint();
if (managed) {
int InitVal = 123, NumElms = (1024 * 1024);
LaunchKrnl4(NumElms, InitVal);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
// The following test case allocation, host access, device access of HMM
// memory from size 1 to 10KB
TEST_CASE("Unit_hipMallocManaged_MultiSize") {
IfTestPassed = true;
int managed = HmmAttrPrint();
if (managed == 1) {
unsigned char *Hmm1 = NULL, *Hmm2 = NULL;
int InitVal = 100, blockSize = 64, DataMismatch = 0;
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
dim3 dimBlock(blockSize, 1, 1);
for (int i = 1; i < (1024*1024); ++i) {
HIP_CHECK(hipMallocManaged(&Hmm1, i));
HIP_CHECK(hipMallocManaged(&Hmm2, i));
for (int j = 0; j < i; ++j) {
Hmm1[j] = InitVal;
}
dim3 dimGrid((i + blockSize -1)/blockSize, 1, 1);
KrnlWth2MemTypesC<<<dimGrid, dimBlock, 0, strm>>>(Hmm2, Hmm1, i);
HIP_CHECK(hipStreamSynchronize(strm));
// Verifying the results
for (int k = 0; k < i; ++k) {
if (Hmm2[k] != (InitVal + 10)) {
DataMismatch++;
}
}
if (DataMismatch != 0) {
WARN("DataMismatch observed!\n");
IfTestPassed = false;
}
DataMismatch = 0;
HIP_CHECK(hipFree(Hmm1));
HIP_CHECK(hipFree(Hmm2));
REQUIRE(IfTestPassed);
}
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
-76
Просмотреть файл
@@ -262,79 +262,3 @@ TEST_CASE("Unit_hipMallocManaged_AccessMultiStream") {
}
}
TEST_CASE("Unit_hipMallocManaged_ExtremeSizes") {
int managed = HmmAttrPrint();
if (managed == 1) {
bool IfTestPassed = true;
hipError_t err;
void *Hmm = NULL;
size_t totalDevMem = 0, freeDevMem = 0;
int NumDevs = 0;
HIP_CHECK(hipGetDeviceCount(&NumDevs));
// Testing allocation of extreme and unusual mem values
for (int i = 0; i < NumDevs; i++) {
HIP_CHECK(hipSetDevice(i));
HIP_CHECK(hipMemGetInfo(&freeDevMem, &totalDevMem));
err = hipMallocManaged(&Hmm, 1, hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating memory on GPU: " << i);
WARN(" size 1 with");
WARN(" hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, freeDevMem, hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max free memory on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, (freeDevMem - 1), hipMemAttachGlobal);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max (free - 1) memory on ");
WARN("GPU: " << i);
WARN(" using hipMallocManaged() api with flag 'hipMemAttachGlobal'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, 1, hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating memory size 1 on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, freeDevMem, hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max free memory on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&Hmm, (freeDevMem - 1), hipMemAttachHost);
if (hipSuccess == err) {
HIP_CHECK(hipFree(Hmm));
} else {
WARN("Observed error while allocating max (freeDevMem - 1) memory"
" on GPU: " << i);
WARN(" with hipMallocManaged() api with flag 'hipMemAttachHost'\n");
WARN("Error: " << hipGetErrorString(err));
IfTestPassed = false;
}
}
REQUIRE(IfTestPassed);
} else {
SUCCEED("Gpu doesnt support HMM! Hence skipping the test with PASS result");
}
}
+408
Просмотреть файл
@@ -0,0 +1,408 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* Test Case Description:
Scenario-1: The following function tests the count parameter(last param) to
hipMemRangeGetAttribute api by passing possible extreme values.
Curently the only way to test if count param working properly is to verify
the first parameter of hipMemRangeGetAttribute() api has value 1 stored
Scenario-2: This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part
Scenario-3: Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).
Scenario-4: The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash
Scenario-5: The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute
Scenario-6: The following Test Case does negative tests on hipMemRangeGetAttribute()*/
#include <hip_test_common.hh>
#include <stdlib.h>
#ifdef __linux__
#include <unistd.h>
#include <sys/sysinfo.h>
#endif
static bool CheckError(hipError_t err, int LineNo) {
if (err == hipSuccess) {
WARN("Error expected but received hipSuccess at line no.:"
<< LineNo);
return false;
} else {
return true;
}
}
static int HmmAttrPrint() {
int managed = 0;
WARN("The following are the attribute values related to HMM for"
" device 0:\n");
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeDirectManagedMemAccessFromHost, 0));
WARN("hipDeviceAttributeDirectManagedMemAccessFromHost: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributeConcurrentManagedAccess, 0));
WARN("hipDeviceAttributeConcurrentManagedAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccess, 0));
WARN("hipDeviceAttributePageableMemoryAccess: " << managed);
HIP_CHECK(hipDeviceGetAttribute(&managed,
hipDeviceAttributePageableMemoryAccessUsesHostPageTables, 0));
WARN("hipDeviceAttributePageableMemoryAccessUsesHostPageTables:"
<< managed);
HIP_CHECK(hipDeviceGetAttribute(&managed, hipDeviceAttributeManagedMemory,
0));
WARN("hipDeviceAttributeManagedMemory: " << managed);
return managed;
}
// The following function tests the count parameter(last param) to
// hipMemRangeGetAttribute api by passing possible extreme values.
// Curently the only way to test if count param working properly is to verify
// the first parameter of hipMemRangeGetAttribute() api has value 1 stored
TEST_CASE("Unit_hipMemRangeGetAttribute_TstCountParam") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999, FLG_READMOSTLY_ENBLD = 1;
bool IfTestPassed = true;
int data = RND_NUM, *devPtr = nullptr;
size_t TotGpuMem, TotGpuFreeMem;
HIP_CHECK(hipMemGetInfo(&TotGpuFreeMem, &TotGpuMem));
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(reinterpret_cast<void*>(&data),
sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, TotGpuFreeMem, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, TotGpuFreeMem, hipMemAdviseSetReadMostly,
0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, TotGpuFreeMem));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
HIP_CHECK(hipMallocManaged(&devPtr, (TotGpuFreeMem - 1),
hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, (TotGpuFreeMem - 1),
hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, (TotGpuFreeMem - 1)));
if (data != FLG_READMOSTLY_ENBLD) {
WARN("hipMemRangeGetAttribute() api didnt return expected value!\n");
IfTestPassed = false;
}
HIP_CHECK(hipFree(devPtr));
REQUIRE(IfTestPassed);
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following Test Case does negative tests on hipMemRangeGetAttribute()*/
TEST_CASE("Unit_hipMemRangeGetAttribute_NegativeTests") {
int MangdMem = HmmAttrPrint();
if (MangdMem == 1) {
int MEM_SIZE = 4096, RND_NUM = 9999;
float *devPtr = nullptr;
int NumDevs;
HIP_CHECK(hipGetDeviceCount(&NumDevs));
int data = RND_NUM;
int *OutData = new int[NumDevs];
for (int m = 0; m < NumDevs; ++m) {
OutData[m] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&devPtr, MEM_SIZE, hipMemAttachGlobal));
HIP_CHECK(hipMemAdvise(devPtr, MEM_SIZE, hipMemAdviseSetReadMostly, 0));
// checking the behavior with dataSize 0
SECTION("checking the behavior with dataSize 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, 0,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and even
SECTION("checking the behavior with dataSize > 4 and even") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 6,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize > 4 and odd
SECTION("checking the behavior with dataSize > 4 and odd") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 7,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behavior with dataSize which is not multiple of 4
SECTION("checking the behavior with dataSize which is not multiple of 4") {
REQUIRE(CheckError(hipMemRangeGetAttribute(OutData, 27,
hipMemRangeAttributeReadMostly,
devPtr, MEM_SIZE), __LINE__));
}
// checking the behaviour with devPtr(4th param) as NULL
SECTION("checking the behaviour with devPtr(4th param) as NULL") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
NULL, MEM_SIZE), __LINE__));
}
// checking the behaviour with count(5th param) as 0
SECTION("checking the behaviour with count(5th param) as 0") {
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
devPtr, 0), __LINE__));
}
// checking the behavior with invalid attribute (3rd param) as 0
// as it is attribute hence avoiding the negative tests with 3rd param
// checking the behaviour of the api with ptr allocated using
// hipHostMalloc
void *ptr = nullptr;
SECTION("Checking behavior with hipHostMalloc ptr") {
HIP_CHECK(hipHostMalloc(&ptr, MEM_SIZE, 0));
REQUIRE(CheckError(hipMemRangeGetAttribute(&data, sizeof(int),
hipMemRangeAttributeReadMostly,
ptr, MEM_SIZE), __LINE__));
HIP_CHECK(hipHostFree(ptr));
}
HIP_CHECK(hipFree(devPtr));
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* This test case checks the behavior of hipMemRangeGetAttribute() with
AccessedBy flag is consistent with cuda's counter part*/
TEST_CASE("Unit_hipMemRangeGetAttribute_AccessedBy1") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
if (OutData[0] != 0) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
for (int i = 1; i < Ngpus; ++i) {
if (OutData[i] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (Ngpus >= 2) {
for (int i = 0; i < Ngpus; ++i) {
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ, hipMemAdviseSetAccessedBy, i));
}
// checking the behavior with dataSize less than the number of gpus
// This should not result in segfault.
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*(Ngpus-1),
hipMemRangeAttributeAccessedBy,
Hmm, MEM_SZ));
// OutData should have stored the gpu ordinals for which AccessedBy is
// assigned except for the last element which should have -2 stored
// so as to be consistent with cuda's behavior
for (int i = 0; i < (Ngpus - 1); ++i) {
if (OutData[i] != i) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
if (OutData[Ngpus - 1] != -2) {
WARN("Didn't receive expected value at line: " << __LINE__);
REQUIRE(false);
}
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* Allocate 4 * page size of memory with the flag hipMemAttachGloal. Advise
AccessedBy, ReadMostly and PreferredLocation to first half(2*pageSz) of the
memory and probe the for the flags which are set earlier using
hipMemRangeGetAttribute() api for the full size(4*PageSz).*/
/* Need to discuss the difference in behavior w.r.t cuda*/
TEST_CASE("Unit_hipMemRangeGetAttribte_3") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, MEM_SZ = 4096*4, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetReadMostly, 0));
// The Api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
(Hmm), MEM_SZ));
HIP_CHECK(hipMemAdvise(Hmm, MEM_SZ/2, hipMemAdviseSetPreferredLocation, 0));
// The api called below should not fail
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
(Hmm), MEM_SZ));
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenarios tests that probing the attributes which are not set
by hipMemAdvise() but being probed using hipMemRangeGetAttribute() should
not result in a crash*/
TEST_CASE("Unit_hipMemRangeGetAttribute_4") {
int managed = HmmAttrPrint();
if (managed == 1) {
int *Hmm = NULL, PageSz = 4096, Ngpus, RND_NUM = 999;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[i] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, 4*PageSz));
SECTION("Set ReadMostly & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetReadMostly, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetReadMostly, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetAccessedBy, 0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributePreferredLocation,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetAccessedBy, 0));
}
SECTION("Set AccessedBy & probe other flags") {
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseSetPreferredLocation,
0));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeReadMostly,
Hmm, 4*PageSz));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4*Ngpus,
hipMemRangeAttributeAccessedBy,
Hmm, 4*PageSz));
HIP_CHECK(hipMemAdvise(Hmm, 4*PageSz, hipMemAdviseUnsetPreferredLocation,
0));
}
HIP_CHECK(hipFree(Hmm));
delete[] OutData;
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
/* The following scenario is a simple test which does the following:
Allocate Hmm memory --> hipMemPrefetchAsync() to device 0 and then
probe LastPrefetchLocation attribute using hipMemRangeGetAttribute*/
TEST_CASE("Unit_hipMemRangeGetAttribute_PrefetchAndGtAttr") {
int managed = HmmAttrPrint();
if (managed == 1) {
int Ngpus = 0, *Hmm = NULL, RND_NUM = 999;
size_t PageSz = 4096;
HIP_CHECK(hipGetDeviceCount(&Ngpus));
int *OutData = new int[Ngpus];
for (int i = 0; i < Ngpus; ++i) {
OutData[Ngpus] = RND_NUM;
}
HIP_CHECK(hipMallocManaged(&Hmm, PageSz*4));
hipStream_t strm;
HIP_CHECK(hipStreamCreate(&strm));
HIP_CHECK(hipMemPrefetchAsync(Hmm, PageSz*4, 0, strm));
HIP_CHECK(hipStreamSynchronize(strm));
HIP_CHECK(hipMemRangeGetAttribute(OutData, 4,
hipMemRangeAttributeLastPrefetchLocation,
Hmm, PageSz*4));
HIP_CHECK(hipStreamDestroy(strm));
HIP_CHECK(hipFree(Hmm));
if (OutData[0] != 0) {
WARN("Didnt receive expected value at line: " << __LINE__);
delete[] OutData;
REQUIRE(false);
}
} else {
SUCCEED("GPU 0 doesn't support hipDeviceAttributeManagedMemory "
"attribute. Hence skipping the testing with Pass result.\n");
}
}
+31 -13
Просмотреть файл
@@ -83,22 +83,40 @@ TEMPLATE_TEST_CASE("Unit_hipMemcpy2DAsync_Host&PinnedMem", ""
// Initialize the data
HipTest::setDefaultData<TestType>(NUM_W*NUM_H, A_h, B_h, C_h);
SECTION("Calling Async apis with stream object created by user") {
// Host to Device
HIP_CHECK(hipMemcpy2DAsync(A_d, pitch_A, A_h, COLUMNS*sizeof(TestType),
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyHostToDevice, stream));
// Host to Device
HIP_CHECK(hipMemcpy2DAsync(A_d, pitch_A, A_h, COLUMNS*sizeof(TestType),
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyHostToDevice, stream));
// Performs D2D on same GPU device
HIP_CHECK(hipMemcpy2DAsync(B_d, pitch_B, A_d,
pitch_A, COLUMNS*sizeof(TestType),
ROWS, hipMemcpyDeviceToDevice, stream));
// Performs D2D on same GPU device
HIP_CHECK(hipMemcpy2DAsync(B_d, pitch_B, A_d,
pitch_A, COLUMNS*sizeof(TestType),
ROWS, hipMemcpyDeviceToDevice, stream));
// hipMemcpy2DAsync Device to Host
HIP_CHECK(hipMemcpy2DAsync(B_h, COLUMNS*sizeof(TestType), B_d, pitch_B,
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling Async apis with hipStreamPerThread") {
// Host to Device
HIP_CHECK(hipMemcpy2DAsync(A_d, pitch_A, A_h, COLUMNS*sizeof(TestType),
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyHostToDevice, hipStreamPerThread));
// hipMemcpy2DAsync Device to Host
HIP_CHECK(hipMemcpy2DAsync(B_h, COLUMNS*sizeof(TestType), B_d, pitch_B,
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
// Performs D2D on same GPU device
HIP_CHECK(hipMemcpy2DAsync(B_d, pitch_B, A_d,
pitch_A, COLUMNS*sizeof(TestType),
ROWS, hipMemcpyDeviceToDevice, hipStreamPerThread));
// hipMemcpy2DAsync Device to Host
HIP_CHECK(hipMemcpy2DAsync(B_h, COLUMNS*sizeof(TestType), B_d, pitch_B,
COLUMNS*sizeof(TestType), ROWS,
hipMemcpyDeviceToHost, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
// Validating the result
REQUIRE(HipTest::checkArray<TestType>(A_h, B_h, COLUMNS, ROWS) == true);
+12 -4
Просмотреть файл
@@ -62,10 +62,18 @@ TEST_CASE("Unit_hipMemcpy2DFromArrayAsync_Basic") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
SECTION("Calling hipMemcpy2DFromArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DFromArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DFromArrayAsync(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
+12 -5
Просмотреть файл
@@ -58,11 +58,18 @@ TEST_CASE("Unit_hipMemcpy2DToArrayAsync_Basic") {
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
SECTION("Calling hipMemcpy2DToArrayAsync() with user declared stream obj") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy2DToArrayAsync() with hipStreamPerThread") {
HIP_CHECK(hipMemcpy2DToArrayAsync(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
+8 -2
Просмотреть файл
@@ -602,8 +602,14 @@ void Memcpy3DAsync<T>::simple_Memcpy3DAsync() {
#else
myparms.kind = hipMemcpyHostToDevice;
#endif
REQUIRE(hipMemcpy3DAsync(&myparms, stream) == hipSuccess);
HIP_CHECK(hipStreamSynchronize(stream));
SECTION("Calling hipMemcpy3DAsync() using user declared stream obj") {
REQUIRE(hipMemcpy3DAsync(&myparms, stream) == hipSuccess);
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpy3DAsync() using hipStreamPerThread") {
REQUIRE(hipMemcpy3DAsync(&myparms, hipStreamPerThread) == hipSuccess);
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
// Array to Array
memset(&myparms, 0x0, sizeof(hipMemcpy3DParms));
+14 -5
Просмотреть файл
@@ -149,11 +149,20 @@ TEST_CASE("Unit_hipMemcpyPeerAsync_Basic") {
// Copying data from GPU-0 to GPU-1 and performing vector addition
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
SECTION("Calling hipMemcpyPerAsync() using user defined stream obj") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
stream));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
}
SECTION("Calling hipMemcpyPerAsync() using hipStreamPerThread") {
HIP_CHECK(hipMemcpyPeerAsync(X_d, 1, A_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipMemcpyPeerAsync(Y_d, 1, B_d, 0, copy_bytes,
hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1),
0, 0, static_cast<const int*>(X_d),
static_cast<const int*>(Y_d), Z_d, numElements*sizeof(int));
+34 -15
Просмотреть файл
@@ -61,7 +61,6 @@ TEST_CASE("Unit_hipMemset2DAsync_WithKernel") {
size_t elements = NUM_W * NUM_H;
unsigned blocks{};
int validateCount{};
hipStream_t stream;
blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIP_CHECK(hipMallocPitch(reinterpret_cast<void**>(&A_d), &pitch_A,
@@ -81,21 +80,42 @@ TEST_CASE("Unit_hipMemset2DAsync_WithKernel") {
}
HIP_CHECK(hipMemcpy2D(B_d, width, B_h, pitch_B, NUM_W, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipStreamCreate(&stream));
SECTION("Using User created stream") {
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
for (size_t k = 0; k < ITER; k++) {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, B_d, C_d, elements);
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemset2DAsync(C_d, pitch_C, memsetval, NUM_W, NUM_H,
stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2D(A_h, width, C_d, pitch_C, NUM_W, NUM_H,
hipMemcpyDeviceToHost));
for (size_t p = 0 ; p < elements ; p++) {
if (A_h[p] == memsetval) {
validateCount+= 1;
}
}
}
HIP_CHECK(hipStreamDestroy(stream));
}
SECTION("Using hipStreamPerThread stream") {
for (size_t k = 0; k < ITER; k++) {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, hipStreamPerThread, B_d, C_d, elements);
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
HIP_CHECK(hipMemset2DAsync(C_d, pitch_C, memsetval, NUM_W, NUM_H,
hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
HIP_CHECK(hipMemcpy2D(A_h, width, C_d, pitch_C, NUM_W, NUM_H,
hipMemcpyDeviceToHost));
for (size_t k = 0; k < ITER; k++) {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, stream, B_d, C_d, elements);
HIP_CHECK(hipMemset2DAsync(C_d, pitch_C, memsetval, NUM_W, NUM_H, stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipMemcpy2D(A_h, width, C_d, pitch_C, NUM_W, NUM_H,
hipMemcpyDeviceToHost));
for (size_t p = 0 ; p < elements ; p++) {
if (A_h[p] == memsetval) {
validateCount+= 1;
for (size_t p = 0 ; p < elements ; p++) {
if (A_h[p] == memsetval) {
validateCount+= 1;
}
}
}
}
@@ -104,7 +124,6 @@ TEST_CASE("Unit_hipMemset2DAsync_WithKernel") {
HIP_CHECK(hipFree(A_d)); HIP_CHECK(hipFree(B_d)); HIP_CHECK(hipFree(C_d));
free(A_h); free(B_h);
HIP_CHECK(hipStreamDestroy(stream));
}
+12 -6
Просмотреть файл
@@ -184,11 +184,17 @@ static void testMemsetMaxValue(bool bAsync) {
HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent));
if (bAsync) {
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemset3DAsync(devPitchedPtr, memsetval, extent, stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipStreamDestroy(stream));
SECTION("Using user created stream") {
hipStream_t stream;
HIP_CHECK(hipStreamCreate(&stream));
HIP_CHECK(hipMemset3DAsync(devPitchedPtr, memsetval, extent, stream));
HIP_CHECK(hipStreamSynchronize(stream));
HIP_CHECK(hipStreamDestroy(stream));
}
SECTION("Using hipStreamPerThread") {
HIP_CHECK(hipMemset3DAsync(devPitchedPtr, memsetval, extent, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
}
} else {
HIP_CHECK(hipMemset3D(devPitchedPtr, memsetval, extent));
}
@@ -236,7 +242,7 @@ static void seekAndSet3DArraySlice(bool bAsync) {
// select random slice for memset
unsigned int seed = time(nullptr);
int slice_index = HipTest::RAND_R(&seed) % ZSIZE_S;
int slice_index = rand_r(&seed) % ZSIZE_S;
INFO("memset3d for sliceindex " << slice_index);
+25 -10
Просмотреть файл
@@ -21,7 +21,6 @@
* Test for checking order of execution of device kernel and
* hipMemsetAsync apis on all gpus
*/
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <hip_test_kernels.hh>
@@ -83,16 +82,26 @@ class MemSetKernelTest {
}
};
static bool testhipMemsetAsyncWithKernel() {
static bool testhipMemsetAsyncWithKernel(bool UseStrmPerThrd) {
MemSetKernelTest<char> obj;
constexpr char memsetval = 0x42;
obj.memAllocate(memsetval);
for (int k = 0 ; k < ITER ; k++) {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N);
HIP_CHECK(hipMemsetAsync(obj.C_d , obj.memSetVal , N , obj.stream));
HIP_CHECK(hipStreamSynchronize(obj.stream));
for (int k = 0 ; k < ITER ; ++k) {
if (UseStrmPerThrd) { // will use hipStreamPerThread stream object
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, hipStreamPerThread, obj.B_d,
obj.C_d, N);
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
HIP_CHECK(hipMemsetAsync(obj.C_d , obj.memSetVal, N, hipStreamPerThread));
HIP_CHECK(hipStreamSynchronize(hipStreamPerThread));
} else {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d,
N);
HIP_CHECK(hipMemsetAsync(obj.C_d , obj.memSetVal , N , obj.stream));
HIP_CHECK(hipStreamSynchronize(obj.stream));
}
HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost));
obj.validateExecutionOrder();
@@ -109,7 +118,7 @@ static bool testhipMemsetD32AsyncWithKernel() {
hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks),
dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N);
HIP_CHECK(hipMemsetD32Async((hipDeviceptr_t)obj.C_d , obj.memSetVal,
N, obj.stream));
N, obj.stream));
HIP_CHECK(hipStreamSynchronize(obj.stream));
HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost));
@@ -161,7 +170,7 @@ static bool testhipMemsetD8AsyncWithKernel() {
*/
TEST_CASE("Unit_hipMemsetAsync_VerifyExecutionWithKernel") {
int numDevices = 0;
bool ret;
bool ret, UseStrmPerThrd = false;
blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
@@ -172,7 +181,13 @@ TEST_CASE("Unit_hipMemsetAsync_VerifyExecutionWithKernel") {
HIP_CHECK(hipSetDevice(devNum));
SECTION("hipMemsetAsync With Kernel") {
ret = testhipMemsetAsyncWithKernel();
UseStrmPerThrd = false;
ret = testhipMemsetAsyncWithKernel(UseStrmPerThrd);
REQUIRE(ret == true);
}
SECTION("hipMemsetAsync With Kernel using hipStreamPerThread stream obj") {
UseStrmPerThrd = true;
ret = testhipMemsetAsyncWithKernel(UseStrmPerThrd);
REQUIRE(ret == true);
}
+276
Просмотреть файл
@@ -0,0 +1,276 @@
/*
Copyright (c) 2020 - 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Test Description:
/* This test implements sum reduction kernel, first with each threads own rank
as input and comparing the sum with expected sum output derieved from n(n-1)/2
formula.
This sample tests functionality of intrinsics provided by thread_block_tile type,
shfl_down and shfl_xor.
*/
#include "test_common.h"
#include <hip/hip_cooperative_groups.h>
#include <stdio.h>
#include <vector>
using namespace cooperative_groups;
#define ASSERT_EQUAL(lhs, rhs) assert(lhs == rhs)
#define WAVE_SIZE 32
__device__ int reduction_kernel_shfl_down(coalesced_group const& g, int val) {
int sz = g.size();
for (int i = sz / 2; i > 0; i >>= 1) {
val += g.shfl_down(val, i);
}
// Choose the 0'th indexed thread that holds the reduction value to return
if (g.thread_rank() == 0) {
return val;
}
// Rest of the threads return no useful values
else {
return -1;
}
}
__global__ void kernel_shfl_down (int * dPtr, int *dResults, int lane_delta, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group const& g = coalesced_threads();
int rank = g.thread_rank();
int val = dPtr[rank];
dResults[rank] = g.shfl_down(val, lane_delta);
return;
}
}
__global__ void kernel_cg_group_partition(int* result, unsigned int tileSz, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group threadBlockCGTy = coalesced_threads();
int input, outputSum, expectedSum;
// Choose a leader thread to print the results
if (threadBlockCGTy.thread_rank() == 0) {
printf(" Creating %d groups, of tile size %d threads:\n\n",
(int)threadBlockCGTy.size() / tileSz, tileSz);
}
threadBlockCGTy.sync();
coalesced_group tiledPartition = tiled_partition(threadBlockCGTy, tileSz);
int threadRank = tiledPartition.thread_rank();
input = tiledPartition.thread_rank();
// (n-1)(n)/2
expectedSum = ((tileSz - 1) * tileSz / 2);
outputSum = reduction_kernel_shfl_down(tiledPartition, input);
if (tiledPartition.thread_rank() == 0) {
printf(
" Sum of all ranks 0..%d in this tiledPartition group using shfl_down is %d (expected "
"%d)\n",
tiledPartition.size() - 1, outputSum, expectedSum);
result[threadBlockCGTy.thread_rank() / (tileSz)] = outputSum;
}
return;
}
}
void verifyResults(int* ptr, int expectedResult, int numTiles) {
for (int i = 0; i < numTiles; i++) {
if (ptr[i] != expectedResult) {
printf(" Results do not match! ");
}
}
}
void compareResults(int* cpu, int* gpu, int size) {
for (unsigned int i = 0; i < size / sizeof(int); i++) {
if (cpu[i] != gpu[i]) {
printf(" results do not match.");
}
}
}
void printResults(int* ptr, int size) {
for (int i = 0; i < size; i++) {
std::cout << ptr[i] << " ";
}
std::cout << '\n';
}
static void test_group_partition(unsigned int tileSz) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = 32;
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
int numTiles = ((blockSize * threadsPerBlock) / i) / tileSz;
int expectedSum = ((tileSz - 1) * tileSz / 2);
int* expectedResult = new int[numTiles];
// numTiles = 0 when partitioning is possible. The below statement is to avoid
// out-of-bounds error and still evaluate failure case.
numTiles = (numTiles == 0) ? 1 : numTiles;
for (int i = 0; i < numTiles; i++) {
expectedResult[i] = expectedSum;
}
int* dResult = NULL;
int* hResult = NULL;
hipHostMalloc(&hResult, numTiles * sizeof(int), hipHostMallocDefault);
memset(hResult, 0, numTiles * sizeof(int));
hipMalloc(&dResult, numTiles * sizeof(int));
// Launch Kernel
hipLaunchKernelGGL(kernel_cg_group_partition, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, dResult, tileSz, i);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
hipMemcpy(hResult, dResult, sizeof(int) * numTiles, hipMemcpyDeviceToHost);
verifyResults(hResult, expectedSum, numTiles);
// Free all allocated memory on host and device
hipFree(dResult);
hipFree(hResult);
delete[] expectedResult;
printf("\n...PASSED.\n\n");
}
}
static void test_shfl_down() {
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
int totalThreads = blockSize * threadsPerBlock;
int group_size = totalThreads / i;
int group_size_in_bytes = group_size * sizeof(int);
int* hPtr = NULL;
int* dPtr = NULL;
int* dResults = NULL;
int lane_delta = rand() % group_size;
std::cout << "Testing coalesced_groups shfl_down with lane_delta " << lane_delta << "and group size "
<< WAVE_SIZE << '\n' << std::endl;
int arrSize = blockSize * threadsPerBlock * sizeof(int);
hipHostMalloc(&hPtr, arrSize);
// Fill up the array
for (int i = 0; i < WAVE_SIZE; i++) {
hPtr[i] = rand() % 1000;
}
int* cpuResultsArr = (int*)malloc(group_size_in_bytes);
for (int i = 0; i < group_size; i++) {
cpuResultsArr[i] = (i + lane_delta >= group_size) ? hPtr[i] : hPtr[i + lane_delta];
}
//printf("Array passed to GPU for computation\n");
//printResults(hPtr, WAVE_SIZE);
hipMalloc(&dPtr, group_size_in_bytes);
hipMalloc(&dResults, group_size_in_bytes);
hipMemcpy(dPtr, hPtr, group_size_in_bytes, hipMemcpyHostToDevice);
// Launch Kernel
hipLaunchKernelGGL(kernel_shfl_down, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, dPtr, dResults, lane_delta, i);
hipMemcpy(hPtr, dResults, group_size_in_bytes, hipMemcpyDeviceToHost);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
//printf("GPU results: \n");
//printResults(hPtr, WAVE_SIZE);
//printf("Printing cpu to be verified array\n");
//printResults(cpuResultsArr, WAVE_SIZE);
compareResults(hPtr, cpuResultsArr, group_size_in_bytes);
std::cout << "Results verified!\n";
hipFree(hPtr);
hipFree(dPtr);
free(cpuResultsArr);
}
}
int main() {
// Use default device for validating the test
int deviceId;
ASSERT_EQUAL(hipGetDevice(&deviceId), hipSuccess);
hipDeviceProp_t deviceProperties;
ASSERT_EQUAL(hipGetDeviceProperties(&deviceProperties, deviceId), hipSuccess);
int maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock;
if (!deviceProperties.cooperativeLaunch) {
std::cout << "info: Device doesn't support cooperative launch! skipping the test!\n";
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
} else {
passed();
}
return 0;
}
// Test shfl_down with random group sizes
for (int i = 0; i < 100; i++) {
test_shfl_down();
}
std::cout << "Testing static tiled_partition for different tile sizes using shfl_down"
<< std::endl;
int testNo = 1;
std::vector<unsigned int> tileSizes = {2, 4, 8, 16, 32};
for (auto i : tileSizes) {
std::cout << "TEST " << testNo << ":" << '\n' << std::endl;
test_group_partition(i);
testNo++;
}
passed();
}
+260
Просмотреть файл
@@ -0,0 +1,260 @@
/*
Copyright (c) 2020 - 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Test Description:
/* This test implements prefix sum(scan) kernel, first with each threads own rank
as input and comparing the sum with expected serial summation output on CPU.
This sample tests functionality of intrinsics provided by coalesced_group,
shfl_up.
*/
#include "test_common.h"
#include <hip/hip_cooperative_groups.h>
#include <stdio.h>
#include <vector>
using namespace cooperative_groups;
#define ASSERT_EQUAL(lhs, rhs) assert(lhs == rhs)
#define WAVE_SIZE 32
__device__ int prefix_sum_kernel(coalesced_group const& g, int val) {
int sz = g.size();
for (int i = 1; i < sz; i <<= 1) {
int temp = g.shfl_up(val, i);
if (g.thread_rank() >= i) {
val += temp;
}
}
return val;
}
__global__ void kernel_shfl_up (int * dPtr, int *dResults, int lane_delta, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group g = coalesced_threads();
int rank = g.thread_rank();
int val = dPtr[rank];
dResults[rank] = g.shfl_up(val, lane_delta);
return;
}
}
__global__ void kernel_cg_group_partition(int* dPtr, unsigned int tileSz, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group threadBlockCGTy = coalesced_threads();
int input, outputSum;
// we pass its own thread rank as inputs
input = threadBlockCGTy.thread_rank();
// Choose a leader thread to print the results
if (threadBlockCGTy.thread_rank() == 0) {
printf(" Creating %d groups, of tile size %d threads:\n\n",
(int)threadBlockCGTy.size() / tileSz, tileSz);
}
threadBlockCGTy.sync();
coalesced_group tiledPartition = tiled_partition(threadBlockCGTy, tileSz);
input = tiledPartition.thread_rank();
outputSum = prefix_sum_kernel(tiledPartition, input);
// Update the result array with the corresponsing prefix sum
dPtr[threadBlockCGTy.thread_rank()] = outputSum;
return;
}
}
void serialScan(int* ptr, int size) {
// Fill up the array
for (int i = 0; i < size; i++) {
ptr[i] = i;
}
int acc = 0;
for (int i = 0; i < size; i++) {
acc = acc + ptr[i];
ptr[i] = acc;
}
}
void printResults(int* ptr, int size) {
for (int i = 0; i < size; i++) {
std::cout << ptr[i] << " ";
}
std::cout << '\n';
}
void verifyResults(int* cpu, int* gpu, int size) {
for (unsigned int i = 0; i < size / sizeof(int); i++) {
if (cpu[i] != gpu[i]) {
printf(" Results do not match.");
}
}
}
static void test_group_partition(unsigned tileSz) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
int* hPtr = NULL;
int* dPtr = NULL;
int* cpuPrefixSum = NULL;
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
int arrSize = blockSize * threadsPerBlock * sizeof(int);
hipHostMalloc(&hPtr, arrSize);
hipMalloc(&dPtr, arrSize);
// Launch Kernel
hipLaunchKernelGGL(kernel_cg_group_partition, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, dPtr, tileSz, i);
hipMemcpy(hPtr, dPtr, arrSize, hipMemcpyDeviceToHost);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
cpuPrefixSum = new int[tileSz];
serialScan(cpuPrefixSum, tileSz);
//std::cout << "\nPrefix sum results on CPU\n";
//printResults(cpuPrefixSum, tileSz);
//std::cout << "\nPrefix sum results on GPU\n";
//printResults(hPtr, tileSz);
std::cout << "\n";
verifyResults(hPtr, cpuPrefixSum, tileSz);
std::cout << "Results verified!\n";
delete[] cpuPrefixSum;
hipFree(hPtr);
hipFree(dPtr);
}
}
static void test_shfl_up() {
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
int totalThreads = blockSize * threadsPerBlock;
int group_size = totalThreads / i;
int group_size_in_bytes = group_size * sizeof(int);
int* hPtr = NULL;
int* dPtr = NULL;
int* dResults = NULL;
int lane_delta = (rand() % group_size);
std::cout << "Testing coalesced_groups shfl_up with lane_delta " << lane_delta
<< " and group size " << WAVE_SIZE << '\n' << std::endl;
int arrSize = blockSize * threadsPerBlock * sizeof(int);
hipHostMalloc(&hPtr, arrSize);
// Fill up the array
for (int i = 0; i < WAVE_SIZE; i++) {
hPtr[i] = rand() % 1000;
}
//printResults(hPtr, WAVE_SIZE);
int* cpuResultsArr = (int*)malloc(group_size_in_bytes);
for (int i = 0; i < group_size; i++) {
cpuResultsArr[i] = (i <= (lane_delta - 1)) ? hPtr[i] : hPtr[i - lane_delta];
}
//printf("Printing cpu results arr\n");
//printResults(cpuResultsArr, WAVE_SIZE);
hipMalloc(&dPtr, group_size_in_bytes);
hipMalloc(&dResults, group_size_in_bytes);
hipMemcpy(dPtr, hPtr, group_size_in_bytes, hipMemcpyHostToDevice);
// Launch Kernel
hipLaunchKernelGGL(kernel_shfl_up, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, dPtr, dResults, lane_delta, i);
hipMemcpy(hPtr, dResults, group_size_in_bytes, hipMemcpyDeviceToHost);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
//printf("GPU computation array :\n");
//printResults(hPtr, WAVE_SIZE);
verifyResults(hPtr, cpuResultsArr, group_size_in_bytes);
std::cout << "Results verified!\n";
hipFree(hPtr);
hipFree(dPtr);
free(cpuResultsArr);
}
}
int main() {
// Use default device for validating the test
int deviceId;
ASSERT_EQUAL(hipGetDevice(&deviceId), hipSuccess);
hipDeviceProp_t deviceProperties;
ASSERT_EQUAL(hipGetDeviceProperties(&deviceProperties, deviceId), hipSuccess);
int maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock;
if (!deviceProperties.cooperativeLaunch) {
std::cout << "info: Device doesn't support cooperative launch! skipping the test!\n";
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
} else {
passed();
}
return 0;
}
for (int i = 0; i < 100; i++) {
test_shfl_up();
}
std::cout << "Testing coalesced_groups partitioning and shfl_up" << '\n' << std::endl;
int testNo = 1;
std::vector<unsigned int> tileSizes = {2, 4, 8, 16, 32};
for (auto i : tileSizes) {
std::cout << "TEST " << testNo << ":" << '\n' << std::endl;
test_group_partition(i);
testNo++;
}
passed();
}
/* Kogge-Stone algorithm */
+583
Просмотреть файл
@@ -0,0 +1,583 @@
/*
Copyright (c) 2020 - 2021 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Test Description:
/* This test implements sum reduction kernel, first with each threads own rank
as input and comparing the sum with expected sum output derieved from n(n-1)/2
formula. The second part, partitions this parent group into child subgroups
a.k.a tiles using using tiled_partition() collective operation. This can be called
with a static tile size, passed in templated non-type variable-tiled_partition<tileSz>,
or in runtime as tiled_partition(thread_group parent, tileSz). This test covers both these
cases.
This test tests functionality of cg group partitioning, (static and dynamic) and its respective
API's size(), thread_rank(), and sync().
*/
#include "test_common.h"
#include <hip/hip_cooperative_groups.h>
#include <stdio.h>
#include <vector>
using namespace cooperative_groups;
#define ASSERT_EQUAL(lhs, rhs) assert(lhs == rhs)
#define NUM_ELEMS 10000000
#define NUM_THREADS_PER_BLOCK 512
#define WAVE_SIZE 32
/* Test coalesced group's functionality.
*
*/
__device__ int atomicAggInc(int *ptr) {
coalesced_group g = coalesced_threads();
int prev;
// elect the first active thread to perform atomic add
if (g.thread_rank() == 0) {
prev = atomicAdd(ptr, g.size());
}
// broadcast previous value within the warp
// and add each active threads rank to it
prev = g.thread_rank() + g.shfl(prev, 0);
return prev;
}
__global__ void kernel_shfl (int * dPtr, int *dResults, int srcLane, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group const& g = coalesced_threads();
int rank = g.thread_rank();
int val = dPtr[rank];
dResults[rank] = g.shfl(val, srcLane);
return;
}
}
__global__ void kernel_shfl_any_to_any (int *randVal, int *dsrcArr, int *dResults, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group const& g = coalesced_threads();
int rank = g.thread_rank();
int val = randVal[rank];
dResults[rank] = g.shfl(val, dsrcArr[rank]);
return;
}
}
__global__ void filter_arr(int *dst, int *nres, const int *src, int n) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
for (int i = id; i < n; i += gridDim.x * blockDim.x) {
if (src[i] > 0) dst[atomicAggInc(nres)] = src[i];
}
}
/* Parallel reduce kernel.
*
* Step complexity: O(log n)
* Work complexity: O(n)
*
* Note: This kernel works only with power of 2 input arrays.
*/
__device__ int reduction_kernel(coalesced_group g, int* x, int val) {
int lane = g.thread_rank();
int sz = g.size();
for (int i = g.size() / 2; i > 0; i /= 2) {
// use lds to store the temporary result
x[lane] = val;
// Ensure all the stores are completed.
g.sync();
if (lane < i) {
val += x[lane + i];
}
// It must work on one tiled thread group at a time,
// and it must make sure all memory operations are
// completed before moving to the next stride.
// sync() here just does that.
g.sync();
}
// Choose the 0'th indexed thread that holds the reduction value to return
if (g.thread_rank() == 0) {
return val;
}
// Rest of the threads return no useful values
else {
return -1;
}
}
__global__ void kernel_cg_coalesced_group_partition(unsigned int tileSz, int* result,
bool isGlobalMem, int* globalMem, int cg_sizes) {
int id = threadIdx.x + blockIdx.x * blockDim.x;
if (id % cg_sizes == 0) {
coalesced_group threadBlockCGTy = coalesced_threads();
int threadBlockGroupSize = threadBlockCGTy.size();
int* workspace = NULL;
if (isGlobalMem) {
workspace = globalMem;
} else {
// Declare a shared memory
extern __shared__ int sharedMem[];
workspace = sharedMem;
}
int input, outputSum, expectedOutput;
// input to reduction, for each thread, is its' rank in the group
input = threadBlockCGTy.thread_rank();
expectedOutput = (threadBlockGroupSize - 1) * threadBlockGroupSize / 2;
outputSum = reduction_kernel(threadBlockCGTy, workspace, input);
if (threadBlockCGTy.thread_rank() == 0) {
printf(" Sum of all ranks 0..%d in coalesced_group is %d\n\n",
(int)threadBlockCGTy.size() - 1, outputSum);
printf(" Creating %d groups, of tile size %d threads:\n\n",
(int)threadBlockCGTy.size() / tileSz, tileSz);
}
threadBlockCGTy.sync();
coalesced_group tiledPartition = tiled_partition(threadBlockCGTy, tileSz);
// This offset allows each group to have its own unique area in the workspace array
int workspaceOffset = threadBlockCGTy.thread_rank() - tiledPartition.thread_rank();
outputSum = reduction_kernel(tiledPartition, workspace + workspaceOffset, input);
if (tiledPartition.thread_rank() == 0) {
printf(
" Sum of all ranks 0..%d in this tiledPartition group is %d. Corresponding parent thread "
"rank: %d\n",
tiledPartition.size() - 1, outputSum, input);
result[input / (tileSz)] = outputSum;
}
return;
}
}
__global__ void kernel_coalesced_active_groups() {
thread_block threadBlockCGTy = this_thread_block();
int threadBlockGroupSize = threadBlockCGTy.size();
// input to reduction, for each thread, is its' rank in the group
int input = threadBlockCGTy.thread_rank();
if (threadBlockCGTy.thread_rank() == 0) {
printf(" Creating odd and even set of active thread groups based on branch divergence\n\n");
}
threadBlockCGTy.sync();
// Group all active odd threads
if (threadBlockCGTy.thread_rank() % 2) {
coalesced_group activeOdd = coalesced_threads();
if (activeOdd.thread_rank() == 0) {
printf(" ODD: Size of odd set of active threads is %d."
" Corresponding parent thread_rank is %d.\n\n",
activeOdd.size(), threadBlockCGTy.thread_rank());
}
}
else { // Group all active even threads
coalesced_group activeEven = coalesced_threads();
if (activeEven.thread_rank() == 0) {
printf(" EVEN: Size of even set of active threads is %d."
" Corresponding parent thread_rank is %d.",
activeEven.size(), threadBlockCGTy.thread_rank());
}
}
return;
}
void printResults(int* ptr, int size) {
for (int i = 0; i < size; i++) {
std::cout << ptr[i] << " ";
}
std::cout << '\n';
}
void compareResults(int* cpu, int* gpu, int size) {
for (unsigned int i = 0; i < size / sizeof(int); i++) {
if (cpu[i] != gpu[i]) {
printf(" results do not match.");
}
}
}
static void test_active_threads_grouping() {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
// Launch Kernel
hipLaunchKernelGGL(kernel_coalesced_active_groups, blockSize, threadsPerBlock, 0, 0);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
printf("\n...PASSED.\n\n");
}
// Search if the sum exists in the expected results array
void verifyResults(int* hPtr, int* dPtr, int size) {
int i = 0, j = 0;
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
if (hPtr[i] == dPtr[j]) {
break;
}
}
if (j == size) {
printf(" Result verification failed!");
}
}
}
static void test_group_partition(unsigned int tileSz, bool useGlobalMem) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
int numTiles = ((blockSize * threadsPerBlock) / i) / tileSz;
// numTiles = 0 when partitioning is possible. The below statement is to avoid
// out-of-bounds error and still evaluate failure case.
numTiles = (numTiles == 0) ? 1 : numTiles;
// Build an array of expected reduction sum output on the host
// based on the sum of their respective thread ranks to use for verification
int* expectedSum = new int[numTiles];
int temp = 0, sum = 0;
for (int i = 1; i <= numTiles; i++) {
sum = temp;
temp = (((tileSz * i) - 1) * (tileSz * i)) / 2;
expectedSum[i-1] = temp - sum;
}
int* dResult = NULL;
hipMalloc(&dResult, sizeof(int) * numTiles);
int* globalMem = NULL;
if (useGlobalMem) {
hipMalloc((void**)&globalMem, threadsPerBlock * sizeof(int));
}
int* hResult = NULL;
hipHostMalloc(&hResult, numTiles * sizeof(int), hipHostMallocDefault);
memset(hResult, 0, numTiles * sizeof(int));
// Launch Kernel
if (useGlobalMem) {
hipLaunchKernelGGL(kernel_cg_coalesced_group_partition, blockSize, threadsPerBlock, 0, 0, tileSz,
dResult, useGlobalMem, globalMem, i);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
} else {
hipLaunchKernelGGL(kernel_cg_coalesced_group_partition, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, tileSz, dResult, useGlobalMem, globalMem, i);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
}
hipMemcpy(hResult, dResult, numTiles * sizeof(int), hipMemcpyDeviceToHost);
verifyResults(expectedSum, hResult, numTiles);
// Free all allocated memory on host and device
hipFree(dResult);
hipFree(hResult);
if (useGlobalMem) {
hipFree(globalMem);
}
delete[] expectedSum;
printf("\n...PASSED.\n\n");
}
}
static void test_shfl_any_to_any() {
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
int totalThreads = blockSize * threadsPerBlock;
int group_size = (totalThreads + i - 1) / i;
int group_size_in_bytes = group_size * sizeof(int);
int* hPtr = NULL;
int* dPtr = NULL;
int* dsrcArr = NULL;
int* dResults = NULL;
int* srcArr = (int*)malloc(group_size_in_bytes);
int* srcArrCpu = (int*)malloc(group_size_in_bytes);
std::cout << "Testing coalesced_groups shfl any-to-any\n" <<std::endl;
int arrSize = blockSize * threadsPerBlock * sizeof(int);
hipHostMalloc(&hPtr, arrSize);
// Fill up the array
for (int i = 0; i < WAVE_SIZE; i++) {
hPtr[i] = rand() % 1000;
}
// Fill up the random array
for (int i = 0; i < group_size; i++) {
srcArr[i] = rand() % 1000;
srcArrCpu[i] = srcArr[i] % group_size;
}
/* Fill cpu results array so that we can verify with gpu computation */
int* cpuResultsArr = (int*)malloc(group_size_in_bytes);
for(int i = 0; i < group_size; i++) {
cpuResultsArr[i] = hPtr[srcArrCpu[i]];
}
//printf("Array passed to GPU for computation\n");
//printResults(hPtr, WAVE_SIZE);
hipMalloc(&dPtr, group_size_in_bytes);
hipMalloc(&dResults, group_size_in_bytes);
hipMalloc(&dsrcArr, group_size_in_bytes);
hipMemcpy(dsrcArr, srcArr, group_size_in_bytes, hipMemcpyHostToDevice);
hipMemcpy(dPtr, hPtr, group_size_in_bytes, hipMemcpyHostToDevice);
// Launch Kernel
hipLaunchKernelGGL(kernel_shfl_any_to_any, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0 , dPtr, dsrcArr, dResults, i);
hipMemcpy(hPtr, dResults, group_size_in_bytes, hipMemcpyDeviceToHost);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
//printf("GPU results: \n");
//printResults(hPtr, group_size);
//printf("Printing cpu to be verified array\n");
//printResults(cpuResultsArr, group_size);
//printf("Printing srcLane array that was passed\n");
//printResults(srcArr, group_size);
//printf("Printing srcLane array on the CPU\n");
//printResults(srcArrCpu, group_size);
compareResults(hPtr, cpuResultsArr, group_size_in_bytes);
std::cout << "Results verified!\n";
hipFree(hPtr);
hipFree(dPtr);
free(srcArr);
free(srcArrCpu);
free(cpuResultsArr);
}
}
static void test_shfl_broadcast() {
std::vector<unsigned int> cg_sizes = {1, 2, 3};
for (auto i : cg_sizes) {
hipError_t err;
int blockSize = 1;
int threadsPerBlock = WAVE_SIZE;
int totalThreads = blockSize * threadsPerBlock;
int group_size = (totalThreads + i - 1) / i;
int group_size_in_bytes = group_size * sizeof(int);
int* hPtr = NULL;
int* dPtr = NULL;
int* dResults = NULL;
int srcLane = rand() % 1000;
int srcLaneCpu = 0;
std::cout << "Testing coalesced_groups shfl with srcLane " << srcLane << '\n'
<< " and group size " << i <<std::endl;
int arrSize = blockSize * threadsPerBlock * sizeof(int);
hipHostMalloc(&hPtr, arrSize);
// Fill up the array
for (int i = 0; i < WAVE_SIZE; i++) {
hPtr[i] = rand() % 1000;
}
/* Fill cpu results array so that we can verify with gpu computation */
srcLaneCpu = hPtr[srcLane % group_size];
int* cpuResultsArr = (int*)malloc(sizeof(int) * group_size);
for (int i = 0; i < group_size; i++) {
cpuResultsArr[i] = srcLaneCpu;
}
printf("Array passed to GPU for computation\n");
printResults(hPtr, WAVE_SIZE);
hipMalloc(&dPtr, group_size_in_bytes);
hipMalloc(&dResults, group_size_in_bytes);
hipMemcpy(dPtr, hPtr, group_size_in_bytes, hipMemcpyHostToDevice);
// Launch Kernel
hipLaunchKernelGGL(kernel_shfl, blockSize, threadsPerBlock,
threadsPerBlock * sizeof(int), 0, dPtr, dResults, srcLane, i);
hipMemcpy(hPtr, dResults, group_size_in_bytes, hipMemcpyDeviceToHost);
err = hipDeviceSynchronize();
if (err != hipSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", hipGetErrorString(err));
}
printf("GPU results: \n");
printResults(hPtr, group_size);
printf("Printing cpu to be verified array\n");
printResults(cpuResultsArr, group_size);
compareResults(hPtr, cpuResultsArr, group_size_in_bytes);
std::cout << "Results verified!\n";
hipFree(hPtr);
hipFree(dPtr);
free(cpuResultsArr);
}
}
int main() {
// Use default device for validating the test
int deviceId;
ASSERT_EQUAL(hipGetDevice(&deviceId), hipSuccess);
hipDeviceProp_t deviceProperties;
ASSERT_EQUAL(hipGetDeviceProperties(&deviceProperties, deviceId), hipSuccess);
int maxThreadsPerBlock = deviceProperties.maxThreadsPerBlock;
if (!deviceProperties.cooperativeLaunch) {
std::cout << "info: Device doesn't support cooperative launch! skipping the test!\n";
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
} else {
passed();
}
}
std::cout << "Now testing coalesced_groups" << '\n' << std::endl;
int *data_to_filter, *filtered_data, nres = 0;
int *d_data_to_filter, *d_filtered_data, *d_nres;
int numOfBuckets = 5;
data_to_filter = reinterpret_cast<int *>(malloc(sizeof(int) * NUM_ELEMS));
// Generate input data.
for (int i = 0; i < NUM_ELEMS; i++) {
data_to_filter[i] = rand() % numOfBuckets;
}
hipMalloc(&d_data_to_filter, sizeof(int) * NUM_ELEMS);
hipMalloc(&d_filtered_data, sizeof(int) * NUM_ELEMS);
hipMalloc(&d_nres, sizeof(int));
hipMemcpy(d_data_to_filter, data_to_filter,
sizeof(int) * NUM_ELEMS, hipMemcpyHostToDevice);
hipMemset(d_nres, 0, sizeof(int));
dim3 dimBlock(NUM_THREADS_PER_BLOCK, 1, 1);
dim3 dimGrid((NUM_ELEMS / NUM_THREADS_PER_BLOCK) + 1, 1, 1);
filter_arr<<<dimGrid, dimBlock>>>(d_filtered_data, d_nres, d_data_to_filter,
NUM_ELEMS);
hipMemcpy(&nres, d_nres, sizeof(int), hipMemcpyDeviceToHost);
filtered_data = reinterpret_cast<int *>(malloc(sizeof(int) * nres));
hipMemcpy(filtered_data, d_filtered_data, sizeof(int) * nres,
hipMemcpyDeviceToHost);
int *host_filtered_data =
reinterpret_cast<int *>(malloc(sizeof(int) * NUM_ELEMS));
// Generate host output with host filtering code.
int host_flt_count = 0;
for (int i = 0; i < NUM_ELEMS; i++) {
if (data_to_filter[i] > 0) {
host_filtered_data[host_flt_count++] = data_to_filter[i];
}
}
printf("\nWarp Aggregated Atomics %s \n",
(host_flt_count == nres) ? "PASSED" : "FAILED");
// Now, testing shfl collective
std::cout << "Now testing shfl collective as a broadcast" << '\n' << std::endl;
for (int i = 0; i < 100; i++) {
test_shfl_broadcast();
}
// Now, testing shfl collective
std::cout << "Now testing shfl operations any-to-any member lanes" << '\n' << std::endl;
for (int i = 0; i < 100; i++) {
test_shfl_any_to_any();
}
// Now, pass a already coalesced_group that was partitioned
/* Test coalesced group partitioning */
std::cout << "Now testing coalesced_groups partitioning" << '\n' << std::endl;
int testNo = 1;
for (int memTy = 0; memTy < 2; memTy++) {
std::vector<unsigned int> tileSizes = {2, 4, 8, 16, 32};
for (auto i : tileSizes) {
std::cout << "TEST " << testNo << ":" << '\n' << std::endl;
test_group_partition(i, memTy);
testNo++;
}
}
std::cout << "Now grouping active threads based on branch divergence" << '\n' << std::endl;
test_active_threads_grouping();
passed();
return 0;
}
+32 -3
Просмотреть файл
@@ -105,6 +105,25 @@ bool hipWithoutGraphs(float* inputVec_h, float* inputVec_d, double* outputVec_d,
return true;
}
typedef struct callBackData {
const char* fn_name;
double* data;
} callBackData_t;
double result_gpu = 0.0;
void myHostNodeCallback(void* data) {
static int iter = 0;
iter++;
// Check status of GPU after stream operations are done
callBackData_t* tmp = (callBackData_t*)(data);
// checkCudaErrors(tmp->status);
double* result = (double*)(tmp->data);
char* function = (char*)(tmp->fn_name);
if (iter == GRAPH_LAUNCH_ITERATIONS)
printf("[%s] Host callback final reduced sum = %lf\n", function, *result);
result_gpu = *result;
*result = 0.0; // reset the result
}
bool hipGraphsUsingStreamCapture(float* inputVec_h, float* inputVec_d, double* outputVec_d,
double* result_d, size_t inputSize, size_t numOfBlocks) {
hipStream_t stream1, stream2, stream3, streamForGraph;
@@ -237,6 +256,16 @@ bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d,
nodeDependencies.clear();
nodeDependencies.push_back(memcpyNode);
hipGraphNode_t hostNode;
hipHostNodeParams hostParams = {0};
hostParams.fn = myHostNodeCallback;
callBackData_t hostFnData;
hostFnData.data = &result_h;
hostFnData.fn_name = "hipGraphsManual";
hostParams.userData = &hostFnData;
HIPCHECK(hipGraphAddHostNode(&hostNode, graph, nodeDependencies.data(), nodeDependencies.size(),
&hostParams));
hipGraphExec_t graphExec;
hipGraphNode_t* nodes = NULL;
size_t numNodes = 0;
@@ -266,8 +295,8 @@ bool hipGraphsManual(float* inputVec_h, float* inputVec_d, double* outputVec_d,
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);
if (result_h_cpu != result_gpu) {
printf("Final reduced sum = %lf %lf\n", result_h_cpu, result_gpu);
return false;
}
return true;
@@ -304,4 +333,4 @@ int main(int argc, char** argv) {
failed("Failed during hipGraph with capture\n");
}
passed();
}
}