OpenCL编程指南-9.1命令、队列、事件

概述

命令队列是OpenCL的核心。平台定义了一个上下文,其中包含一个或多个计算设备。每个计算设备可以有一个或多个命令队列。提交到这些队列的命令将完成OpenCL程序的具体工作。

在一个简单的OpenCL程序中,提交到一个命令队列的命令会按顺序执行。一个命令完成后,下一个命令才能开始,程序会展开为一个有严格顺序的命令序列。各个命令存在大量并发性时,这种有序方法能够提供应用程序所需要的性能。

不过,实际的应用程序通常并没有这么简单。大多数情况下,应用程序不需要严格有序地执行命令。执行其他命令的同时,内存对象可以在设备和宿主机之间移动。处理不相关内存对象的命令可以并发执行。在一般的应用程序中,同时运行的命令会提供充分的并发性。这种并发性可以由运行时系统加以利用,来增加可实现的并行性,从而得到显著的性能提升。

还有一种常见的情况,即命令之间的依赖性能够表述为一个有向无环图(Directed AcyclicGraph,DAG)。这种图可能包含独立的分支,可以安全、并发地运行。如果要求这些命令以串行顺序运行,就会对系统带来不必要的约束。无序的命令队列允许系统充分利用这些命令之间的并发性,不过还有更多并发性可以利用。对于可能与不同计算设备关联的不同命令队列,通过在这些命令队列上运行DAG的独立分支,可以利用大量额外的并发性。

这些例子有一个共同的特点,应用程序有很多机会实现并发性,仅由命令队列是无法满足的。通过放宽这些顺序约束,在性能方面可能很有好处。不过,这些好处是有代价的。如果未使用命令队列的顺序语义来确保安全的命令执行顺序,这个工作就要由程序员来负责。在OpenCL中,这个任务可以利用事件来完成。

事件(event)是OpenCL中传递命令状态的对象。命令队列中的命令会生成事件,其他命令在执行之前可能要等待这些事件。用户可以创建定制事件,在宿主机和计算设备之间提供额外的一层控制。事件机制可以用来控制OpenCL和图形标准(如OpenGL)之间的交互。最后,在内核中,程序员利用事件可以允许数据的移动与这些数据的相关操作重叠进行。

事件和命令队列

OpenCL事件是OpenCL中传递命令有关信息的对象。事件的状态描述了相关命令的状态。可以取以下状态值。

CL_QUEUED: 命令已经在命令队列中排队。
CL_SUBMITTED: 入队的命令由宿主机提交给与命令队列关联的设备。
CL_RUNNING: 计算设备正在执行命令。
CL_COMPLETE: 命令已经完成。
ERROR_CODE: 负值指示遇到某种错误条件。具体的值为平台或生成该事件的运行时API返回的值。

创建事件有很多方法。最常见的事件源就是命令本身。在命令队列中排队的任何命令都会生成或等待事件。不同命令在API中都以同样的方式出现,所以我们可以利用一个例子来解释事件如何工作。考虑一个命令将内核入队,准备在一个计算设备上执行:

cl_int clEnqueueNDRangeKernel (cl_command_queue command_queue,cl_kernel kernel,cl_uint work_dim,const size_t *global_work_offset,const size_t *global_work_size,const size_t *local_work_size,cl_uint num_events_in_wait_list,const cl_event *event_wait_list,cl_event *event)

现在,我们只对这个函数的最后三个参数感兴趣

cl_uint num_events_in_wait_list: 这个命令在执行之前需要等待完成的事件数。const cl_event * event_wait_list: 这是一个指针数组,定义了这个命令等待的num_events_in_wait_list个事件。与event_wait_list中的事件和与command_queue关联的上下文必须相同。cl_event * event: 这是一个指针,指向这个命令生成的一个事件对象。可以由后续的命令或宿主机用来延续这个命令的状态。

参数num_events_in_wait_list和* event_wait_list提供了合法值时,只有当列表中的所有事件都有CL_COMPLETE状态或者有一个负值指示某个错误条件时,命令才会运行。

事件用来定义一个序列点,两个命令会在这里进入程序的一个已知状态,因此可以作为OpenCL中的一个同步点。与OpenCL中的所有同步点类似,根据OpenCL内存模型执行多个内核的情况下,内存对象会进入一个明确的状态。内存对象与一个上下文关联,所以即使计算涉及一个上下文中的多个命令队列,也能保证一致的状态。

例如,考虑下面这个简单的例子:

