OpenCL 2.0 规范 – Pipes(管道)

上一篇文章我们介绍了OpenCL2.0的新特性共享虚拟内存(SVM)。本文将继续讲述另一个新特性,“pipes(管道)”。

 

为了更好地理解下面内容,我们建议做好如下准备工作:

 

l  参考注释,通读每篇博文的代码。

l  请点击这里下载AMD OpenCL2.0驱动,下载页中列出了已支持平台的清单。

l  请点击这里下载范例代码

l  请尝试编写并运行自己的OpenCL2.0代码,可以进入OpenCL社区进讨论。

 

范例代码将运行于不同的AMD平台,例如Radeon HD8000系列。驱动页面会列出完整的可支持产品家族名单。

 

概述

 

OpenCL2.0引入了一新的工作机制用于在不同kernel程序间传递数据,其名字是“pipes(管道)”。一个pipe实质上是一个结构化缓冲区,里面含有“packets()”的集合空间—packet是指kernel程序类型对象。如其名字所示,这些数据包在pipe中是有序放置的。写入数据时pipe中会有一个写入结束端,读取数据时pipe中会有一个读取结束端。pipe可以说是buffer对象的附加,例如bufferimagePipes只能被kernel程序函数访问而不能被主机访问。

 

特殊的内置函数read_pipewrite_pipe,实现了从kernel程序对pipes进行访问。一个kernel程序可以对pipe进行写入或读取,但不能同时进行。Pipes只在标准同步点时是一致的;多个kernel程序(甚至是硬件许可)对同一pipe同时访问结果都是不确定的。主机端无法访问pipe

 

创建pipes是非常简单的,在主机执行clCreatePipe就可以了。

 

你可以使用pipes实现各种功能。你可以在kernels程序间传递pipes。更好的是,可使用OpenCL2.0中的设备端任务队列(将在下一个博文中提及)特性来整合pipes,来动态构建不同的计算流程模式

 

Pipes有两种类型:read(读取) pipe,可以读取不同的packets;另一个是write(写入) pipe,可以写入不同的packets

 

注:不能对只读pipe进行写入,也不能对只写pipe进行读取。不能同时对pipe进行读取和写入。

 

访问Pipes的函数

 

OpenCL2.0新增了一个主机API函数来创建pipe

cl_mem clCreatePipe ( cl_context context, cl_mem_flags flags,
      cl_uint pipe_packet_size, cl_uint pipe_max_packets,
      const cl_pipe_properties * properties,
      cl_int *errcode_ret)


由该函数分配的内存可被作为只读或只写pipes传入kernels程序。Pipe对象只能被作为kernel程序参数或kernel程序函数进行传递,而不能kernel中进行声明或作为程序全局的对象使用。

 

同时,在OpenCL2.0 spec中新增了一组pipes操作内建函数。重要的有:

l  read_pipe (pipe p, gentype *ptr)pipe p读取packetptr

l  write_pipe (pipe p, gentype *ptr):把由ptr指向的 packet写入pipe p

 

为了确保有足够的pipe结构空间来进行读取和写入,可以使用内建函数来预留足够的空间。例如,可以使用 reserve_read_pipe 或者 reserve_write_pipe来实现。这两个函数会返回一个预留ID,可用于进行实际操作。类似地,在workgroup级别也有相应的预留函数,work_group_reserve_read_pipework_group_reserve_write_pipe。使用commit_read_pipe commit_write_pipe可实现相应的提交操作(读取/写入)

 

Pipes示例

 

该示例代码包含两个kernel程序:producer_kernel,对Pipe进行写入; consumer_kernel,对同一pipe进行读取。producer程序会写入一个随机数序列;consumer程序会读取该序列并生成一个柱状图。

 

主机负责创建pipe,用在上述两个函数中:

rngPipe = clCreatePipe(context,
               CL_MEM_READ_WRITE,
               szPipePkt,
               szPipe,
               NULL,
               &status);


该代码创建了一个可以被kernel程序访问的pipe(读取/写入)。主机创建了两个kernel程序,producer_kernel和 consumer_kernel。在producer程序中会为写入 pipe预留足够的空间:


//reserve space in pipe for writing random numbers.
reserve_id_t rid = work_group_reserve_write_pipe(rng_pipe, szgr);

下一步,kernel程序会执行以下函数进行pipe写入和提交:


write_pipe(rng_pipe,rid,lid, &gfrn);
work_group_commit_write_pipe(rng_pipe, rid);


类似地,consumer程序从该pipe进行读取:

 

//reserve pipe for reading
reserve_id_t rid = work_group_reserve_read_pipe(rng_pipe, szgr);
if(is_valid_reserve_id(rid)) {
  //read random number from the pipe.
  read_pipe(rng_pipe,rid,lid, &rn);
  work_group_commit_read_pipe(rng_pipe, rid);
  }


之后consumer_kernel程序会使用该随机数集合来生成柱状图。CPU会生成一样的柱状图来检查正确性。其中,lid是一个work item的局部id,由get_local_id(0)来获取。

 

这个pipe示例展示了如何将pipe作为易用的数据结构来使用,使得两个kernel程序进行通信,其使用起来也是非常方便的。


在OpenCL1.2中,类似的通信行为需要主机的参与—尽管kernels程序可以不必把控制权交回主机来通信。然而使用Pipe后可以减少代码输入。此外,还有别pipes的示例与设备队列一起使用的,会在以后的文章中继续探讨。

 

总的来说,在OpenCL2.0中使用pipes会让代码变得更加简洁和易读。不要犹豫了,赶快编写代码来试试吧。

 

示例代码和自述文档


示例代码演示了OpenCL2.0的二分法搜索和区域增长特性。请根据以下链接进行访问:


1.     示例代码和自述文档请点击这里进行查阅

2.     请点击这里下载AMD OpenCL2.0驱动

3.     根据指引和自述文档来运行示例

欢迎进入OpenCL开发者论坛进行讨论和反馈


外文链接:http://developer.amd.com/community/blog/2014/10/31/opencl-2-0-pipes/

你可能感兴趣的:(OpenCL 2.0 规范 – Pipes(管道))