2017-04-09 2 views
0

4 * 4 어레이에 8 * 8 어레이의 블록 평균을 찾으려고합니다. 다음과 같은 내용이 있습니다 : enter image description hereCUDA 블록 평균

저는 현재 프로그램을 실행할 때마다 각 스레드가 읽는 값이 달라지는 경쟁 조건 유형 수수께끼에 갇혀 있습니다. 지금 당장 나의 유일한 관심사는 모든 블록 요소를 함께 추가하는 것입니다. 나중에 그 합계를 나눌 것입니다. 이것은 내 코드입니다. 나는 (내 배열이 모든 잘못된 생각하지만 난 두 차원 하나의 동적 공간을 충당 그냥 드릴 수 없습니다)에게 제발 처음부터 잘못된 접근 방식을 사용하고, 그래서 만약

#include <stdio.h> 
#include<math.h> 

const int MAIN_SIZE = 8; 
const int RESULT_SIZE = 4; 

typedef int mainArray[MAIN_SIZE]; 
typedef int resultArray[RESULT_SIZE]; 

__global__ void computeMean(mainArray *main, resultArray *result) { 
    int mColumn = blockIdx.x * blockDim.x + threadIdx.x; 
    int mRow = blockIdx.y * blockDim.y + threadIdx.y; 
    if (mRow >= MAIN_SIZE || mColumn >= MAIN_SIZE) 
     return; 

    // real calculation 
    int rRow = std::floor(static_cast<float>(mRow/2)), 
     rColumn = std::floor(static_cast<float>(mColumn/2)); 
    int x = result[rRow][rColumn] + main[mRow][mColumn]; 
    result[rRow][rColumn] += x; 
    printf("Adding %d on %d %d at location %d %d; new value: %d\n", main[mRow][mColumn], mRow, mColumn, rRow, rColumn, result[rRow][rColumn]); 
} 

int main() { 
    mainArray *hMain, *dMain; 
    resultArray *hResult, *dResult; 
    size_t mSize = MAIN_SIZE * MAIN_SIZE * sizeof(int*); 
    size_t rSize = RESULT_SIZE * RESULT_SIZE * sizeof(int*); 
    hMain = (mainArray *) malloc (mSize); 
    hResult = (resultArray *) malloc (rSize); 

    // populate arrays 
    int k = 0; 
    for(int i = 0; i < MAIN_SIZE; i++) { 
     for(int j = 0; j < MAIN_SIZE; j++) { 
      hMain[i][j] = ++k; 
     } 
    } 
    memset(hResult, 0, rSize); 

    printf("main\n"); 
    for(int i = 0; i < MAIN_SIZE; i++) { 
     for(int j = 0; j < MAIN_SIZE; j++) { 
      printf("%d ", hMain[i][j]); 
     } 
     printf("\n"); 
    } 

    printf("result\n"); 
    for(int i = 0; i < RESULT_SIZE; i++) { 
     for(int j = 0; j < RESULT_SIZE; j++) { 
      printf("%d ", hResult[i][j]); 
     } 
     printf("\n"); 
    } 

    // Allocate memory on device 
    cudaMalloc(&dMain, mSize); 
    cudaMalloc(&dResult, rSize); 

    // Do memcopies to GPU 
    cudaMemcpy(dMain, hMain, mSize, cudaMemcpyHostToDevice); 
    cudaMemcpy(dResult, hResult, rSize, cudaMemcpyHostToDevice); 

    dim3 block(1, 1); 
    dim3 grid ((MAIN_SIZE + block.x - 1)/block.x, (MAIN_SIZE + block.y - 1)/block.y); 
    computeMean<<<grid, block>>>(dMain, dResult); 

    // Do memcopies back to host 
    cudaMemcpy(hMain, dMain, mSize, cudaMemcpyDeviceToHost); 
    cudaMemcpy(hResult, dResult, rSize, cudaMemcpyDeviceToHost); 

    // validate 
    if (cudaGetLastError() != cudaSuccess) {printf("cuda error\n"); return -1;} 

    printf("success!\n"); 
    for(int i = 0; i < RESULT_SIZE; i++) { 
     for(int j = 0; j < RESULT_SIZE; j++) { 
      printf("%d ", hResult[i][j]); 
     } 
     printf("\n"); 
    } 

    free(hMain); 
    free(hResult); 
    cudaFree(dMain); 
    cudaFree(dResult); 
    return 0; 
} 

