728x90
// show memory usage of GPU

size_t free_byte ;
size_t total_byte ;

cuda_status = cudaMemGetInfo( &free_byte, &total_byte ) ;

if ( cudaSuccess != cuda_status )
{
printf("Error: cudaMemGetInfo fails, %s \n", cudaGetErrorString(cuda_status) );
exit(1);
}

double free_db = (double)free_byte ;
double total_db = (double)total_byte ;
double used_db = total_db - free_db ;

printf("GPU memory usage: used = %f, free = %f MB, total = %f MB\n",
used_db/1024.0/1024.0, free_db/1024.0/1024.0, total_db/1024.0/1024.0);


출처 : https://devtalk.nvidia.com/default/topic/487541/best-way-to-report-memory-consumption-in-cuda-/?offset=1

728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - 스트림(stream)  (0) 2016.03.03
CUDA - 고정 메모리(cudaHostAlloc())  (0) 2016.03.03
CUDA - 원자적 연산  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
728x90

CUDA Stream은 어플리케이션을 가속시키는 데 중요한 역할을 한다. 하나의 CUDA Stream은 하나의 큐를 나타내며, 여기에는 특정 순서에 따라 실행될 GPU 작업들이 추가되어 있다. 커널의 실행, 메모리 복사 그리고 이벤트의 시작과 중지와 같은 작업들을 하나의 스트림에 추가할 수 있다. 스트림에 추가된 작업들의 순서가 곧 실행될 순서를 의미한다. 각 스트림을 GPU 상의 하나의 태스크로 여길 수 있으며, 이러한 태스크들은 병렬로 실행될 수 있다. 


CUDA Stream을 사용하기 위해서는 디바이스 오버랩(Device Overlap)이라고 알려진 기능을 제공하는지 확인해야한다.


CUDA Stream을 사용하는 방법은 다음과 같다.

CUDA Stream은 정 메모리를 이용해야만 한다.



728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - GPU Memory Usage Check  (0) 2016.11.22
CUDA - 고정 메모리(cudaHostAlloc())  (0) 2016.03.03
CUDA - 원자적 연산  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
728x90

CUDA 런타임은 cudaHostAlloc()이라는 CUDA만의 호스트 메모리를 할당하는 방법을 제공하고 있다.


사실 malloc()과 cudaHostAlloc()으로 메모리를 할당하는 것에는 중요한 차이점이 존재한다. C 라이브러리 함수인 malloc()은 표준의 페이징(pageable)이 가능한 호스트 메모리를 할당하는 반면, cudaHostAlloc()은 잠긴 페이지의 호스트 메모리를 할당한다.


때때로 고정 메모리(pinned memory)라고 불리는 잠긴 페이지의 메모리 버퍼들은 하나의 중요한 속성을 가지고 있다. 이는 운영 체제가 해당 메모리를 절대로 디스크로 페이징하여 내보내지 않는 것을 보장하며 실제 물리 메모리에 존재하도록 해준다.


버퍼의 물리적인 주소를 알게됨으로써 GPU는 호스트로부터 또는 호스트로 데이터를 복사하기 위해 직접 메모리 접근(DMA) 방식을 이용할 수 있다. DMA 방식의 복사는 CPU의 개입 없이 진행되므로 복사 도중 CPU가 버퍼를 디스크로 페이징하여 내보내거나 운영체제의 페이지 테이블을 갱신하면서 버퍼의 물리적인 주소를 재위치시킬 수 있음을 의미하기도 한다.

CPU는 페이징이 가능한 메모리의 데이터를 이동시킬 수 있으므로 DMA 방식의 복사를 위해서는 고정 메모리를 사용하는 것이 필수다. 


하지만 주의 할 점이 있다.


고정 메모리를 사용하는 것은 양날의 검이다. 고정 메모리를 사용하면 가상 메모리의 멋진 특징들을 효과적으로 이용하지 못한다. 구체적으로 말하면, 잠긴 페이지의 버퍼들은 디스크로 스왑(swap)될 수 없기 때문에 어플리케이션을 구동중인 컴퓨터는 잠긴 페이지의 모든 버퍼들에 대해 가용한 물리적인 메모리를 가져야만 한다. 이것은 시슽렘에서 표준 malloc()를 사용할 때보다 메모리 부족현상이 훨씬 빨리 발생할 수 있음을 의미한다. 이것은 어플리케이션이 더 적은 양의 물리적인 메모리로 인해 실패할 수 있음을 의미하며, 시스템에서 구동중인 다른 어플리케이션들의 성능에도 영향을 미칠 수 있음을 의미한다.





728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - GPU Memory Usage Check  (0) 2016.11.22
CUDA - 스트림(stream)  (0) 2016.03.03
CUDA - 원자적 연산  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
728x90

CUDA는 계산 능력이 1.1 이상의 버전에서 원자적 연산(automic operation)을 지원한다.


하지만, 원자적 연산을 모든 블록의 쓰레드가 동시에 실행하게 되면, 그 원자에 접근하려는 수천 개의 스레드들이 치열한 다툼을 하게 되면서 오히려 성능 저하가 발생하게 된다.


그럴 때에는 공유 메모리를 사용하여, 원자에는 최대한 접근을 하지 않도록 하는 것이 좋다.





728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - 스트림(stream)  (0) 2016.03.03
CUDA - 고정 메모리(cudaHostAlloc())  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
CUDA - 그래픽스 상호운용 - 6  (0) 2016.02.24
728x90

NVIDIA에서 공식적으로 제공하는 방법이다.



위 코드와 같은 방법으로 사용이 가능하다.


