Revert "Revert "Merge branch 'amd-master-next' into amd-npi-next""

This reverts commit 28b17d3dbd.

Reason for revert: <INSERT REASONING HERE>

Change-Id: I92ceb171e31026ed1864704cef2fc1497b883ef9


[ROCm/hip commit: ad2d55c144]
这个提交包含在:
Vladislav Sytchenko 于 2020-10-05 13:20:58 -04:00 提交
1 父节点 28b17d3dbd
当前提交 e4caaa2a77
111 个文件已更改
+6800 -753

没有与搜索条件相匹配的文件

@@ -0,0 +1,227 @@
/*
Copyright (c) 2020 - 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.
*/
/* HIT_START
* BUILD: %t %s ../../test_common.cpp
* TEST: %t
* HIT_END
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include "test_common.h"
#ifdef __linux__
sem_t *sem_ob1 = NULL, *sem_ob2 = NULL;
typedef struct mem_handle {
int device;
hipIpcMemHandle_t memHandle;
bool IfTestPassed;
} hip_ipc_t;
class IpcMemHandleTest {
public:
bool InitFlag = true;
hip_ipc_t *shrd_mem = NULL;
pid_t pid;
size_t N = 1024;
size_t Nbytes = N * sizeof(int);
int *A_d = NULL, out = 0;
int *A_h, *C_h;
int Num_devices = 0, Data_mismatch, CanAccessPeer = 0;
int *Ad1 = NULL, *Ad2 = NULL;
IpcMemHandleTest();
bool Test();
~IpcMemHandleTest();
};
bool IpcMemHandleTest::Test() {
if (InitFlag == false) {
// Abort the test if the initialization fails
printf("Resource initialization failed. Hence test skipped!");
return false;
}
pid = fork();
if (pid != 0) {
// Parent process
HIPCHECK(hipGetDeviceCount(&Num_devices));
for (int i = 0; i < Num_devices; ++i) {
if (shrd_mem->IfTestPassed == true) {
HIPCHECK(hipSetDevice(i));
HIPCHECK(hipMalloc(&A_d, Nbytes));
HIPCHECK(hipIpcGetMemHandle((hipIpcMemHandle_t *) &shrd_mem->memHandle,
A_d));
HIPCHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice));
shrd_mem->device = i;
if ((out=sem_post(sem_ob1)) == -1) {
// Need to use inline function to release resources.
shrd_mem->IfTestPassed = false;
failed("sem_post() call failed in parent process.");
}
if ((out=sem_wait(sem_ob2)) == -1) {
shrd_mem->IfTestPassed = false;
failed("sem_wait() call failed in parent process.");
}
HIPCHECK(hipFree(A_d));
}
}
} else {
// Child process
HIPCHECK(hipGetDeviceCount(&Num_devices));
for (int j = 0; j < Num_devices; ++j) {
if ((out=sem_wait(sem_ob1)) == -1) {
shrd_mem->IfTestPassed = false;
printf("sem_wait() call failed in child process.");
if ((out=sem_post(sem_ob2)) == -1) {
printf("sem_post() call on sem_ob2 failed");
exit(1);
}
}
for (int i = 0; i < Num_devices; ++i) {
Data_mismatch = 0;
HIPCHECK(hipSetDevice(i));
HIPCHECK(hipMalloc(&Ad2, Nbytes));
HIPCHECK(hipIpcOpenMemHandle((void **) &Ad1, shrd_mem->memHandle,
hipIpcMemLazyEnablePeerAccess));
HIPCHECK(hipDeviceCanAccessPeer(&CanAccessPeer, i, shrd_mem->device));
if (CanAccessPeer == 1) {
HIPCHECK(hipMemcpy(Ad2, Ad1, Nbytes, hipMemcpyDeviceToDevice));
HIPCHECK(hipMemcpy(C_h, Ad2, Nbytes, hipMemcpyDeviceToDevice));
for (int i = 0; i < N; ++i) {
if (C_h[i] != 123)
Data_mismatch++;
}
if (Data_mismatch != 0) {
printf("Data mismatch found when data copied from Ipc memhandle");
printf(" to Device: %d\n", i);
shrd_mem->IfTestPassed = false;
}
memset(reinterpret_cast<void*>(C_h), 0, Nbytes);
// Checking if the data obtained from Ipc shared memory is consistent
HIPCHECK(hipMemcpy(C_h, Ad1, Nbytes, hipMemcpyDeviceToHost));
for (int i = 0; i < N; ++i) {
if (C_h[i] != 123)
Data_mismatch++;
}
if (Data_mismatch != 0) {
printf("Data mismatch found when data copied from Ipc memhandle");
printf(" Host.\n");
shrd_mem->IfTestPassed = false;
}
}
HIPCHECK(hipIpcCloseMemHandle(reinterpret_cast<void*>(Ad1)));
}
HIPCHECK(hipFree(Ad2));
if ((out=sem_post(sem_ob2)) == -1) {
shrd_mem->IfTestPassed = false;
printf("sem_post() call on sem_ob2 failed");
exit(1);
}
}
exit(0);
}
if ((out = sem_unlink("/my-sem-object1")) == -1) {
printf("sem_unlink() call on /my-sem-object1 failed");
}
if ((out = sem_unlink("/my-sem-object2")) == -1) {
printf("sem_unlink() call on /my-sem-object2 failed");
}
int status;
waitpid(pid, &status, 0);
if (shrd_mem->IfTestPassed == false) {
return false;
} else {
return true;
}
}
IpcMemHandleTest::IpcMemHandleTest() {
std::string cmd_line = "rm -rf /dev/shm/sem.my-sem-object*";
int res = system(cmd_line.c_str());
if (res == -1) {
InitFlag = false;
printf("System call to remove existing shared objects failed!");
}
int out;
if ((sem_ob1 = sem_open ("/my-sem-object1", O_CREAT|O_EXCL, 0660, 0)) ==
SEM_FAILED) {
InitFlag = false;
printf("Initialization of 1st semaphore object failed");
}
if ((sem_ob2 = sem_open ("/my-sem-object2", O_CREAT|O_EXCL, 0660, 0)) ==
SEM_FAILED) {
InitFlag = false;
printf("Initialization of 2nd semaphore object failed");
}
shrd_mem = reinterpret_cast<hip_ipc_t *>(mmap(NULL, sizeof(hip_ipc_t),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
0, 0));
if (shrd_mem == NULL) {
InitFlag = false;
printf("mmap() call failed!");
}
shrd_mem->IfTestPassed = true;
A_h = reinterpret_cast<int*>(malloc(Nbytes));
C_h = reinterpret_cast<int*>(malloc(Nbytes));
for (size_t i = 0; i < N; i++) {
A_h[i] = 123;
}
}
IpcMemHandleTest::~IpcMemHandleTest() {
munmap(shrd_mem, sizeof(hip_ipc_t));
HIPCHECK(hipFree((A_d)));
free(A_h);
free(C_h);
HIPCHECK(hipFree((Ad1)));
HIPCHECK(hipFree((Ad2)));
}
#endif
int main() {
bool IfTestPassed = true;
// The following program spawns a child process and does the following
// Parent iterate through each device, create memory -- create hipIpcMemhandle
// stores the mem handle in mmaped memory, release the child using sem_post()
// and wait for child to release itself(parent process)
// child process:
// Child process get the ipc mem handle using hipIpcOpenMemHandle
// Iterate through all the available gpus and do Device to Device copies
// and check for data consistencies and close the hipIpcCloseMemHandle
// release the parent and wait for parent to release itself(child)
#ifdef __linux__
IpcMemHandleTest obj;
IfTestPassed = obj.Test();
#else
printf("This is not a Linux platform. Hence Skipping the test!\n");
IfTestPassed = true;
#endif
if (IfTestPassed == false) {
failed("");
}
passed();
}
@@ -0,0 +1,487 @@
/*
Copyright (c) 2020-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 WARRANNTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
Testcase Scenarios :
(TestCase 1)::
1) Test hipMalloc() api passing zero size and confirming *ptr returning
nullptr. Also pass nullptr to hipFree() api.
2) Pass maximum value of size_t for hipMalloc() api and make sure appropriate
error is returned.
3) Check for hipMalloc() error code, passing invalid/null pointer.
(TestCase 2)::
4) Regress hipMalloc()/hipFree() in loop for bigger chunk of allocation
with adequate number of iterations and later test for kernel execution on
default gpu.
5) Regress hipMalloc()/hipFree() in loop while allocating smaller chunks
keeping maximum number of iterations and then run kernel code on default
gpu, perfom data validation.
(TestCase 3)::
6) Check hipMalloc() api adaptability when app creates small chunks of memory
continuously, stores it for later use and then frees it at later point
of time.
(TestCase 4)::
7) Run hipMalloc() api/kernel code on same gpu parallely from parent and child
processes, validate the results.
(TestCase 5)::
8) Execute hipMalloc() api simultaneously on all the gpus by spawning multiple
child processes. Validate buffers allocated after running kernel code.
(TestCase 6)::
9) Multithread Scenario : Exercise hipMalloc() api parellely on all gpus from
multiple threads and regress the api.
(TestCases 2, 3, 4, 5, 6)::
10) Validate memory usage with hipMemGetInfo() while regressing hipMalloc()
api. Check for any possible memory leaks.
*/
/* HIT_START
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS --std=c++11
* TEST_NAMED: %t hipMalloc_ArgValidation --tests 1
* TEST_NAMED: %t hipMalloc_LoopRegression_AllocFreeCycle --tests 2
* TEST_NAMED: %t hipMalloc_LoopRegression_AllocPool --tests 3
* TEST_NAMED: %t hipMallocChild_Concurrency_DefaultGpu --tests 4
* TEST_NAMED: %t hipMallocChild_Concurrency_MultiGpu --tests 5
* TEST_NAMED: %t hipMalloc_MultiThreaded_MultiGpu --tests 6
* HIT_END
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <limits>
#include <atomic>
#include "test_common.h"
/* Max alloc/free iterations for bigger chunks */
#define MAX_ALLOCFREE_BC (10000)
/* Buffer size for alloc/free cycles */
#define BUFF_SIZE_AF (5*1024*1024)
/* Max alloc/free iterations for smaller chunks */
#define MAX_ALLOCFREE_SC (5000000)
/* Max alloc and pool iterations (TBD) */
#define MAX_ALLOCPOOL_ITER (2000000)
/**
* Validates data consitency on supplied gpu
*/
bool validateMemoryOnGPU(int gpu) {
size_t Nbytes = N * sizeof(int);
int *A_d, *B_d, *C_d;
int *A_h, *B_h, *C_h;
size_t prevAvl, prevTot, curAvl, curTot;
bool TestPassed = true;
HIPCHECK(hipSetDevice(gpu));
HIPCHECK(hipMemGetInfo(&prevAvl, &prevTot));
HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false);
unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N);
HIPCHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice));
HIPCHECK(hipMemcpy(B_d, B_h, Nbytes, hipMemcpyHostToDevice));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock),
0, 0, static_cast<const int*>(A_d),
static_cast<const int*>(B_d), C_d, N);
HIPCHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost));
if (!HipTest::checkVectorADD(A_h, B_h, C_h, N)) {
printf("Validation PASSED for gpu %d from pid %d\n", gpu, getpid());
} else {
printf("%s : Validation FAILED for gpu %d from pid %d\n",
__func__, gpu, getpid());
TestPassed &= false;
}
HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false);
HIPCHECK(hipMemGetInfo(&curAvl, &curTot));
if ((prevAvl != curAvl) || (prevTot != curTot)) {
printf("%s : Memory allocation mismatch observed."
"Possible memory leak.", __func__);
TestPassed &= false;
}
return TestPassed;
}
/**
* Fetches Gpu device count
*/
void getDeviceCount(int *pdevCnt) {
#ifdef __linux__
int fd[2], val = 0;
pid_t childpid;
// create pipe descriptors
pipe(fd);
// disable visible_devices env from shell
unsetenv("ROCR_VISIBLE_DEVICES");
unsetenv("HIP_VISIBLE_DEVICES");
childpid = fork();
if (childpid > 0) { // Parent
close(fd[1]);
// parent will wait to read the device cnt
read(fd[0], &val, sizeof(val));
// close the read-descriptor
close(fd[0]);
// wait for child exit
wait(NULL);
*pdevCnt = val;
} else if (!childpid) { // Child
int devCnt = 1;
// writing only, no need for read-descriptor
close(fd[0]);
HIPCHECK(hipGetDeviceCount(&devCnt));
// send the value on the write-descriptor:
write(fd[1], &devCnt, sizeof(devCnt));
// close the write descriptor:
close(fd[1]);
exit(0);
} else { // failure
*pdevCnt = 1;
return;
}
#else
HIPCHECK(hipGetDeviceCount(pdevCnt));
#endif
}
/**
* Regress memory allocation and free in loop
*/
bool regressAllocInLoop(int gpu) {
bool TestPassed = true;
size_t tot, avail, ptot, pavail;
int i = 0;
int *ptr;
HIPCHECK(hipSetDevice(gpu));
// Exercise allocation in loop with bigger chunks
for (i = 0; i < MAX_ALLOCFREE_BC; i++) {
size_t numBytes = BUFF_SIZE_AF;
HIPCHECK(hipMemGetInfo(&pavail, &ptot));
HIPCHECK(hipMalloc(&ptr, numBytes));
HIPCHECK(hipMemGetInfo(&avail, &tot));
if (pavail-avail != numBytes) {
printf("LoopAllocation : Memory allocation of %6.2fMB"
"not matching with hipMemGetInfo - FAIL\n",
numBytes/(1024.0*1024.0));
TestPassed &= false;
HIPCHECK(hipFree(ptr));
break;
}
HIPCHECK(hipFree(ptr));
}
// Exercise allocation in loop with smaller chunks and max iters
HIPCHECK(hipMemGetInfo(&pavail, &ptot));
for (i = 0; i < MAX_ALLOCFREE_SC; i++) {
size_t numBytes = 16;
HIPCHECK(hipMalloc(&ptr, numBytes));
HIPCHECK(hipFree(ptr));
}
HIPCHECK(hipMemGetInfo(&avail, &tot));
if ((pavail != avail) || (ptot != tot)) {
printf("LoopAllocation : Memory allocation mismatch observed."
"Possible memory leak.");
TestPassed &= false;
}
return TestPassed;
}
/*
* Thread func to regress alloc and check data consistency
*/
std::atomic<bool> g_thTestPassed(true);
void threadFunc(int gpu) {
g_thTestPassed = g_thTestPassed & regressAllocInLoop(gpu);
g_thTestPassed = g_thTestPassed & validateMemoryOnGPU(gpu);
printf("thread execution status on gpu(%d) : %d\n", gpu, g_thTestPassed.load());
}
int main(int argc, char* argv[]) {
HipTest::parseStandardArguments(argc, argv, true);
if (p_tests == 1) { // Arg validation
// Test hipMalloc for zero size
bool TestPassed = true;
int *ptr;
HIPCHECK(hipMalloc(&ptr, 0));
// ptr expected to be reset to null ptr
if (ptr) {
printf("ArgValidation : Failed in zero size test\n");
TestPassed &= false;
}
// Free null ptr
HIPCHECK(hipFree(ptr));
// Test hipMalloc for invalid arguments
hipError_t ret;
if ((ret = hipMalloc(NULL, 100)) != hipErrorInvalidValue) {
printf("ArgValidation : Inappropritate error value returned"
" for invalid argument. Error: '%s'(%d)\n",
hipGetErrorString(ret), ret);
TestPassed &= false;
}
// Test hipMalloc for Maximum value of size_t
if ((ret = hipMalloc(&ptr, std::numeric_limits<std::size_t>::max()))
!= hipErrorMemoryAllocation) {
printf("ArgValidation : Invalid error returned for max size_t."
" Error: '%s'(%d)\n", hipGetErrorString(ret), ret);
TestPassed &= false;
}
if (TestPassed) {
passed();
} else {
failed("hipMalloc ArgumentValidation Failure!");
}
} else if (p_tests == 2) { // Loop Regression Alloc/Free Cycle
bool TestPassed = true;
TestPassed &= regressAllocInLoop(0);
TestPassed &= validateMemoryOnGPU(0);
if (TestPassed) {
passed();
} else {
failed("hipMalloc_LoopRegression_AllocFreeCycle Failure!");
}
} else if (p_tests == 3) { // Loop Regression Alloc and Pool
size_t avail, tot, pavail, ptot;
bool TestPassed = true;
hipError_t err;
int *ptr;
std::vector<int *> ptrlist;
HIPCHECK(hipMemGetInfo(&pavail, &ptot));
// Allocate small chunks of memory million times
for (int i = 0; i < MAX_ALLOCPOOL_ITER; i++) { // Iterations TBD
if ((err = hipMalloc(&ptr, 10)) != hipSuccess) {
HIPCHECK(hipMemGetInfo(&avail, &tot));
printf("Loop regression pool allocation failure. "
"Total gpu memory : %6.2fMB, Free memory %6.2fMB iter %d error '%s'\n",
tot/(1024.0*1024.0), avail/(1024.0*1024.0), i, hipGetErrorString(err));
TestPassed &= false;
break;
}
// Store pointers allocated to emulate memory pool of app
ptrlist.push_back(ptr);
}
// Free ptrs at later point of time
for ( auto &t : ptrlist ) {
HIPCHECK(hipFree(t));
}
HIPCHECK(hipMemGetInfo(&avail, &tot));
TestPassed &= validateMemoryOnGPU(0);
if ((pavail != avail) || (ptot != tot)) {
printf("%s : Memory allocation mismatch observed. Possible memory leak.",
__func__);
TestPassed &= false;
}
if (TestPassed) {
passed();
} else {
failed("hipMalloc_LoopRegression_AllocPool failure!");
}
} else if (p_tests == 4) {
bool TestPassed = true;
#ifdef __linux__
// Parallel execution of parent and child on gpu0
int pid;
if ((pid = fork()) < 0) {
printf("Child_Concurrency_Gpu0 : fork() returned error %d.", pid);
TestPassed &= false;
} else if (!pid) { // Child process
bool TestPassedChild = true;
TestPassedChild = validateMemoryOnGPU(0);
if (TestPassedChild) {
exit(0); // child exit with success status
} else {
printf("Child_Concurrency_Gpu0 : childpid %d failed\n", getpid());
exit(1); // child exit with failure status
}
} else { // Parent process
int exitStatus;
TestPassed = validateMemoryOnGPU(0);
pid = wait(&exitStatus);
if ( WEXITSTATUS(exitStatus) || ( pid < 0 ) )
TestPassed &= false;
}
#else
printf("Test hipMallocChild_Concurrency_DefaultGpu skipped on non-linux\n");
#endif
// TC scenarios specific to linux
// are treated as pass in windows.
if (TestPassed) {
passed();
} else {
failed("hipMallocChild_Concurrency_DefaultGpu Failed!");
}
} else if (p_tests == 5) {
bool TestPassed = true;
#ifdef __linux__
// Parallel execution on multiple gpus from different child processes
int devCnt = 1, pid = 0, cumStatus = 0;
// Get GPU count
getDeviceCount(&devCnt);
// Spawn child for each GPU
for (int gpu = 0; gpu < devCnt; gpu++) {
if ((pid = fork()) < 0) {
printf("Child_Concurrency_MultiGpu : fork() returned error %d\n", pid);
failed("Test Failed!");
} else if (!pid) { // Child process
bool TestPassedChild = true;
TestPassedChild = validateMemoryOnGPU(gpu);
if (TestPassedChild) {
exit(0); // child exit with success status
} else {
printf("Child_Concurrency_MultiGpu : childpid %d failed\n",
getpid());
exit(1); // child exit with failure status
}
}
}
// Parent shall wait for child to complete
for (int i = 0; i < devCnt; i++) {
int pidwait = 0, exitStatus;
pidwait = wait(&exitStatus);
if (pidwait < 0) {
TestPassed &= false;
break;
}
cumStatus |= WEXITSTATUS(exitStatus);
}
// Cummulative status of all child
if (cumStatus) {
TestPassed &= false;
}
#else
printf("Test hipMallocChild_Concurrency_MultiGpu skipped on non-linux\n");
#endif
// TC scenarios specific to linux
// are treated as pass in windows.
if (TestPassed) {
passed();
} else {
failed("hipMallocChild_Concurrency_MultiGpu Failed!");
}
} else if (p_tests == 6) { // Multithreaded multiple gpu execution
std::vector<std::thread> threadlist;
int devCnt = 1;
// Get GPU count
getDeviceCount(&devCnt);
for (int i = 0; i < devCnt; i++) {
threadlist.push_back(std::thread(threadFunc, i));
}
for (auto &t : threadlist) {
t.join();
}
if (g_thTestPassed) {
passed();
} else {
failed("hipMalloc_MultiThreaded_MultiGpu Failed!");
}
} else {
failed("Didnt receive any valid option. Try options 1 to 6\n");
}
}
@@ -0,0 +1,423 @@
/*
Copyright (c) 2020 - 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 6 is disabled */
/* HIT_START
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS -std=c++11
* TEST_NAMED: %t hipMallocManaged1 --tests 1
* TEST_NAMED: %t hipMallocManaged2 --tests 2
* TEST_NAMED: %t hipMallocManagedNegativeTests --tests 3
* TEST_NAMED: %t hipMallocManagedMultiChunkSingleDevice --tests 4
* TEST_NAMED: %t hipMallocManagedMultiChunkMultiDevice --tests 5 EXCLUDE_HIP_PLATFORM nvcc
* TEST_NAMED: %t hipMallocManagedOversubscription --tests 6 EXCLUDE_HIP_PLATFORM rocclr nvcc
* HIT_END
*/
#include <atomic>
#include "test_common.h"
#define N 1048576 // equals to (1024*1024)
#define INIT_VAL 123
/*
* Kernel function to perform addition operation.
*/
template <typename T>
__global__ void
vector_sum(T *Ad1, T *Ad2, size_t NUM_ELMTS) {
size_t offset = (blockIdx.x * blockDim.x + threadIdx.x);
size_t stride = blockDim.x * gridDim.x;
for (size_t i = offset; i < NUM_ELMTS; i += stride) {
Ad2[i] = Ad1[i] + Ad1[i];
}
}
// The following Test case tests the following scenario:
// A large chunk of hipMallocManaged() memory(Hmm) is created
// Equal parts of Hmm is accessed on available gpus and
// kernel is launched on acessed chunk of hmm memory
// and checks if there are any inconsistencies or access issues
bool MultiChunkMultiDevice(int NumDevices) {
std::atomic<int> DataMismatch{0};
bool IfTestPassed = true;
int Counter = 0;
unsigned int NUM_ELMS = (1024 * 1024);
float *Ad[NumDevices], *Hmm = NULL, *Ah = new float[NUM_ELMS];
hipStream_t stream[NumDevices];
for (int Oloop = 0; Oloop < NumDevices; ++Oloop) {
HIPCHECK(hipSetDevice(Oloop));
HIPCHECK(hipMalloc(&Ad[Oloop], NUM_ELMS * sizeof(float)));
HIPCHECK(hipMemset(Ad[Oloop], 0, NUM_ELMS * sizeof(float)));
HIPCHECK(hipStreamCreate(&stream[Oloop]));
}
HIPCHECK(hipMallocManaged(&Hmm, (NumDevices * NUM_ELMS * sizeof(float))));
for (int i = 0; i < NumDevices; ++i) {
for (; Counter < ((i + 1) * NUM_ELMS); ++Counter) {
Hmm[Counter] = INIT_VAL + i;
}
}
const unsigned threadsPerBlock = 256;
const unsigned blocks = (NUM_ELMS + 255)/256;
for (int Klaunch = 0; Klaunch < NumDevices; ++Klaunch) {
vector_sum<float> <<<blocks, threadsPerBlock, 0, stream[Klaunch]>>>
(&Hmm[Klaunch * NUM_ELMS], Ad[Klaunch], NUM_ELMS);
}
HIPCHECK(hipDeviceSynchronize());
for (int m = 0; m < NumDevices; ++m) {
HIPCHECK(hipMemcpy(Ah, Ad[m], NUM_ELMS * sizeof(float),
hipMemcpyDeviceToHost));
for (int n = 0; n < NUM_ELMS; ++n) {
if (Ah[n] != ((INIT_VAL + m) * 2)) {
DataMismatch++;
}
}
memset(reinterpret_cast<void*>(Ah), 0, NUM_ELMS * sizeof(float));
}
if (DataMismatch.load() != 0) {
printf("MultiChunkMultiDevice: Mismatch observed!\n");
IfTestPassed = false;
}
for (int i = 0; i < NumDevices; ++i) {
HIPCHECK(hipFree(Ad[i]));
HIPCHECK(hipStreamDestroy(stream[i]));
}
HIPCHECK(hipFree(Hmm));
free(Ah);
return IfTestPassed;
}
// The following Test case tests the following scenario:
// A large chunk of hipMallocManaged() memory(Hmm) is created
// Equal parts of Hmm is accessed and
// kernel is launched on acessed chunk of hmm memory
// and checks if there are any inconsistencies or access issues
bool MultiChunkSingleDevice(int NumDevices) {
std::atomic<int> DataMismatch{0};
int Chunks = 4, Counter = 0;
bool IfTestPassed = true;
unsigned int NUM_ELMS = (1024 * 1024);
float *Ad[Chunks], *Hmm = NULL, *Ah = new float[NUM_ELMS];
hipStream_t stream[Chunks];
for (int i = 0; i < Chunks; ++i) {
HIPCHECK(hipMalloc(&Ad[i], NUM_ELMS * sizeof(float)));
HIPCHECK(hipMemset(Ad[i], 0, NUM_ELMS * sizeof(float)));
HIPCHECK(hipStreamCreate(&stream[i]));
}
HIPCHECK(hipMallocManaged(&Hmm, (Chunks * NUM_ELMS * sizeof(float))));
for (int i = 0; i < Chunks; ++i) {
for (; Counter < ((i + 1) * NUM_ELMS); ++Counter) {
Hmm[Counter] = (INIT_VAL + i);
}
}
const unsigned threadsPerBlock = 256;
const unsigned blocks = (NUM_ELMS + 255)/256;
for (int k = 0; k < Chunks; ++k) {
vector_sum<float> <<<blocks, threadsPerBlock, 0, stream[k]>>>
(&Hmm[k * NUM_ELMS], Ad[k], NUM_ELMS);
}
HIPCHECK(hipDeviceSynchronize());
for (int m = 0; m < Chunks; ++m) {
HIPCHECK(hipMemcpy(Ah, Ad[m], NUM_ELMS * sizeof(float),
hipMemcpyDeviceToHost));
for (int n = 0; n < NUM_ELMS; ++n) {
if (Ah[n] != ((INIT_VAL + m) * 2)) {
DataMismatch++;
}
}
}
if (DataMismatch.load() != 0) {
printf("MultiChunkSingleDevice: Mismatch observed!\n");
IfTestPassed = false;
}
for (int i = 0; i < Chunks; ++i) {
HIPCHECK(hipFree(Ad[i]));
HIPCHECK(hipStreamDestroy(stream[i]));
}
HIPCHECK(hipFree(Hmm));
free(Ah);
return IfTestPassed;
}
// The following tests oversubscription hipMallocManaged() api
// Currently disabled.
bool TestOversubscriptionMallocManaged(int NumDevices) {
bool IfTestPassed = true;
hipError_t err;
void *A = NULL;
size_t total = 0, free = 0;
HIPCHECK(hipMemGetInfo(&free, &total));
// ToDo: In case of HMM, memory over-subscription is allowed. Hence, relook
// into how out of memory can be tested.
// Demanding more mem size than available
err = hipMallocManaged(&A, (free +1), hipMemAttachGlobal);
if (hipErrorOutOfMemory != err) {
printf("hipMallocManaged: Returned %s for size value > device memory\n",
hipGetErrorString(err));
IfTestPassed = false;
}
return IfTestPassed;
}
// The following test does negative testing of hipMallocManaged() api
// by passing invalid values and check if the behavior is as expected
bool NegativeTestsMallocManaged(int NumDevices) {
bool IfTestPassed = true;
hipError_t err;
void *A = NULL;
size_t total = 0, free = 0;
HIPCHECK(hipMemGetInfo(&free, &total));
err = hipMallocManaged(NULL, 1024, hipMemAttachGlobal);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s when devPtr is null\n",
hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&A, 0, hipMemAttachGlobal);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s when size is 0\n",
hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(NULL, 0, hipMemAttachGlobal);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s when devPtr & size is null & 0\n",
hipGetErrorString(err));
IfTestPassed = false;
}
#ifdef __HIP_PLATFORM_HCC__
// The flag hipMemAttachHost is currently not supported therefore
// api should return "hipErrorInvalidValue" for now
err = hipMallocManaged(&A, 1024, hipMemAttachHost);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s for 'hipMemAttachHost' flag\n",
hipGetErrorString(err));
IfTestPassed = false;
}
#endif // __HIP_PLATFORM_HCC__
err = hipMallocManaged(NULL, 0, 0);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s when params are null, 0, 0\n",
hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&A, 1024, 145);
if (hipErrorInvalidValue != err) {
printf("hipMallocManaged: Returned %s when flag param is numerical 145\n",
hipGetErrorString(err));
IfTestPassed = false;
}
err = hipMallocManaged(&A, -10, hipMemAttachGlobal);
if (hipErrorOutOfMemory != err) {
printf("hipMallocManaged: Returned %s for negative size value.\n",
hipGetErrorString(err));
IfTestPassed = false;
}
return IfTestPassed;
}
// Allocate two pointers using hipMallocManaged(), initialize,
// then launch kernel using these pointers directly and
// later validate the content without using any Memcpy.
template <typename T>
bool TestMallocManaged2(int NumDevices) {
bool IfTestPassed = true;
T *Hmm1 = NULL, *Hmm2 = NULL;
for (int i = 0; i < NumDevices; ++i) {
HIPCHECK(hipSetDevice(i));
std::atomic<int> DataMismatch{0};
HIPCHECK(hipMallocManaged(&Hmm1, N * sizeof(T)));
HIPCHECK(hipMallocManaged(&Hmm2, N * sizeof(T)));
for (int m = 0; m < N; ++m) {
Hmm1[m] = m;
Hmm2[m] = 0;
}
const unsigned threadsPerBlock = 256;
const unsigned blocks = (N + 255)/256;
// Kernel launch
vector_sum <<<blocks, threadsPerBlock>>> (Hmm1, Hmm2, N);
HIPCHECK(hipDeviceSynchronize());
for (int v = 0; v < N; ++v) {
if (Hmm2[v] != (v + v)) {
DataMismatch++;
}
}
if (DataMismatch.load() != 0) {
IfTestPassed = false;
}
HIPCHECK(hipFree(Hmm1));
HIPCHECK(hipFree(Hmm2));
}
return IfTestPassed;
}
// In the following test, a memory is created using hipMallocManaged() by
// setting a device and verified if it is accessible when the context is set
// to all other devices. This include verification and Device two Device
// transfers and kernel launch o discover if there any access issues.
template <typename T>
bool TestMallocManaged1(int NumDevices) {
std::atomic<unsigned int> DataMismatch;
bool TestPassed = true;
T *Ah1 = new T[N], *Ah2 = new T[N], *Ad = NULL, *Hmm = NULL;
for (int i =0; i < N; ++i) {
Ah1[i] = INIT_VAL;
Ah2[i] = 0;
}
for (int Oloop = 0; Oloop < NumDevices; ++Oloop) {
DataMismatch = 0;
HIPCHECK(hipSetDevice(Oloop));
HIPCHECK(hipMallocManaged(&Hmm, N * sizeof(T)));
for (int Iloop = 0; Iloop < NumDevices; ++Iloop) {
HIPCHECK(hipSetDevice(Iloop));
HIPCHECK(hipMalloc(&Ad, N * sizeof(T)));
// Copy data from host to hipMallocMananged memory and verify
HIPCHECK(hipMemcpy(Hmm, Ah1, N * sizeof(T), hipMemcpyHostToDevice));
for (int v = 0; v < N; ++v) {
if (Hmm[v] != INIT_VAL) {
DataMismatch++;
}
}
if (DataMismatch.load() != 0) {
printf("Mismatch is observed with host data at device %d", Iloop);
printf(" while hipMallocManaged memory set to the device %d\n", Oloop);
TestPassed = false;
DataMismatch = 0;
}
// Executing D2D transfer with hipMallocManaged memory and verify
HIPCHECK(hipMemcpy(Ad, Hmm, N * sizeof(T), hipMemcpyDeviceToDevice));
HIPCHECK(hipMemcpy(Ah2, Ad, N * sizeof(T), hipMemcpyDeviceToHost));
for (int k = 0; k < N; ++k) {
if (Ah2[k] != INIT_VAL) {
DataMismatch++;
}
}
if (DataMismatch.load() != 0) {
printf("Mismatch is observed with D2D transfer at device %d\n", Iloop);
printf(" while hipMallocManaged memory set to the device %d\n", Oloop);
TestPassed = false;
DataMismatch = 0;
}
HIPCHECK(hipMemset(Ad, 0, N * sizeof(T)));
const unsigned threadsPerBlock = 256;
const unsigned blocks = (N + 255)/256;
// Launching the kernel to check if there is any access issue with
// hipMallocManaged memory and local device's memory
vector_sum <<<blocks, threadsPerBlock>>> (Hmm, Ad, N);
hipDeviceSynchronize();
HIPCHECK(hipMemcpy(Ah2, Ad, N * sizeof(T), hipMemcpyDeviceToHost));
for (int m = 0; m < N; ++m) {
if (Ah2[m] != 246) {
DataMismatch++;
}
}
if (DataMismatch.load() != 0) {
printf("Data Mismatch observed after kernel lch device %d\n", Iloop);
TestPassed = false;
DataMismatch = 0;
}
HIPCHECK(hipFree(Ad));
}
HIPCHECK(hipFree(Hmm));
}
free(Ah1);
free(Ah2);
return TestPassed;
}
int main(int argc, char* argv[]) {
HipTest::parseStandardArguments(argc, argv, true);
if ((p_tests <= 0) || (p_tests > 5)) {
failed("Valid arguments are from 1 to 5");
}
int NumDevices = 0;
HIPCHECK(hipGetDeviceCount(&NumDevices));
bool TestStatus = true, OverAllStatus = true;
if (p_tests == 1) {
TestStatus = TestMallocManaged1<float>(NumDevices);
if (!TestStatus) {
printf("Test Failed with float datatype.\n");
OverAllStatus = false;
}
TestStatus = TestMallocManaged1<int>(NumDevices);
if (!TestStatus) {
printf("Test Failed with int datatype.\n");
OverAllStatus = false;
}
TestStatus = TestMallocManaged1<unsigned char>(NumDevices);
if (!TestStatus) {
printf("Test Failed with unsigned char datatype.\n");
OverAllStatus = false;
}
TestStatus = TestMallocManaged1<double>(NumDevices);
if (!TestStatus) {
printf("Test Failed with double datatype.\n");
OverAllStatus = false;
}
if (!OverAllStatus) {
failed("");
}
}
if (p_tests == 2) {
TestStatus = TestMallocManaged2<float>(NumDevices);
if (!TestStatus) {
failed("Test Failed with float datatype.");
}
}
if (p_tests == 3) {
TestStatus = NegativeTestsMallocManaged(NumDevices);
if (!TestStatus) {
failed("Negative Tests with hipMallocManaged() failed!.");
}
}
if (p_tests == 4) {
TestStatus = MultiChunkSingleDevice(NumDevices);
if (!TestStatus) {
failed("hipMallocManaged: MultiChunkSingleDevice test failed!");
}
}
if (p_tests == 5) {
TestStatus = MultiChunkMultiDevice(NumDevices);
if (!TestStatus) {
failed("hipMallocManaged: MultiChunkMultiDevice test failed!");
}
}
if (p_tests == 6) {
TestStatus = TestOversubscriptionMallocManaged(NumDevices);
if (!TestStatus) {
failed("hipMallocManaged: TestOversubscriptionMallocManaged failed!");
}
}
passed();
}
@@ -75,6 +75,9 @@ int main() {
HIPCHECK(hipFree(Z_d));
} else {
std::cout<<"Machine does not seem to have P2P Capabilities, Empty Pass"<<std::endl;
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
}
}
}
@@ -81,6 +81,9 @@ int main() {
HIPCHECK(hipFree(Z_d));
} else {
std::cout<<"Machine does not seem to have P2P Capabilities, Empty Pass"<<std::endl;
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
}
}
}
@@ -77,6 +77,9 @@ int main() {
HIPCHECK(hipFree(Z_d));
} else {
std::cout<<"Machine does not seem to have P2P Capabilities, Empty Pass"<<std::endl;
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
}
}
}
passed();
@@ -83,6 +83,9 @@ int main() {
HIPCHECK(hipFree(Z_d));
} else {
std::cout<<"Machine does not seem to have P2P Capabilities, Empty Pass"<<std::endl;
if (hip_skip_tests_enabled()) {
return hip_skip_retcode();
}
}
}
@@ -24,7 +24,7 @@ THE SOFTWARE.
*/
/* HIT_START
* BUILD: %t %s ../../test_common.cpp
* BUILD: %t %s ../../test_common.cpp EXCLUDE_HIP_PLATFORM nvcc
* TEST: %t
* HIT_END
*/
@@ -24,7 +24,7 @@ THE SOFTWARE.
*/
/* HIT_START
* BUILD: %t %s ../../test_common.cpp
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS -std=c++11 EXCLUDE_HIP_PLATFORM nvcc
* TEST: %t
* HIT_END
*/
@@ -20,7 +20,7 @@
// Test for hipMemset2D functionality for different width and height values
/* HIT_START
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS -std=c++11
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS -std=c++11 EXCLUDE_HIP_PLATFORM nvcc
* TEST_NAMED: %t hipMemset2D-basic
* TEST_NAMED: %t hipMemset2D-dim1 --width2D 10 --height2D 10 --memsetWidth 4 --memsetHeight 4
* TEST_NAMED: %t hipMemset2D-dim2 --width2D 100 --height2D 100 --memsetWidth 20 --memsetHeight 40
@@ -21,7 +21,7 @@
// and also launch hipMemcpyAsync() api on the same stream. This test case is simulate the scenario
// reported in SWDEV-181598.
/* HIT_START
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS --std=c++11
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS --std=c++11 EXCLUDE_HIP_PLATFORM nvcc
* TEST: %t
* HIT_END
*/
@@ -21,7 +21,7 @@
// and also launch hipMemcpyAsync() api. This test case is simulate the scenario
// reported in SWDEV-181598.
/* HIT_START
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS --std=c++11
* BUILD: %t %s ../../test_common.cpp NVCC_OPTIONS --std=c++11 EXCLUDE_HIP_PLATFORM nvcc
* TEST: %t
* HIT_END
*/