2012-01-11 5 views
2
__kernel void CKmix(__global short* MCL, __global short* MPCL,__global short *C, int S, int B) 
{  
    unsigned int i=get_global_id(0); 
    unsigned int ii=get_global_id(1); 
    MCL[i]+=MPCL[B*ii+i+C[ii]+S]; 
} 

커널 솔기가 정상적으로 컴파일되고 CPU를 장치로 사용하여 올바른 결과를 얻었지만 커널을 호출 할 때마다 프로그램을 릴리스하고 메모리 개체를 다시 만들었을 때였습니다. 내 테스트 목적으로 약 16000 번입니다.OpenCL : GPU에없는 CPU의 결과를 수정하십시오 : 메모리를 올바르게 관리하는 방법?

내가 게시하는 코드는 고정 된 메모리와 매핑을 사용하려고하는 곳입니다.

OpenCLProgram = clCreateProgramWithSource(hContext[Plat-1][Dev-1],11, OpenCLSource, NULL ,NULL); 
clBuildProgram(OpenCLProgram, 0,NULL,NULL, NULL,NULL); 
ocKernel = clCreateKernel(OpenCLProgram, "CKmix", NULL); 

이것은 또한 성공적입니다. 컨텍스트의 2 차원 배열을 갖는 이유는 모든 플랫폼과 장치를 반복하고 사용자가 사용할 플랫폼과 장치를 선택할 수 있도록하기 위해서입니다.

WorkSize[0]=SN; 
WorkSize[1]=NF; 

PinnedCCL = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE| CL_MEM_ALLOC_HOST_PTR, sizeof(short) *NF, NULL, NULL); 
PinnedMCL = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(short) * Z*NF, NULL, NULL); 
PinnedMO = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(short) * Z,NULL, NULL); 
PinnedMTEMP = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(short) * Z,NULL, NULL); 

DevComboCCL = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE, sizeof(short) *NF, NULL, NULL);  
DevMappedMCL = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE , sizeof(short) * Z*NF, NULL,NULL); 
DevMO = clCreateBuffer(hContext[Plat-1][Dev-1], CL_MEM_READ_WRITE , sizeof(short) * Z,NULL, NULL); 

MO = (short*) clEnqueueMapBuffer(hCmdQueue[Plat-1][Dev-1], PinnedMO, CL_TRUE, CL_MAP_READ, 0, sizeof(short)*Z, 0, NULL, NULL, NULL); 
CCL = (short*) clEnqueueMapBuffer(hCmdQueue[Plat-1][Dev-1], PinnedCCL, CL_TRUE, CL_MAP_WRITE, 0, sizeof(short)*NF, 0, NULL, NULL,NULL); 
MCL = (short*) clEnqueueMapBuffer(hCmdQueue[Plat-1][Dev-1], PinnedMCL, CL_TRUE, CL_MAP_WRITE, 0, sizeof(short)*Z*NF, 0, NULL, NULL, NULL); 
MTEMP = (short*) clEnqueueMapBuffer(hCmdQueue[Plat-1][Dev-1], PinnedMTEMP, CL_TRUE, CL_MAP_READ, 0, sizeof(short)*Z, 0, NULL, NULL, NULL); 

for (n=0; n < Z; ++n) { 
    MTEMP[n]=0; 
    } 

clSetKernelArg(ocKernel, 0, sizeof(cl_mem), (void*) &DevMO); 
clSetKernelArg(ocKernel, 1, sizeof(cl_mem), (void*) &DevMCL);  
clSetKernelArg(ocKernel, 2, sizeof(cl_mem), (void*) &DevCCL); 
clSetKernelArg(ocKernel, 3, sizeof(int), (void*) &SH); 
clSetKernelArg(ocKernel, 4, sizeof(int), (void*) &SN); 

위의 내용은 내 초기화 작업을 구성하고 아래 나머지 작업은 반복적으로 발생합니다.