cl_event k_events[2];//enqueue two kernels exposing events
err = clEnqueueNDRangeKernel(commands, kernel1, 1, NULL, &global, &lobal, 0, NULL, &k_events[0]);err = clEnqueueNDRangeKernel(commands, kernel2, 1, NULL, &global, &lobal, 0, NULL, &k_events[1]);//enqueue the next kernel..which waits for two prior
//events before launching the kernel
err = clEnqueueNDRangeKernel(commands, kernel3, 1, NULL, &global, &local, 2, &k_events, NULL);

这里有3个内核排队等待执行。前两个clEnqueueNDRangeKernel命令将kernel1和kernel2入队。这些命令的最后一个参数会生成事件,事件将放在数组k_events[ ]的相应元素中。第三个clEnqueueNDRangeKernel命令将kernel3入队。如 clEnqueueNDRangeKernel的第7个参数和第8个参数所示,kernel3要等待数组k_events[ ]中的两个事件完成后,这个内核才会运行。不过,需要说明的是,将 kernel3入队的最后一个参数是 NULL。这表示我们不希望再生成一个让后续命令访问的事件。

如果需要详细控制命令执行的顺序,事件至关重要。不过,不需要这种控制时,可以让命令忽略事件(这包括事件的使用和生成),这会很方便。可以使用下面的过程告诉一个命令忽略事件:
1)将命令等待的事件数(num_events_in_wait_list)设置为0。
2)将事件数组的指针(*event_wait_list)设置为NULL。需要说明的是,如果设置这个指针为NULL,num_events_in_wait_list必须为0。
3)将指向所生成事件的指针(*event)设置为NULL。
这个过程可以确保不会等待任何事件,也不会生成任何事件,这当然意味着对于这个特定的内核执行实例,应用程序不可能查询事件或者将事件等待入队。

将命令入队时,通常需要指示一个同步点,该点之前的所有命令必须先完成,之后的命令才能开始。可以使用clBarrier()函数对队列中的命令指示这样一个同步点。

cl_int clEnqueueBarrier(cl_command_queue command_queue)

这个函数只有一个参数,定义了栅栏应用到哪个队列。如果函数成功执行,则命令返回CL_SUCCESS;否则,返回以下某个错误条件。

CL_INVALID_COMMMAND_QUEUE: 命令队列不是一个合法的命令队列。
CL_OUT_OF_RESOURCES: 在设备上分配OpenCL实现所需要的资源时失败。
CL_OUT_OF_HOST_MEMORY: 在宿主机上分配OpenCL实现所需要的资源时失败。

clEnqueueBarrier命令定义了一个同步点。这对于理解命令之间的顺序约束很重要。不过更重要的是,在介绍的OpenCL内存模型中,内存对象的一致性是针对同步点定义的。具体来说,在一个同步点上,命令可见的内存对象更新必须先完成,这样后面的命令才能看到新的值。

要定义更一般的同步点,OpenCL使用了事件和标志。标志用以下命令设置。

cl_int clEnqueueMarker(cl_command_queue command_queue,cl_event *event)cl_command_queue command_queue: 应用这个标志的命令队列
cl_event *event: 这个指针指向用来传递标志状态的事件对象

只有当所有命令都入队之后,标志命令才能完成。对于一个有序队列,clEnqueueMarker命令的效果就类似于一个栅栏。但与栅栏不同的是,标志命令会返回一个事件。宿主机或其他命令可以等待这个事件,来确保标志命令完成前所有命令都已经入队。如果函数成功执行,clEnqueueMarker会返回CL_SUCCESS;否则,返回以下错误之一。

CL_INVALID_COMMAND_QUEUE: command_queue不是一个合法的命令队列。
CL_INVALID_VALUE: 事件是一个NULL值。
CL_OUT_OF_RESOURCES: 在设备上分配OpenCL实现所需要的资源时失败。
CL_OUT_OF_HOST_MEMORY: 在宿主机上分配OpenCL实现所需要的资源时失败。

下面这个函数将一个事件等待入队,这会等待一个特定的事件或-组事件完成,之后才会执行将来入队的命令。

cl_int clEnqueueWaitForEvents(cl_command_queue command_queue,cl_uint num_events,const cl_event *event_list)cl_command_queue command_queue: 应用这个事件的命令队列
cl_uint num_events_in_wait_list: 这个命令等待完成的事件数
const cl_event *event_wait_list: 这是一个指针数组,定义了这个命令等待的num_events_in_wait_list个事件

这些事件定义了同步点。这意味着clEnqueueWaitForEvents完成时,内存模型中定义的内存对象更新必须完成,而且后续命令可以依赖于内存对象的一致状态。与event_list中的事件和与command_queue关联的上下文必须相同。