우선 두개의 cudaEvent 변수를 생성해야 하는데, 이것은 record 하는 순간의 timestamp를 저장하는 형식이기 때문이다.

이후 cudaEventRecord()를 이용하여 시작하는 순간과 끝나는 순간의 timestamp를 저장하면 된다.

시간은 cudaEventElapsedTime()를 이용하여 받아오는데, cudaEvent는 기본적으로 float으로 반환한다.


cudaEventSynchronize()는 Host에서 사용되는 함수로써, event가 발생할 때까지 Host는 대기하게 된다.

이와 비슷한 함수로 cudaStreamWaitEvent()가 있는데, 이 함수는 Device내부에서 event가 발생할 때까지 대기한다.


728x90
728x90


우선 잘못된 방법 중 하나로 malloc()라서 간과하고 일반적인 malloc()로 2차원 배열을 선언하는 방식은 접근 에러가 뜨게 된다.

그 원인이 한번 선언된 순간 해당 메모리 주소 정보는 메인에서 관리되지 않는다고 한다. 즉 Host에서 익숙하게 malloc() 사용하듯이 cudaMalloc()을 사용하는 순간 Host(CPU 이하 Host)에 등록된 주소는 잃게되고 Device(GPU 이하 Device)의 주소로 넘어가게 되는데 이때 Host에서는 접근이 불가하게 된다.


근데 Host에서 명령하는 cudaMalloc()을 사용하게 되면 접근이 불가능한데 d_array의 주소를 Host가 접근을 하지만 이미 접근권한을 잃은 Host는 d_array에 대해 nullptr 혹은 잘못된 값을 받아오게 될 것이다. 잘못된 주소를 Device에게 메모리 할당을 요청하기 때문에 에러가 발생하게 된다.



마찬가지로 할당된 주소를 달아주는 순간 Host는 그  권한을 잃게된다...


해결방안1. (반만 해결됨)

1차원 배열로 선언하되 2차원 배열로 이용한다. 뭔소리인가 하면, x, y인 2d 데이터에 접근할 때 data[y * width + x]의 형태로 접근하는 것이다.

쉽게 말해서 2 X 5 행렬을 사용한다면 10칸을 할당해서 아래와 같이 논리적으로 생각하고 쓴다는 것이다.




해결방안2. (추천 방법)

Example:

// kernel which copies data from d_array to destinationArray
__global__ void CopyData(float* d_array, 
                                   float* destinationArray, 
                                   size_t pitch, 
                                   int columnCount, 
                                   int rowCount)
{
  for (int row = 0; row < rowCount; row++) 
  {
     // update the pointer to point to the beginning of the next row
     float* rowData = (float*)(((char*)d_array) + (row * pitch));
        
    for (int column = 0; column < columnCount; column++) 
    {
      rowData[column] = 123.0; // make every value in the array 123.0
      destinationArray[(row*columnCount) + column] = rowData[column];
    }
  }
}


int main(int argc, char** argv) 
{	
  int columnCount = 15; 
  int rowCount = 10;
  float* d_array; // the device array which memory will be allocated to
  float* d_destinationArray; // the device array
  
  // allocate memory on the host
  float* h_array = new float[columnCount*rowCount];

  // the pitch value assigned by cudaMallocPitch
  // (which ensures correct data structure alignment)
  size_t pitch; 
  
  //allocated the device memory for source array
  cudaMallocPitch(&d_array, &pitch, columnCount * sizeof(float), rowCount);
  
  //allocate the device memory for destination array
  cudaMalloc(&d_destinationArray,columnCount*rowCount*sizeof(float));
  
  //call the kernel which copies values from d_array to d_destinationArray
  CopyData<<<100, 512>>>(d_array, d_destinationArray, pitch, columnCount, rowCount);

  //copy the data back to the host memory
  cudaMemcpy(h_array,
                    d_destinationArray,
                    columnCount*rowCount*sizeof(float),
                    cudaMemcpyDeviceToHost);

  //print out the values (all the values are 123.0)
  for(int i = 0 ; i < rowCount ; i++)
  {
    for(int j = 0 ; j < columnCount ; j++)
    {
      cout << "h_array[" << (i*columnCount) + j << "]=" << h_array[(i*columnCount) + j] << endl;
    }
  }
}


참고 사이트 : http://www.stevenmarkford.com/allocating-2d-arrays-in-cuda/

출처 : http://k1321a.blog.me/220357402521

728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - 원자적 연산  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 그래픽스 상호운용 - 6  (0) 2016.02.24
CUDA - 그래픽스 상호운용 - 5  (0) 2016.02.24
CUDA - 그래픽스 상호운용 - 4  (0) 2016.02.19
728x90

CUDA 코드는 앞에서 다 봤기 때문에 더 설명할 내용은 없는 듯 하다.



- 소스 코드 -

main.cpp

texture_2d.cu


728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
CUDA - 그래픽스 상호운용 - 5  (0) 2016.02.24
CUDA - 그래픽스 상호운용 - 4  (0) 2016.02.19
CUDA - 그래픽스 상호운용 - 3  (0) 2016.02.19
728x90

이번엔 RunKernels()에 대해 한번 보자.



앞에서 cudaGraphicsMapResource()로 주소 공간을 할당한 것을 cudaGraphicsSubResourceGetMappedArray()를 이용하여 배열로 반환 받는다.

cuda_texture_2d()는 예제에서 구현된 함수로 다음 장에 작성하겠다.

cudaMemcpy2DToArray()는 이름대로 2차원 배열을 복사한다.

728x90

+ Recent posts