나는 CUDA에 현재 새로운 오전 . 미리 감사드립니다.

+0

'결과'에서 같은 위치에 여러 개의 스레드를 읽고 쓸 수 있습니다. 여러 종류의 위험 요소가 여기에 있습니다. CUDA 스레드 병렬 아키텍처는 이러한 문제를 자동으로 해결하지 않습니다. (예 : [고전적인 병렬 감소] (http://developer.download.nvidia.com/assets/cuda/files/reduction.pdf) 기법을 사용하여) 충돌하지 않은 접근을 준비하거나 [atomics] (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#atomic-functions)를 참조하십시오. –

+0

또한, 이것은 :'mRow/2'는 정수 나누기입니다. 기간. 결과에 대한 정적 캐스트와 'floor'연산을 수행하는 것은 의미없는 낭비적인 노력의 무리입니다. 적절한 부동 소수점 바닥을 원한다면, 나누기를하기 전에 인수 중 하나를'float' **로 캐스팅해야합니다. –

+0

@RobertCrovella : OP 질문에 답하셨습니다. 대답을 해 주실 것입니다. – einpoklum

답변

2

코드의이 부분에 몇 가지 문제가 있습니다

int rRow = std::floor(static_cast<float>(mRow/2)), 
    rColumn = std::floor(static_cast<float>(mColumn/2)); 
int x = result[rRow][rColumn] + main[mRow][mColumn]; 
result[rRow][rColumn] += x; 

mRowmColumn에서 정수 나누기를 사용하여 발견 rRowrColumn 때문에, 그것은 분명해야 그 threadIdx.x입니다 스레드 0 또는 1 것이다 동일한 rColumn 결과를 생성하고, 다른 많은 복제 사례가 있습니다. 다른 스레드가

CUDA에 기록 할 수있는 위치에서 읽기 순서 또는 제어

  • 없이 동일한 위치에 쓰기

    1. 하지 않습니다 : 결과적으로는 스레드가 이 위험을 당신을 위해 분류하십시오. 특정 프로그래밍 단계를 거쳐야합니다. (기존 결과 데이터에 주 데이터를 추가하고 그 결과 합계를 에 추가하면 논리적 인 오류가 발생하므로 원하는 결과가 아닐 수 있습니다.) 두 가지 일반적인 접근 방식 해결하기 위해 스레드 위험 요소가 될 것입니다 :

      1. 사용 atomics
      2. 단순 들어 classical parallel reduction 방법

      를 사용하여, 나는 첫 번째 방법을 보여줍니다 수정 된 코드를 제공합니다.

      $ cat t1324.cu 
      #include <stdio.h> 
      #include<math.h> 
      
      const int MAIN_SIZE = 8; 
      const int RESULT_SIZE = 4; 
      
      typedef int mainArray[MAIN_SIZE]; 
      typedef int resultArray[RESULT_SIZE]; 
      
      __global__ void computeMean(mainArray *main, resultArray *result) { 
          int mColumn = blockIdx.x * blockDim.x + threadIdx.x; 
          int mRow = blockIdx.y * blockDim.y + threadIdx.y; 
          if (mRow >= MAIN_SIZE || mColumn >= MAIN_SIZE) 
           return; 
      
          // real calculation 
          int rRow = std::floor(static_cast<float>(mRow/2)), 
           rColumn = std::floor(static_cast<float>(mColumn/2)); 
          //int x = result[rRow][rColumn] + main[mRow][mColumn]; 
          //result[rRow][rColumn] += x; 
          atomicAdd(&(result[rRow][rColumn]), main[mRow][mColumn]); 
          //printf("Adding %d on %d %d at location %d %d; new value: %d\n", main[mRow][mColumn], mRow, mColumn, rRow, rColumn, result[rRow][rColumn]); 
      } 
      
      int main() { 
          mainArray *hMain, *dMain; 
          resultArray *hResult, *dResult; 
          size_t mSize = MAIN_SIZE * MAIN_SIZE * sizeof(int*); 
          size_t rSize = RESULT_SIZE * RESULT_SIZE * sizeof(int*); 
          hMain = (mainArray *) malloc (mSize); 
          hResult = (resultArray *) malloc (rSize); 
      
          // populate arrays 
          //int k = 0; 
          for(int i = 0; i < MAIN_SIZE; i++) { 
           for(int j = 0; j < MAIN_SIZE; j++) { 
            hMain[i][j] = 1; //++k; 
           } 
          } 
          memset(hResult, 0, rSize); 
      
          printf("main\n"); 
          for(int i = 0; i < MAIN_SIZE; i++) { 
           for(int j = 0; j < MAIN_SIZE; j++) { 
            printf("%d ", hMain[i][j]); 
           } 
           printf("\n"); 
          } 
      
          printf("result\n"); 
          for(int i = 0; i < RESULT_SIZE; i++) { 
           for(int j = 0; j < RESULT_SIZE; j++) { 
            printf("%d ", hResult[i][j]); 
           } 
           printf("\n"); 
          } 
      
          // Allocate memory on device 
          cudaMalloc(&dMain, mSize); 
          cudaMalloc(&dResult, rSize); 
      
          // Do memcopies to GPU 
          cudaMemcpy(dMain, hMain, mSize, cudaMemcpyHostToDevice); 
          cudaMemcpy(dResult, hResult, rSize, cudaMemcpyHostToDevice); 
      
          dim3 block(1, 1); 
          dim3 grid ((MAIN_SIZE + block.x - 1)/block.x, (MAIN_SIZE + block.y - 1)/block.y); 
          computeMean<<<grid, block>>>(dMain, dResult); 
      
          // Do memcopies back to host 
          cudaMemcpy(hMain, dMain, mSize, cudaMemcpyDeviceToHost); 
          cudaMemcpy(hResult, dResult, rSize, cudaMemcpyDeviceToHost); 
      
          // validate 
          if (cudaGetLastError() != cudaSuccess) {printf("cuda error\n"); return -1;} 
      
          printf("success!\n"); 
          for(int i = 0; i < RESULT_SIZE; i++) { 
           for(int j = 0; j < RESULT_SIZE; j++) { 
            printf("%d ", hResult[i][j]); 
           } 
           printf("\n"); 
          } 
      
          free(hMain); 
          free(hResult); 
          cudaFree(dMain); 
          cudaFree(dResult); 
          return 0; 
      } 
      $ nvcc -arch=sm_35 -o t1324 t1324.cu 
      $ cuda-memcheck ./t1324 
      ========= CUDA-MEMCHECK 
      main 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      1 1 1 1 1 1 1 1 
      result 
      0 0 0 0 
      0 0 0 0 
      0 0 0 0 
      0 0 0 0 
      success! 
      4 4 4 4 
      4 4 4 4 
      4 4 4 4 
      4 4 4 4 
      ========= ERROR SUMMARY: 0 errors 
      $ 
      

      다른 몇 가지주의 사항 : I 신속 정확한 출력을 식별 할 수 있도록

      1. 나는 초기화 데이터를 변경했습니다. 여기
      2. 귀하의 코드 :

        int rRow = std::floor(static_cast<float>(mRow/2)), 
        

        내가 믿는 당신이 생각하는 일을하지 않습니다. mRow/2은 정수로 나눈 값입니다. 이후에 float으로 캐스팅 한 다음 floor을 가져 가면 아무런 효과가 없다고 생각하지 않습니다. 내가 볼 수있는 것은 아프지 않습니다 (정수 나누기를 원한다고 확신합니다). 그래서 그대로 두었습니다. 부동 소수점 나누기를 원한다면 두 개의 정수 피연산자 중 하나를 부동 소수점으로 캐스팅해야합니다. 작성한 코드는 그렇게하지 않습니다. (결과를 던집니다.)

  • +0

    이렇게 늦은 답장을 보내 주셔서 감사합니다. 결국 원자 추가를 사용하여 내 자아를 해결하게되었습니다. 하지만 시간을내어 주셔서 감사합니다. 왜냐하면 내가 작성한 이유는 2.5에서 나온 결과를 나눗셈에 적용했기 때문이며, 자동으로 3으로 변환되기 때문에 자동으로 변환되기 때문에 (즉, 변환되지 않습니다. 그것은 떠 다니고 바닥 값을 가져갔습니다. – hraw

    관련 문제