2013-07-21 36 views
5

所以我現在一直在玩OpenCL,測試主機和設備之間的內存傳輸速度。 我正在使用英特爾OpenCL SDK,並在集成圖形的Intel i5 Processor上運行。 我發現然後clEnqueueMapBuffer代替clEnqueueWriteBuffer這原來是近10倍的速度利用固定內存時,像這樣:CL_MEM_ALLOC_HOST_PTR比CL_MEM_USE_HOST_PTR更慢

int amt = 16*1024*1024; 
... 
k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, a, NULL); 
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, b, NULL); 
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, ret, NULL); 

int* map_a = (int*) clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 
int* map_b = (int*) clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 
int* map_c = (int*) clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 
clFinish(c_q); 

abret是128個對齊INT陣列。 時間出來約22.026186毫秒,相對於使用clEnqueueWriteBuffer 然而,當我改變了我的代碼

k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL); 
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL); 
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL); 

int* map_a = (int*)clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 
int* map_b = (int*)clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 
int* map_c = (int*)clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error); 

/** initiate map_a and map_b **/ 

時間增加到91.350065毫秒

什麼能198.604528毫秒是問題嗎?或者它是一個問題呢?

編輯: 這是我如何初始化第二碼數組:

for (int i = 0; i < amt; i++) 
{ 
    map_a[i] = i; 
    map_b[i] = i; 
} 

而現在,我檢查,map_a和map_b 包含在節目結束的權利元素,但map_c包含全部0。我這樣做:

clEnqueueUnmapMemObject(c_q, k_a, map_a, 0, NULL, NULL); 
clEnqueueUnmapMemObject(c_q, k_b, map_b, 0, NULL, NULL); 
clEnqueueUnmapMemObject(c_q, k_c, map_c, 0, NULL, NULL); 

和我的內核就是

__kernel void test(__global int* a, __global int* b, __global int* c) 
{ 
    int i = get_global_id(0); 
    c[i] = a[i] + b[i]; 
} 
+0

在第二個代碼中,您可以展示如何用a,b和ret數據初始化k_a,k_b和k_c,以及clFinish在哪裏。如果這兩個代碼做了不同的事情,它將很難幫助你 –

+0

對不起,代碼是相同的,我只是沒有意外複製一切。在第二個代碼中,我不用ret初始化k_c,因爲我認爲我只能從map_c讀取數據。 – selena731

+0

映射和使用之後,您必須取消映射,或者從映射對象執行clWrite/Read以確保內存一致性。 – DarkZeros

回答

1

我的理解是,CL_MEM_ALLOC_HOST_PTR分配但不復制。第二代碼塊是否實際上將任何數據傳送到設備上?

此外,clCreateBuffer與CL_MEM_USE_HOST_PTR和CL_MEM_COPY_HOST_PTR一起使用時不應該要求clEnqueueWrite,因爲緩衝區是使用void * host_ptr指向的內存創建的。

使用「固定」記憶中的OpenCL應該是一個過程,如:

int amt = 16*1024*1024; 
    int Array[] = new int[amt]; 
    int Error = 0; 

    //Note, since we are using NULL for the data pointer, we HAVE to use CL_MEM_ALLOC_HOST_PTR 
    //This allocates memory on the devices 
    cl_mem B1 = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, &Error); 

    //Map the Device memory to host memory, aka pinning it 
    int *host_ptr = clEnqueueMapBuffer(queue, B1, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &Error); 

    //Copy from host memory to pinned host memory which copies to the card automatically` 
    memcpy(host_ptr, Array, sizeof(int)*amt); 

    //Call your kernel and everything else and memcpy back the pinned back to host when 
    //you are done 

編輯:你可以做,以加快該計劃的最後一件事是爲不使用CL_FALSE使內存讀/寫阻塞而不是CL_TRUE。只需確保在數據被複制回主機之前調用clFinish(),以便清空命令隊列並處理所有命令。

來源:OpenCL In Action

+0

Sry但我不能同意這個答案。由於映射內存並執行memcpy()確實使用DMA並行地複製數據,並且它應該更快。但是,如果沒有unmap(),則不能在內核中使用它。由於內核可能使用緩衝區的非完整副本。通常情況下,這可能會導致人爲加速,這根本不是真正的加速,但是不完整的內存拷貝。 – DarkZeros

+0

這個答案不會混淆映射(即在寫入到其中一方的PCIe事務)與固定(即頁面鎖定,以便您永遠不需要解析物理頁面或交換)嗎? – einpoklum

0

隨着國旗的正確組合,你應該能夠實現「零拷貝」(即非常快)圖/英特爾集成顯卡的去映射,因爲沒有必要的「CPU來GPU「複製,因爲它們都使用相同的內存(這就是」集成「的含義)。閱讀內存上的Intel OpenCL Optimization Guide部分。