본문 바로가기

GPGPU/CUDA

CUDA Host<->Device cudaHostGetDevicePointer

반응형

대용량 데이터를 처리하다보니 GPU 메모리 제약으로 처리할 수 없어서 고민하던 중 Host메모리를 Device에서 사용 할 수 있는 방법을 찾았습니다. [cudaHostAlloc, cudaHostGetDevicePointer]

 

개발 환경은 Visual Studio 2013, CUDA ToolK 11.0, GPU 1050, Compute capability 6.1버전에서 테스트를 완료했습니다.

 

파일 2.5GByte를 Host Memory에 할당하고 CUDA Kernel에서 처리하였습니다. 

알고가면 좋은 내용을 간단히 정리하겠습니다.
1. Host에 할당한 메모리는 Read/Write가 모두 가능
2. Host Memory를 할당 시 공유 GPU 메모리 사용량 증가(Host 메모리의 절반 사용가능)
3. Device에서 Host 메모리를 사용하다보니 너무 잦은 메모리 I/O는 성능 저하!!

사용량을 확인하고 싶은 신 경우!!

빨간색 : cudaHostAlloc을 통해 할당 될 경우 공유 GPU 메모리 사용량이 증가합니다.

           [전체 메모리의 절반만큼 사용이 가능하고 Host메모리의 사용량이 증가합니다.]

파란색 : cudaMalloc은 전용 GPU 메모리 사용량!! -> GPU 메모리 제원만큼 사용이 가능!

보라색 : CUDA Kernel이 처리되면 사용량이 증가합니다!!

 

 

 

 

//////////////////////////////////////////
//////////////////////////////////////////
//! 파일을 바이너리에서 읽어옵니다.
BYTE* pbAlt = NULL;
__int64 lSize = 0;
FILE* fileAlt = _wfopen("파일명", L"r+b");
if (fileAlt != NULL)
{
	//read size of file
	_fseeki64(fileAlt, 0, SEEK_END);
	lSize = _ftelli64(fileAlt);
	_fseeki64(fileAlt, 0, SEEK_SET);

	pbAlt = new BYTE[lSize];

	unsigned int totnum = 0;
	unsigned int curnum = 0;
        
	//fread(&dAlt[0], sizeof(unsigned short), 1271012340, fileAlt);
	int nStepFile = 1024 * 64;
	while ((curnum = fread(&pbAlt[totnum], 1, nStepFile, fileAlt)) > 0) {
		totnum += curnum;
	}
	fclose(fileAlt);
}

//////////////////////////////////////////
//////////////////////////////////////////
//! CUDA관련

//! GPU Device상태
cudaDeviceProp m_deviceProp;

//! GPU가 한개 이기 때문에 0인덱스의 정보를 얻어서 HostMemory사용 여부를 확인합니다.
cudaGetDeviceProperties(&m_deviceProp, 0);

if (!m_deviceProp.canMapHostMemory)
{
	fprintf(stderr, "Device does not support mapping CPU host memory!\n");
	return false;
}


char *h_pchAlt = NULL;

if(pbAlt)
{
	//! Host메모리를 할당해 줍니다.(CUDA에서 쓰기위해서 필요합니다.)
	checkCudaErrors(cudaHostAlloc((void **)&h_pchAlt, lSize, cudaHostAllocWriteCombined));
    //! CUDA에서 할당해 준  Host 메모리에 복사해줍니다.
	memcpy(h_pchAlt, pbAlt, lSize);
	
    char *d_pchAlt;
	cudaHostGetDevicePointer((void **)&d_pchAlt, (void *)h_pchAlt, 0);
	
    //! 만든 커널을 통해 데이터를 사용하면 됩니다.(Read, Write 모두 가능)
    KernelTest << < 1, 1024 >> > (d_pchAlt);
    
    //! 커널이 종료될 때 까지 기다려줍니다.
    checkCudaErrors(cudaDeviceSynchronize());
}

cudaFreeHost(h_pchAlt);

delete[] pbAlt;
pbAlt = NULL;

 

c++에서 사용한 전체 로직이며 실제 사용한 소스는 아닙니다. 참고하면 좋을 것 같아서 첨부합니다. 
cudaHostGetDevicePointer 샘플소스는 "CUDA Samples\v11.0\1_Utilities\bandwidthTest"를 참고하는 것도 좋을 것 같습니다.

 

반응형

'GPGPU > CUDA' 카테고리의 다른 글

CUDA 설치 및 설치 실패 대처  (0) 2022.02.18
CUDA 처리 구조  (0) 2019.12.31
CUDA란?  (0) 2019.12.30
GPU 하드웨어 특징  (0) 2019.11.11
GPGPU란?  (0) 2019.11.08