2012-04-01 3 views
3

다음과 같은 계산을 수행해야합니다. A [x] [y] = 합계 (z = 0에서 z = n까지) {B [x] [y] [ 행렬 A는 차원 [높이] [너비]와 행렬 B를 가지며, C는 차원 [높이] [너비] [n]을 갖는다] [z] + C [x] [y] [z] 나는 각 블록은 공유 메모리를 자신이 있기 때문에 각 블록은 하나 개의 합계를 계산하고 싶은공유 메모리를 사용하는 3 차원 배열의 1 차원 이상의 합계

index = 0; 
for (z = 0; z<n; ++z) 
    for(y = 0; y<width; ++y) 
     for(x = 0; x<height; ++x) { 
      matrix[index] = value; 
      index++; 
     } 

:

값은 같은과 메모리에 매핑됩니다.

dim3 block (n, 1, 1); 
dim grid (height, width, 1); 

커널 : 글로벌 메모리의 코드

부 : 나는 atomicAdd,이 같은 것을 사용 데이터 경주을 방지하기 위해

atomicAdd(&(A[blockIdx.x + blockIdx.y*gridDim.y]), 
      B[blockIdx.x + blockIdx.y*gridDim.y+threadIdx.x*blockDim.x*blockDim.y] 
      + C[blockIdx.x + blockIdx.y*gridDim.y+threadIdx.x*blockDim.x*blockDim.y]); 

나는 합계를 계산하는 공유 메모리를 사용하고 싶습니다 이 결과를 전역 메모리로 복사하십시오.

공유 메모리로 작업하는 방법을 잘 모르겠습니다. 각 블록의 공유 메모리에는 하나의 숫자 (합계 결과) 만 저장됩니다. 이 숫자를 전역 메모리에있는 A 행렬의 올바른 위치에 어떻게 복사해야합니까?

답변

3

사용자가 요구하는 합계를 수행하기 위해 공유 메모리 또는 원자 적 메모리 액세스가 필요하지 않을 수도 있습니다. 이것이 올바르게 이해 되었다면, 데이터가 열의 주요 순서에 있으므로 논리적 연산은 출력 행렬에 행렬 항목당 하나의 스레드를 가지며 각 스레드가 입력 행렬의 z 축을 가로 질러 가면서 합산하는 것입니다. 이 방법 width * height >= n와 열 주요 데이터에 대한 최적해야

__global__ void kernel(float *A, const float *B, const float *C, 
     const int width, const int height, const int n) 
{ 
    int tidx = threadIdx.x + blockDim.x * blockIdx.x; 
    int tidy = threadIdx.y + blockDim.y * blockIdx.y; 

    if ((tidx < height) && (tidy < width)) { 
     int stride = width * height; 
     int ipos = tidx + tidy * height; 

     float * oval = A + ipos; 
     float sum = 0.f; 
     for(int z=0; z<n; z++, ipos+=stride) { 
      sum += B[ipos] + C[ipos]; 
     } 
     *oval = sum; 
    } 
} 

이에 대한 커널은 같은 것을 볼 수 있었다. 이를 위해 공유 메모리를 사용하면 성능상의 이점이 없으며 아토믹 메모리 작업을 사용할 필요가 없습니다. 문제가 있다면 width * height << n 합계 당 블록 현명한 병렬 감소를 시도하는 것이 좋습니다. 그러나 당신은 문제의 전형적인 차원이 무엇인지 밝히지 않았다. 문제가 후자와 더 비슷하다면 의견을 남기고 답장에 기반한 샘플 커널을 추가 할 수 있습니다.

+0

그러나 각 스레드가 입력 행렬의 z 축을 통과 할 때 계산이 직렬화됩니다. 그렇지 않습니까? – user1281071

+0

각 스레드는 z = 0에서 값을 계산 한 다음 z = 1로 이동합니다. 이것은 직렬화된다. 각 z에 대해 글로벌 메모리에 액세스해야합니다. 나는 그것을 좋아할 것이다. – user1281071

+0

코드를 이해하는 방법 : 평면 z = 0에서 시작합니다. 평면 z = 0에있는 모든 요소는 전역에서 읽혀집니다. 그런 다음 결과가 계산되고 전역 메모리에 저장됩니다. z = 1로 이동합니다. 평면 z = 1에있는 모든 요소는 전역에서 읽혀집니다. 그런 다음 전역 메모리에서 이전 결과에 추가 된 결과 (전역 메모리 읽기 및 쓰기)가 계산됩니다. 그러면 z = 2로 이동합니다 ... 이것이 올바른 경우 모든 추가에서 전역 메모리에 대한 액세스와 직렬화가 있습니다. – user1281071