OpenCL 主机端与设备端命令的存储器次序规则

本文将描述与命令队列相关联的OpenCL API函数如何应用于前置关系。在OpenCL 2.0中有两种类型的命令队列与相关API——主机端命令队列与设备端命令队列。在某些情况下,该规则仅用于主机端命令。我们将在存储器次序规则中特别说明主机端命令队列来指出这些特殊情况。在这种实例中的SVM存储器一致性仅仅与同步主机端命令相关。

在本节的剩余部分,我们假定每个排入命令队列的命令C含有一个相关联的事件对象E,该事件对象把其执行状态作为信号发出,不管E是否返回到排队命令C时所处的执行单元。我们也区分出排队一个命令C与创建一个事件E之间的区别,执行命令C与完成命令C之间的区别。
API命令的次序与同步规则定义如下:

1)如果一个API函数调用X将一个命令C排队到名列队列,那么X全局同步于C。比如,排队一个内核程序的主机端API函数,全局同步于内核实例执行的开始。这样,存储器更新次序将内核函数调用排在名令队列之前,存储器更新将全局发生在任一内核对相同存储器位置的读或写之前。对于一个设备端的排队,全局存储器更新次序在X之前,X发生在C对的存储器位置的读写之前(仅在那些存储器位置属于细粒度SVM的情况下)。

2)如果E是一个命令C所等待的事件,那么E全局同步于C。特别地,如果C等待一个事件E,而E在追踪命令C1的执行状态,那么由C1完成的存储器操作将全局发生在由C完成的存储器操作之前。例如,假定我们有一个OpenCL程序使用粗粒度的SVM,共享排队到一个主机端命令队列中的内核,以操作由主机端线程分配的一个缓存的某个区域,然后在内核完成后由主机端线程对那个缓存区域进行访问。为了完成这个功能,主机端线程可以调用clEnqueueMapBuffer将一个阻塞模式的映射命令排队到命令队列,以映射那个存储区域。然后指定该映射命令必须等待一个内核完成信号事件。当clEnqueueMapBuffer返回时,任一对那个缓存区域所执行的存储器操作,均将全局发生在由主机端线程所执行的后续存储器操作之前。

3)对于排队到主机端命令队列的命令C,如果C具有一个事件E,该事件在其完成时发送信号,那么E全局同步于等待E的API调用X。例如,如果一个主机端线程或内核实例调用E的事件等待函数(如在一个主机端线程上调用clWaitForEvents函数),那么E全局同步于事件等待函数调用。

4)如果命令C与C1按次序排队到命令队列中,那么把C发送完成的信号事件(包括在C与C1之间所隐含的事件)全局同步于C1。注意,在OpenCL 2.0中,只有主机端命令可以被配置为前置次序的队列。

5)如果一个API调用将一个标记(marker)命令C排队到命令队列中,并且事件列表中不含任何C要等待的事件,那么在命令队列中排在C之前的所有命令的事件全局同步于C。

6)如果一个主机端API调用将一个栅栏(barrier)命令C排队到命令队列,且事件列表中不含任何C要等待的事件,那么在命令队列中排在C之前的所有命令的事件全局同步于命令队列中排在C之后的所有命令。

7)如果一个主机端线程执行了一次clFinish调用X,那么在命令队列中排在X之前的所有命令的事件全局同步于X。

8)一个内核实例K开始执行时,全局同步于K包含的工作项的所有操作。注意,这涵盖了使用粗粒度SVM程序中工作项的所有原子操作。

9)一个内核实例K的所有工作项的所有操作全局同步于K完成的事件信号。注意,这也包括了在一个程序中使用细粒度的SVM的工作项所执行的任一原子操作。

10)如果一个回调过程P注册在一个事件E上,那么E全局同步于P的所有操作。注意,回调过程仅对主机端命令队列内的命令进行定义。

11)如果C是一个等待事件E完成的命令,且X将一个用户事件E的状态设置为CL_COMPLETE(如在主机端线程使用clSetUserEventStatus函数),那么X全局同步于C。

12)如果一个设备用CLK_ENQUEUE_FLAGS_WAIT_KERNEL标志来排队一个命令C,那么父内核实例的结束状态全局同步于C。

13)如果一个工作组用CLK_ENQUEUE_FLAGS_WAIT_WORK_GROUP标志排队一个命令C,那么该工作组的结束状态全局同步于C。

当使用一个无序(out-of-order)命令队列时,等待一个事件、标记或命令队列栅栏命令中的可确保正确的命令依赖次序。在这些情况下,等待一个事件、标记或栅栏命令将提供必要的全局同步于关系。

OpenCL 1.2标准描述了一个同步点作为一个内核实例或主机端程序的位置。该位置处存储器内容对不同工作项或命令队列中的命令可观察到相同的内容。也就是说,等待一个事件或命令队列栅栏,是在命令队列中各命令之间的同步点。上述规则中的2)、4)、7)、8)涵盖了这些OpenCL同步点的描述。

在一个非SVM缓存或粗粒度SVM缓存上执行的一个映射操作(clEnqueueMapBuffer或clEnqueueMapImage)允许用最后运行时通过该映射操作同步的命令所观察到的数据覆盖整个目标区域,不管这些值是否由执行内核所写。当与该映射操作所同步的内核正在执行时,在此区域内由另一个内核或主机端线程所改变的任一值可以被映射操作所覆盖。

如果细粒度的SVM被使用,但没有支持OpenCL 2.0原子操作,那么主机端以及设备端可以并发读同一个存储器位置,并且可以并发更新非叠交的存储器区域,但企图更新同一个存储器位置,那么结果是未定义的。存储器一致性会在OpenCL同步点得到保证,所以不需要调用clEnqueueMapImage和clEnqueueUnmapMemObject。对于细粒度SVM缓存,只在内核所写的值在同步点处才保证可用。细粒度SVM缓存只允许在原始程序中的写。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程