clEnqueueWriteBuffer(hCmdQueue[Plat-1][Dev-1], DevMCL, CL_TRUE, 0, Z*NF*sizeof(short), MCL, 0, NULL, NULL); 
clEnqueueWriteBuffer(hCmdQueue[Plat-1][Dev-1], DevCCL, CL_TRUE, 0, NF*sizeof(short), CCL, 0, NULL, NULL); 
clEnqueueWriteBuffer(hCmdQueue[Plat-1][Dev-1], DevMO, CL_TRUE, 0, Z*sizeof(short), MTEMP, 0, NULL, NULL); 

clEnqueueNDRangeKernel(hCmdQueue[Plat-1][Dev-1], ocKernel, 2, NULL, WorkSize, NULL, 0, NULL, NULL); 
clEnqueueReadBuffer(hCmdQueue[Plat-1][Dev-1],DevMO, CL_TRUE, 0, Z * sizeof(short),(void*) MO , 0, NULL, NULL); 

오류를 확인했으며 오류가 표시되지 않습니다. 커널은 새로운 데이터로 여러 번 반복적으로 시작됩니다. 내가 어디에서 잘못하고 있는지 확실하지 않습니다.

NVIDIA 550 TI 컴퓨팅 능력 2.1, 최신 데브 드라이버, CUDA는 SDK 4.0,

+0

그래서 정확히 무엇이 잘못 될까요? – Grizzly

+0

@ 그리즐리 올바른 결과 (MO)를 얻지 못하고 있습니다. 또한 GPU 대 CPU를 사용하면 다른 결과를 얻습니다. – MVTC

+0

그래서 어떤 결과를 얻고 무엇을 기대 했습니까? – Grizzly

답변

2

의 유일한 코드에 문제가 있지만,이 경우 나도 몰라 :

unsigned int i=get_global_id(0); 
unsigned int ii=get_global_id(1); 
MCL[i]+=MPCL[B*ii+i+C[ii]+S]; 

입니다 확실히 좋은 생각은 아닙니다. 일반적으로 동일한 스레드에서 여러 스레드가 작동하므로 여러 스레드가 MCL[i]을 동시에 업데이트하려고 시도 할 수 있습니다 (+=은 원자가 아님). 나는 CPU를 위해 충분한 수의 스레드가 GPI에 수천 개의 쓰레드를 가지는 것이 거의 확실하게 문제를 일으키지 만 대부분의 경우 이러한 동작을 보여주기 위해 생성되지는 않는다고 가정 할 것이다.

이 작업을 수행하는 가장 합리적인 방법은 단지 1 차원은 WorkingSet을 가지고 있으며 각 스레드에 대해 하나 개의 위치로 이동하여 모든 값을 축적 : 또는 가능하지 않을 수도 있습니다 물론

unsigned int i=get_global_id(0); 
short accum = MCL[i]; //or 0, if thats the start 
for(int ii = 0; ii < size; ++ii) 
    accum += MPCL[B*ii+i+C[ii]+S]; 
MCL[i] = accum; 

합니다. 수정이 아니라면 아마도 그렇게 간단하지 않을 것입니다.

+0

'global_id (0)'은 1 차원 작업 집합에 대해 유일하지만 2 차원 또는 3 차원 작업 집합에 대해 고유하지 않습니까? –

+1

@SteveBlackwell : 1 차원 워크 세트의 경우 각 스레드가 그 중 하나를 얻는 0..N의 ID가 있습니다. 2 개의 희미한 빛. 너는 ids [0..N, 0 ..M] 각 조합은 한 번 발생하므로 M 개의 스레드가 같은'global_id (0)'을 공유하지만 (다른 'global_id (1)'을 가짐) – Grizzly

+0

@ Grizzly : 솔루션이 작동합니다. 지금 GPU에서 올바른 결과를 얻고 있습니다! CPU를 직렬로 연결하는 것보다 20 % 정도 빠르며 OpenMP를 사용하는 CPU보다 3 배 더 느리기 때문에 여전히이를 최적화하는 방법을 찾아야합니다. 나는 공유 메모리의 사용을 통합하려고 노력할 것이고 합체와 정렬을 이해하려고 노력할 것이다. 감사! – MVTC

관련 문제