如果函数成功执行,则clEnqueuewaitForEvents返回CL_SUCCESS;否则,返回以下错误之一。

CL_INVALID_COMMMAND_QUEUE: command_queue不是一个合法的命令队列。
CL_INVALID_CONTEXT: 与command_queue和与event_list 中的事件关联的上下文不相同。
CL_INVALID_VALUE: num_events为0或event_list为NULL。
CL_INVALID_EVENT: event_list中指定的事件对象不是合法的事件。CL_OUT_OF_RESOURCES: 在设备上分配OpenCL实现所需要的资源时失败。CL_OUT_OF_HOST_MEMORY: 分配命令所需要的资源时失败。

这三个命令clEnqueueBarrier、clEnqueueMarker和 clEnqueueWaitForEvents 会对队列中的命令和同步点施加顺序约束,这会影响OpenCL内存的一致性。它们共同为OpenCL中的同步协议提供基础构建模块。

例如,考虑两个队列共享同一个上下文,但是将命令指向不同的计算设备。可以在这两个设备之间共享内存对象(因为它们共享同一个上下文),不过由于采用OpenCL的放宽的一致性内存模型,在某个给定点,共享的内存对象可能相对于一个队列(或另一个队列)中的命令处于一种不明确的状态。在一个策略点放置一个栅栏可以解决这个问题,程序员可能会用clEnqueueBarrier()命令来解决,如图9-1所示。
在这里插入图片描述
不过,OpenCL中的栅栏命令只会对该栅栏所在的命令队列施加约束,即约束其命令的顺序。程序员如何定义能够跨两个命令队列的栅栏呢? 如图9-2所示。
在这里插入图片描述
在其中一个队列中,clEnqueueMarker()命令入队,返回一个合法的事件对象。标志就相当于它自己的队列中的一个栅栏,不过还会返回一个事件,其他命令可以等待这个事件。在第二个队列中,我们在期望的位置设置了一个栅栏,并在栅栏后面增加了一个clEnqueueWaitForEvents调用。clEnqueueBarrier命令会使相应队列有期望的行为,也就是说,clEnqueueBarrier()之前的所有命令必须先完成,后面的命令才能执行。clEnqueueWaitForEvents()调用可以定义从其他队列到标志的连接。最终结果是得到一个同步协议,可以在两个队列之间定义栅栏功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/21915.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows下mysql的下载与安装

文章目录 1 下载2 安装目录下新建data文件夹和my.ini3 安装4设置密码与远程连接5 配置环境变量6 navicate连接成功 1 下载 官网地址 https://www.mysql.com/点击下载 社区下载 社区服务 选择版本下载 2 安装目录下新建data文件夹和my.ini my.ini 内容如下 [mysql] # 设置my…

【C#学习笔记】内存管理

文章目录 分配内存释放内存GC标记清除算法分代算法 .NET的GC机制有这样两个问题: 官方文档 自动内存管理 自动内存管理是CLR在托管执行过程中提供的服务之一。 公共语言运行时的垃圾回收器为应用程序管理内存的分配和释放。 对开发人员而言,这就意味着…

java-redis

