clCreateBuffer和clCreateBuufer + clEnqueueWriteBuffer

有两种方式实现从主机到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

你可能感兴趣的:(clCreateBuffer和clCreateBuufer + clEnqueueWriteBuffer)