2017-03-16 102 views
1

我正在用openCL 1.2創建應用程序,這是對更大應用程序的測試。該測試將1與每個內核執行的4x4矩陣的每個值相加。這個想法是獲得雙緩衝工作。我創建了兩個實際上做同樣事情的內核,他們共享相同的READ_WRITE緩衝區,因此每個內核執行都可以在最後一個內核執行的地方繼續執行,但它們有所不同,因爲它們具有不同的輸出緩衝區,允許使用輸出緩衝區之一內核在閱讀其他的數據,就像這樣:我認爲OpenCL,爲單個設備使用兩個命令隊列進行雙緩衝

Diagram

的代碼片段是相關或可能是有問題的有以下幾種,我包括隊列,緩衝區和事件以防萬一,但我試圖改變這一切:

隊列

compute_queue = clCreateCommandQueueWithProperties(context, device_id, 0, &err); 
data_queue = clCreateCommandQueueWithProperties(context, device_id, 0, &err); 

緩衝

input_Parametros = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(double) * 5, Parametros, NULL); 
input_matA = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(double) * 4, matA_1, NULL); // The 4x4 matrix 
output_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY , sizeof(double) * 4 * iteraciones_por_kernel, NULL, NULL); 
output_buffer_2 = clCreateBuffer(context, CL_MEM_WRITE_ONLY , sizeof(double) * 4 * iteraciones_por_kernel, NULL, NULL); 

參數爲每個內核設置

clSetKernelArg(kernel_1, 0, sizeof(cl_mem), &input_matA); 
    clSetKernelArg(kernel_1, 1, sizeof(cl_mem), &input_Parametros); 
    clSetKernelArg(kernel_1, 3, sizeof(cl_mem), &output_buffer); 

    clSetKernelArg(kernel_2, 0, sizeof(cl_mem), &input_matA); 
    clSetKernelArg(kernel_2, 1, sizeof(cl_mem), &input_Parametros); 
    clSetKernelArg(kernel_2, 3, sizeof(cl_mem), &output_buffer_2); 

活動

cl_event event_1, event_2, event_3, event_4; 

內核和讀入隊

//////////////////////////////////////////////////////////////// 
    // START 
    //////////////////////////////////////////////////////////////// 

clEnqueueNDRangeKernel(compute_queue, kernel_1, 1, NULL, global, local, 0, 0, &event_1); 

clEnqueueNDRangeKernel(compute_queue, kernel_2, 1, NULL, global, local, 0, 0, &event_2); 

clEnqueueReadBuffer(data_queue, output_buffer, CL_FALSE, 0, sizeof(double)*4*iteraciones_por_kernel, datos_salida, 1 , &event_1, &event_3); 

    //////////////////////////////////////////////////////////////// 
    // ENQUEUE LOOP 
    //////////////////////////////////////////////////////////////// 

for (int i = 1; i <= (n_iteraciones_int - 2); i++){ 

     //////////////////////////////////////////////////////////////// 
     // LOOP PART 1 
     //////////////////////////////////////////////////////////////// 

     if (i % 2 != 0){ 
      clEnqueueNDRangeKernel(compute_queue, kernel_1, 1, NULL, global, local, 1, &event_3, &event_1); 

      clEnqueueReadBuffer(data_queue, output_buffer_2, CL_FALSE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[i*iteraciones_por_kernel_int*4], 1, &event_2, &event_4); 
     } 

     //////////////////////////////////////////////////////////////// 
     // LOOP PART 2 
     //////////////////////////////////////////////////////////////// 

     if (i % 2 == 0){ 

      clEnqueueNDRangeKernel(compute_queue, kernel_2, 1, NULL, global, local, 1, &event_4, &event_2); 

      clEnqueueReadBuffer(data_queue, output_buffer, CL_FALSE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[i*iteraciones_por_kernel_int * 4], 1, &event_1, &event_3); 
     } 

    } 

    //////////////////////////////////////////////////////////////// 
    // END 
    //////////////////////////////////////////////////////////////// 

