2013-03-24 2 views
0

저는 Linux 시스템과 Tesla C2075 시스템에서 작동합니다. 나는 저감 커널의 수정 된 버전 인 커널을 시작하고있다. 내 목표는 큰 데이터 세트 (결과)의 평균 및 단계별 평균 버전 (time_avg)을 찾는 것입니다. 아래 코드를 참조하십시오.커널 시작 실패

"result"와 "time_avg"의 크기는 같고 "nsamps"와 같습니다. "time_avg"는 배열 결과의 연속적인 평균 세트를 포함합니다. 그래서 상반기에는 겹치지 않는 두 샘플의 평균이 포함되어 있습니다. 그 이후의 1/4은 겹치지 않는 샘플 4 개, 평균 8 개 샘플의 다음 8 분의 샘플 등입니다.

__global__ void timeavg_mean(float *result, unsigned int *nsamps, float *time_avg, float *mean) { 

__shared__ float temp[1024]; 
int ltid = threadIdx.x, gtid = blockIdx.x*blockDim.x + threadIdx.x, stride; 
int start = 0, index; 
unsigned int npts = *nsamps; 

printf("here here\n"); 

// Store chunk of memory=2*blockDim.x (which is to be reduced) into shared memory 
if ((2*gtid) < npts){ 
     temp[2*ltid] = result[2*gtid]; 
     temp[2*ltid+1] = result[2*gtid + 1]; 
}  
     for (stride=1; stride<blockDim.x; stride>>=1) { 
       __syncthreads(); 
       if (ltid % (stride*2) == 0){ 
        if ((2*gtid) < npts){ 
         temp[2*ltid] += temp[2*ltid + stride]; 
         index = (int)(start + gtid/stride); 
         time_avg[index] = (float)(temp[2*ltid]/(2.0*stride)); 
        } 
       } 
     start += npts/(2*stride); 
     } 
__syncthreads(); 
if (ltid == 0) 
{ 
     atomicAdd(mean, temp[0]);  
} 
__syncthreads(); 
printf("%f\n", *mean); 
} 

실행 구성은 40 블록, 512 스레드입니다. 데이터 세트는 ~ 40k 샘플입니다.

내 주 코드에서 커널 호출 후 cudaGetLastError()을 호출하면 오류가 반환되지 않습니다. 메모리 할당 및 메모리 복사본은 오류를 반환하지 않습니다. 커널 호출 후 cudaDeviceSynchronize() (또는 평균값을 확인하기 위해 cudaMemcpy)을 쓰면 커널 호출 후 프로그램이 완전히 중단됩니다. 제거하면 프로그램이 실행되고 종료됩니다. 어떤 경우에도 출력물을 "여기 여기"또는 평균값을 인쇄합니까? 커널이 성공적으로 실행되지 않으면 printf가 인쇄되지 않는다는 것을 이해합니다. 이것은 재귀에서 __syncthreads()과 관련이 있습니까? 모든 스레드는 같은 깊이까지 갈 것이므로 체크 아웃 할 것입니다.

무엇이 문제입니까?

감사합니다.

답변

3

커널 호출이 비동기 적이기 때문에 커널이 성공적으로 시작되면 호스트 코드가 계속 실행되고 오류가 표시되지 않습니다. 커널 실행 중에 발생하는 오류는 명시 적 동기화를 수행하거나 암시 적 동기화를 유발하는 함수를 호출 한 후에 만 ​​나타납니다.
커널이 동기화를 멈추었을 때 커널이 실행을 마치지 못했을 때 - 일부 무한 루프가 실행 중이거나 __synchthreads() 또는 다른 동기화 기본을 기다리고 있습니다.
코드에 무한 루프가 포함 된 것 같습니다 : for (stride=1; stride<blockDim.x; stride>>=1). 보폭을 오른쪽이 아닌 왼쪽으로 옮기고 싶을 것입니다 : stride<<=1.

재귀를 언급했지만 코드에는 __global__ 함수가 하나만 포함되어 있으므로 재귀 호출은 없습니다.

+0

좋아요. 무한 루프라는 것을 알지 못했습니다. 고맙습니다! 연산자 ">> ="와 "<< ="는 정확히 어떻게 작동합니까? 나는 귀하의 요점에 동의합니다. 그러나 그러한 상황이 발생하면 가장 좋은 디버깅 방법은 무엇입니까? cuda-gdb를 사용하면 커널을 사용할 수 있습니까? timeavg_mean 함수는 매번 다른 40k 샘플 세트에서 작동하는 주 코드에서 재귀 적으로 (722 회) 호출됩니다. 그러나 이러한 호출은 같은 스트림 내에서 (현재까지) 있습니다. – Rmj

+0

비트 단위 시프트 연산자는 비트를 왼쪽이나 오른쪽으로 시프트합니다. 더 중요한 비트가 왼쪽에 있기 때문에 왼쪽으로 이동하는 것은 값에 2를 곱하는 것을 의미하고, 오른쪽으로 이동하는 것은 2로 나누는 것을 의미합니다. – RoBiK

+0

cuda 디버거를 사용하여 커널을 디버깅 할 수 있으며, 커널 내부에 중단 점을 설정하고 일반적인 디버깅 작업을 수행 할 수 있습니다 (단계 입/출력/검사 변수 등). – RoBiK

1

커널에 무한 루프가 있습니다. for 루프를

으로 바꿉니다.
for (stride=1; stride<blockDim.x; stride<<=1) { 
+0

RoBiK가 더 빨랐습니다 ... – tera

+0

Hehe. 예. 그러나 당신의 대답에 감사드립니다! – Rmj