1.Jedis 1.1 依赖引用 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.3.1</version> </dependency> 1.2 测试代码 RestController public class TestController {GetM…

〖Python网络爬虫实战㉝〗- aiohttp 的基本使用

订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000+python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明作者:爱吃饼干的小白鼠。Python领域优质创作者,2022年度…

二次开发了个寂寞之HttpRunnerManager接口测试管理平台

文章目录 一、背景1、二次开发1.1、首页1.2、项目列表1.3、用例列表1.4、新增用例1.5、测试套件1.6、查看报告 二、总结 一、背景 自入职起&#xff0c;就在公司内部引入开源接口测试平台&#xff0c;选一个大家勉强看得懂源码的开源项目&#xff0c;方便后续的二次开发&#x…

数据量特别大,自己手写虚拟dom节点展示数据。

当数据量特别大时&#xff0c;一次性全部展示出所有数据&#xff0c;会造成页面渲染慢&#xff0c;白屏&#xff0c;卡顿的现象。严重影响体验。为解决这样的问题&#xff0c;可以尝试使用虚拟加载dom节点的方式。 原理&#xff1a;根据屏幕高度和一条数据展示所需要的dom节点…

【每日一题】—— C. Mocha and Hiking(Codeforces Round 738 (Div. 2))

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

Kotlin~Visitor访问者模式

概念 将数据结构和操作分离&#xff0c;使操作集合可以独立于数据结构变化。 角色介绍 Visitor&#xff1a;抽象访问者&#xff0c;为对象结构每个具体元素类声明一个访问操作。Element&#xff1a;抽象元素&#xff0c;定义一个accept方法ConcreteElement&#xff1a;具体元…

docker 资源限制

目录 1、CPU使用率 2、CPU共享比例 3、CPU周期限制 4、CPU核心限制 5、CPU 配额控制参数的混合案例 6、内存限制 7、Block IO 的限制 8、限制bps 和iops docker资源限制 Docker容器技术底层是通过Cgroup&#xff08;Control Group 控制组&#xff09;实现容器对物理资…

Android 性能调优之bitmap的优化

背景 Android开发中&#xff0c;加载图片过多、过大很容易引起OutOfMemoryError异常&#xff0c;即我们常见的内存溢出。因为Android对单个应用施加内存限制&#xff0c;默认分配的内存只有几M&#xff08;具体视不同系统而定&#xff09;。而载入的图片如果是JPG之类的压缩格…

【unity】Pico VR 开发笔记(视角移动)

【unity】Pico VR 开发笔记&#xff08;视角移动&#xff09; 视角移动是简单的基础功能&#xff0c;这里区别于头显定位获得的小范围位移&#xff0c;是长距离不影响安全边界的位移方式。的常见的位移方式有两种&#xff0c;其一是触发后瞬间传送到指定位置&#xff0c;其次是…

flutter开发实战-BackdropFilter高斯模糊子Widget控件

flutter开发实战-BackdropFilter高斯模糊子Widget。 最近开发过程中遇到需要将控件进行模糊&#xff0c;比如iOS的effect的模糊效果。那在flutter中就需要用到了BackdropFilter 一、BackdropFilter BackdropFilter属性定义 BackdropFilter({Key key, required ImageFilter …

微服务---介绍

目录 1.微服务架构5个核心问题 2.微服务架构实现方案 3.微服务架构更多的是架构思想 4.学习微服务的意义 5.微服务架构一般采用 6.服务器有三种类型 1.微服务架构5个核心问题 &#xff08;解决这些问题都是依托于中间件&#xff0c;学微服务也是学这些中间件&#xff09;…

【C++】总结10--C++11第二篇

文章目录 RAIIC11新特性 RAII RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种利用对象生命周期来控制程序资源&#xff08;如内存、文件句柄、网络连接、互斥量等&#xff09;的简单技术&#xff0c;在对象的构造函数中获取资源&#xff0c;在对象…

深度学习torch基础知识

torch. detach()拼接函数torch.stack()torch.nn.DataParallel()np.clip()torch.linspace()PyTorch中tensor.repeat()pytorch索引查找 index_select detach() detach是截断反向传播的梯度流 将某个node变成不需要梯度的Varibale。因此当反向传播经过这个node时&#xff0c;梯度…

IDEA用Gradle构建项目时,lombok插件无效的解决办法

Lombok 可用来帮助开发人员消除 Java 的重复代码&#xff0c;尤其是对于简单的 Java 对象&#xff08;POJO&#xff09;&#xff0c;比如说getter/setter/toString等方法的编写。它通过注解实现这一目的。 正确使用姿势 一、安装Lombok插件 菜单栏File -> Settings ->…

死锁的发生原因和怎么避免

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 例如&#xff1a;项目场景&#xff1a;示例:通过蓝牙芯片(HC-05)与手机 APP 通信&#xff0c;每隔 5s 传输一批传感器数据(不是很大) 问题描述 死锁&#xff0c;简单来说就是两个或者两个以上的线程在…

翻转卡片游戏(力扣)

题目 在桌子上有 n 张卡片&#xff0c;每张卡片的正面和背面都写着一个正数&#xff08;正面与背面上的数有可能不一样&#xff09;。 我们可以先翻转任意张卡片&#xff0c;然后选择其中一张卡片。 如果选中的那张卡片背面的数字 x 与任意一张卡片的正面的数字都不同&#…

【C语言进阶】数据的存储----整型篇

​ &#x1f341; 博客主页:江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言——探索高效编程的基石 &#x1f4bb; 其他专栏&#xff1a;数据结构探索 ​&#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa; 社区&#xff1a;GeekHub &#x1f341; 如果觉…

洛谷P1525 关押罪犯(种类并查集)

S 城现有两座监狱&#xff0c;一共关押着 $N$ 名罪犯&#xff0c;编号分别为 $1-N$ 。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久&#xff0c;如果客观条件具备则随时可能爆发冲突。我们用“怨气值”&#xff08;一个正整数值&#xff09;来表示某两名罪犯之间的…