clEnqueueReadBuffer(data_queue, output_buffer_2, CL_TRUE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[(n_iteraciones_int - 1) * 4], 1, &event_2, 0); 

我不能得到這個即使一切似乎完全正常工作。第一次讀取給出了期望的值,但從那時開始就像內核不再執行一樣,因爲我從output_buffer_2中得到0,並且與第一次讀取時相同的值形成第一個output_buffer。

這對於相同的內核和只有一個隊列來說完全正常,它只需一次數據傳輸就可以完成,但我不想那麼做。

我修改了所有內容並儘可能多地調查,嘗試了所有我能想到的變化。這應該很容易,我認爲可能...問題在哪裏?

如果有任何幫助,我將使用AMD HD7970作爲設備,Windows 10和Visual Studio社區2013。

+1

兩個模量的檢查是對零。一個應該是1 –

+1

最新的阻塞閱讀需要一個事件。確保它在返回該事件的上次迭代中有適當的步驟。奇數編號的最後迭代,你忘了比較1 –

+1

最後,你可能需要clflush兩個隊列循環啓動兩個隊列,而最後讀取只啓動自己的隊列iirc –

回答

1

感謝玉山tugrul buyukisik的幫助下,該程序具有以下變化工作:

活動

cl_event event[20]; //adjust this to your needs 

內核和閱讀排隊

//////////////////////////////////////////////////////////////// 
// START 
//////////////////////////////////////////////////////////////// 

clEnqueueNDRangeKernel(compute_queue, kernel_1, 1, NULL, global, local, 0, 0, &event[0]); 


clEnqueueNDRangeKernel(compute_queue, kernel_2, 1, NULL, global, local, 0, 0, &event[1]); 


clEnqueueReadBuffer(data_queue, output_buffer, CL_FALSE, 0, sizeof(double)*4*iteraciones_por_kernel, datos_salida, 1 , &event[0], &event[2]); 

//////////////////////////////////////////////////////////////// 
// LOOP 
//////////////////////////////////////////////////////////////// 

for (int i = 1; i <= (n_iteraciones_int - 2); i++){ 

     //////////////////////////////////////////////////////////////// 
     // LOOP PART 1 
     //////////////////////////////////////////////////////////////// 

     if (i % 2 == 1){ 

      clEnqueueNDRangeKernel(compute_queue, kernel_1, 1, NULL, global, local, 1, &event[2+2*(i - 1)], &event[4 + 2 * (i - 1)]); 

      clEnqueueReadBuffer(data_queue, output_buffer_2, CL_FALSE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[i*(iteraciones_por_kernel_int) * 4], 1, &event[1+2*(i - 1)], &event[3 + 2 * (i - 1)]); 

     } 

     //////////////////////////////////////////////////////////////// 
     // LOOP PART 2 
     //////////////////////////////////////////////////////////////// 

     if (i % 2 == 0){ 

      clEnqueueNDRangeKernel(compute_queue, kernel_2, 1, NULL, global, local, 1, &event[3 + 2 * (i - 2)], &event[5 + 2 * (i - 2)]); 

      clEnqueueReadBuffer(data_queue, output_buffer, CL_FALSE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[i*(iteraciones_por_kernel_int) * 4], 1, &event[4 + 2 * (i - 2)], &event[6 + 2 * (i - 2)]); 
     } 

    } 

//////////////////////////////////////////////////////////////// 
// END 
//////////////////////////////////////////////////////////////// 

clFlush(compute_queue); 
clFlush(data_queue); 
clEnqueueReadBuffer(data_queue, output_buffer_2, CL_TRUE, 0, sizeof(double) * 4 * iteraciones_por_kernel, &datos_salida[(n_iteraciones_int-1)*(iteraciones_por_kernel_int) * 4], 1, &event[5+2*(n_iteraciones_int-4)], 0);