有兩種方式實現從主機到CL設備的數據傳遞,
第一種:
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);
第二種:
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * DATA_SIZE, inputdata, NULL);
- 這兩種寫法可以說是沒啥區別,但是如過第二中寫法中CL_MEM_COPY_HOST_PTR換成CL_MEM_USE_HOST_PTR,那么根據文檔的說法,第二種並不會把主機的inputdata復制到設備,而僅僅是cache
- 如果inputdata僅僅會初始化一次,那么使用第二種方法看起來更加便捷;但是如果對inputdata要進行多次更新,那么使用第一種的方式更好,可以調用clEnqueueWriteBuffer進行更新
- 使用第一種可以在clEnqueueWriteBuffer中使用event來測量耗時
- 第一種寫法會先在主機創建一個second temporary buffer on the host,然后等到設置這個buffer到kernel的時候再把數據拷貝到設備上。這樣,就可能會在一個短暫的時候,主機上有兩份內存。如果buffer比較大,就會引發問題。而第二種方法則是立即把數據復制的設備,沒有額外的臨時內存分配。參考
- 如果clcontext上綁定了多個device,那么使用第二種方法則會在每個device上都分配該buffer。如果只想對某個設備分配該buffer,那么就應該使用與device綁定了的clEnqueueWriteBuffer。參考
- 然而,在高通的優化指南中,這兩種做法都不推薦。推薦使用Zero Copy的寫法,其關鍵在於CL_MEM_ALLOC_HOST_PTR的應用
// First set cl_mem_flags input in clCreateBuffer:
cl_mem Buffer = clCreateBuffer(context,
CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
sizeof(cl_ushort) * size,
NULL,
&status);
//Then use the map function to return a pointer to the host:
cl_uchar *hostPtr = (cl_uchar *)clEnqueueMapBuffer(
commandQueue,
Buffer,
CL_TRUE,
CL_MAP_WRITE,
0,
sizeof(cl_uchar) * size,
0, NULL, NULL, &status);
//Host updates the buffer using the pointer hostPtr
memcpy(hostPtr, sizeof(cl_uchar) * size, datafromhost);
//Unmapped the object
status = clEnqueueUnmapMemObject(
commandQueue,
Buffer,
(void *) hostPtr,
0, NULL, NULL);
//The object can be used by OpenCL kernels