DeepDriving | CUDA编程-05:流和事件

本文来源公众号“DeepDriving”,仅用于学术分享,侵权删,干货满满。

原文链接:CUDA编程-05:流和事件

1 CUDA流

CUDA中有两个级别的并发内核级并发网格级并发。前面的文章DeepDriving | CUDA编程-04:CUDA内存模型-CSDN博客介绍的是内核级并发,这种并发方式是通过数据并行的方式用多个GPU线程去并发地完成一个内核任务,而网格级并发则是把一个任务分解为多个内核任务,通过在一个设备上并发地运行多个内核任务来实现任务的并发执行,这种方式使得设备的利用率更高。CUDA流是一系列异步操作的集合,同一个CUDA流中的操作严格按照顺序在GPU上运行,使用多个流同时启动多个内核任务就可以实现网格级并发。

首先来回顾一下一个典型的CUDA程序的执行流程:

  1. 将数据从host拷贝到device上;

  2. device上执行内核任务;

  3. 将数据从device上拷贝到host上。

这些操作都会在一个CUDA流中运行,如果显式地创建一个流那么这个流就是显式流(非空流)否则就是隐式流(空流),前面文章介绍的CUDA例程都是在隐式流中运行的。如果显式地创建多个流分别去执行上述3个操作步骤,那么不同的CUDA操作是可以重叠进行的,参考下图:

可以看到,使用多个流可以提升整个CUDA程序的运行效率。使用下面的方法可以声明和创建一个显式流:

cudaStream_t stream;
cudaStreamCreate(&stream);

要销毁一个流则可以使用下面的函数

cudaError_t cudaStreamDestroy(cudaStream_t stream);

由于显式流中的操作必须是异步的,而使用cudaMemcpy函数来拷贝数据是一种同步操作,所以必须使用它的异步版本才能在显式流中进行数据拷贝

cudaError_t cudaMemcpyAsync(void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream = 0);

这个函数的最后一个参数用于指定一个流标识符,默认情况下会使用空流。要执行异步的数据传输,那么就必须在host上使用固定内存,因为这样才能确保其在CPU内存中的物理地址在应用程序的整个生命周期内都不会被改变。可以使用下面的两个函数在host上分配固定内存:

cudaError_t cudaMallocHost(void **ptr, size_t size);
cudaError_t cudaHostAlloc(void **pHost, size_t size, unsigned int flags);

在非空流中启动内核的时候,必须在内核执行配置中提供一个流标识符作为第4个参数(第3个参数为共享内存的大小,如果没有分配可以设置为0):

kernel_name<<<grid, block, sharedMemSize, stream>>>(...);

显式流的所有操作都是异步的,可以在host代码中调用下面两个函数去检查流中的所有操作是否完成:

cudaError_t cudaStreamSynchronize(cudaStream_t stream);
cudaError_t cudaStreamQuery(cudaStream_t stream);

cudaStreamSynchronize函数会强制阻塞host直到指定流中的所有操作都已经执行完成;cudaStreamQuery函数则不会阻塞host,如果指定流中的所有操作都已完成,它会返回cudaSuccess,否则返回cudaErrorNotReady

2 CUDA事件

一个CUDA事件是CUDA流中的一个标记点,它可以用来检查正在执行的流操作是否已经到达了该点。使用事件可以用来执行以下两个基本任务:

  • 同步流的执行操作

  • 监控device的进展

CUDA提供了在流中的任意点插入并查询事件完成情况的函数,只有当流中先前的所有操作都执行结束后,记录在该流中的事件才会起作用。

声明和创建一个事件的方式如下:

cudaEvent_t event;
cudaError_t cudaEventCreate(cudaEvent_t* event);

调用下面的函数可以销毁一个事件

cudaError_t cudaEventDestroy(cudaEvent_t event);

一个事件可以使用如下函数进入CUDA流的操作队列中

cudaError_t cudaEventRecord(cudaEvent_t event, cudaStream_t stream = 0);

下面的函数会在host中阻塞式地等待一个事件完成

cudaError_t cudaEventSynchronize(cudaEvent_t event);

与流类似的,也可以非阻塞式地去查询事件的完成情况

cudaError_t cudaEventQuery(cudaEvent_t event);

如果想知道两个事件之间的操作所耗费的时间,可以调用

cudaError_t cudaEventElapsedTime(float* ms, cudaEvent_t start, cudaEvent_t stop);

这个函数以毫秒为单位返回开始和停止两个事件之间的运行时间,启动和停止事件不必在同一个CUDA流中。

可以参考以下代码:

cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);cudaEventRecord(start);
VectorAddGPU<<<block_per_grid, thread_per_block>>>(da, db, dc, size);
cudaEventRecord(stop);cudaEventSynchronize(stop);
float elapsed_time;
cudaEventElapsedTime(&elapsed_time, start, stop);std::cout << "Elapsed time: " << elapsed_time << " ms." << std::endl;cudaEventDestroy(start);
cudaEventDestroy(stop);

3 流同步

CUDA包括两种类型的host-device同步:显示同步和隐式同步。

前面文章中介绍过的很多函数都是隐式同步的,比如cudaMemcpy函数,它会使得host应用程序在数据传输完成之前都会被阻塞。许多与内存相关的操作都带有隐式同步行为,比如:

  • host上的固定内存分配,比如cudaMallocHost

  • device上的内存分配,比如cudaMalloc

  • device上的内存初始化

  • 同一device上两个地址之间的内存拷贝

  • 一级缓存/共享内存配置的修改

CUDA提供了几种显示同步的方法:

  • 使用cudaDeviceSynchronize函数同步device

  • 使用cudaStreamSynchronize函数同步流

  • 使用cudaEventSynchronize函数同步流中的事件

除此之外,CUDA还提供了下面的函数使用事件进行跨流同步:

cudaError_t cudaStreamWaitEvent(cudaStream_t stream, cudaEvent_t event);

该函数可以使指定的流等待指定的事件,该事件可能与同一个流相关,也可能与不同的流相关,如果是不同的流那么这个函数就是执行跨流同步功能。

4 参考资料

  • CUDA C 编程权威指南

  • Professional CUDA C Programming

  • CUDA C Programming Guide

  • CUDA Programming:A Developer's Guide to Parallel Computing with GPUs

THE END !

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

jdk17详细安装步骤

本文以Windows系统&#xff0c;JDK17版本作为示例&#xff0c;其他版本的操作步骤类似。 一、下载 进入官网后往下翻&#xff0c;找到JAVA17&#xff0c;然后点击Windows 点击下载。 二、安装 安装 JDK的安装是无脑安装&#xff0c;就是一路下一步下一步。。直到完成。默认安…

Docker部署MaxKB 知识库(提高问答命中率)

前言 上一篇文章简单的介绍了下MaxKB&#xff0c;这一篇文章就讲如何部署MaxKB。 MaxKB实现逻辑也比较简单&#xff0c;如下图。 安装 修改Docker镜像源 由于不可抗力&#xff0c;部分源已经无法使用&#xff0c;需要修改以下的源地址来拉取镜像。如果是linux&#xff0c;…

VMware软件的安装与安装Win10系统

上一篇写了&#xff08;虚拟机&#xff09;VMware软件的安装及Ubuntu系统安装&#xff0c;这次续上部分&#xff0c;安装完Ubuntu系统后&#xff0c;又安装了win10&#xff0c;也记录一下。 事前准备好win10镜像文件&#xff0c;可在微软官网下载 入口地址&#xff1a;软件下…

Codesys V3.5 下载安装教程+ 所有版本大全集合

文章目录 一、codesys V3.5 所有的版本集合二、 视频安装教程三、 安装包下载地址四、详细的安装步骤 一、codesys V3.5 所有的版本集合 codesys 版本更新很快&#xff0c;这是小编整理的所有codesys版本&#xff0c;都放在百度网盘上了&#xff0c;在文章最后可以获取下载链接…

MyBatis使用Demo

文章目录 01、Mybatis 意义02、Mybatis 快速入门04、Mapper 代理开发05、Mybatis 配置文件07、查询所有&结果映射08、查询-查看详情09、查询-条件查询10、查询-动态条件查询多条件动态查询单条件动态查询 11、添加&修改功能添加功能修改功能 12、删除功能删除一个批量删…

远程桌面失败:你的凭据不工作

远程桌面失败&#xff1a;你的凭据不工作 远程桌面失败&#xff1a;你的凭据不工作_您的凭据不工作-CSDN博客https://blog.csdn.net/weixin_38004638/article/details/82290796

Python合并文件(dat、mdf、mf4)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

鸿蒙轻内核M核源码分析系列二一 03 文件系统LittleFS

2.2 文件信息数组操作 函数LfsAllocFd()设置文件信息数组元素信息。参数fileName为文件路径信息&#xff0c;传出参数fd为文件描述符即数组索引。遍历文件信息数组&#xff0c;遍历到第一个未使用的元素标记其为已使用状态&#xff0c;设置文件路径信息&#xff0c;把数组索引…

C++ 45 之 赋值运算符的重载

#include <iostream> #include <string> #include <cstring> using namespace std;class Students05{ public:int m_age;char* m_name;Students05(){}Students05(const char* name,int age){// 申请堆空间保存m_name;this->m_name new char[strlen(name)…

宝藏速成秘籍(7)堆排序法

一、前言 1.1、概念 堆排序&#xff08;Heapsort&#xff09;是指利用堆这种数据结构所设计的一种排序算法 。堆是一个近似 完全二叉树 的结构&#xff0c;并同时满足堆积的性质&#xff1a;即子结点的键值或索引总是小于&#xff08;或者大于&#xff09;它的父节点。 1.2、排…

本地靶场搭建

1、windows service2003 链接&#xff1a;https://pan.baidu.com/s/1RIealrcfcDWKu1AIuYFbAQ?pwd4bv8 提取码&#xff1a;4bv8 2、asp环境搭建&#xff08;虚拟机内&#xff09; ①asp工作原理&#xff1a; 客户发送网站请求&#xff0c;iis接收客户请求&#xff0c;解析…

[图解]《分析模式》漫谈04-Martin Fowler叫的是哪家的士

1 00:00:01,230 --> 00:00:04,190 今天我们来探讨一个有趣的话题 2 00:00:05,130 --> 00:00:08,350 Martin Fowler&#xff0c;他叫的是哪一家的的士 3 00:00:11,980 --> 00:00:15,240 第2章这里&#xff0c;Martin Fowler写 4 00:00:15,250 --> 00:00:18,550 他…

【redis的基本数据类型】

基本数据类型 Redis的基本数据类型有五种&#xff0c;分别是 StringListHashSetSortedSet 这些基本的数据类型构成了其他数据类型的基石&#xff0c;而这些基本数据类型又对应着不同的底层实现&#xff0c;不同的底层实现往往是针对不同的使用场景做的特殊的优化&#xff0c;…

自然资源-地理知识收藏好

自然资源-地理知识收藏好 每个华夏儿女应该知道的中国地理知识&#xff0c;中国&#xff0c;全称中华人民共和国&#xff0c;位于亚洲东部&#xff0c;太平洋西岸&#xff0c;是世界四大文明古国之一&#xff0c;华夏文明的发源地&#xff0c;陆地面积约960万平方千米&#xf…

50【Aseprite 作图】模糊工具 笔刷

1 模糊工具 2 笔刷 然后 选中 后 Ctrl B&#xff0c;就变成笔刷了 可以按住shift &#xff0c;像画一条线一样 或者用矩形、圆形工具、油漆桶工具 在上方可以选择笔刷的不同形式&#xff0c;如果是“图案与来源对齐”&#xff0c;就是来源不变&#xff0c;笔刷不会覆盖之前…

⭐Unity 控制任意UI的渐隐渐显

使用脚本之前先给要控制的UI加上CanvasGroup组件 解释: 这个脚本使用协程来逐渐改变CanvasGroup的alpha值&#xff0c;从而实现渐隐和渐显的效果。 Mathf.Lerp函数用于在指定的时间内平滑地从当前透明度过渡到目标透明度。 通过调用FadeIn和FadeOut方法&#xff0c;你可以在任…

Python 小市值股票模型代码及回测分析

目录 一、模型介绍 二、代码详解 2.1 初始化函数 2.2 股票筛选过滤函数 2.3 止损函数 2.4 开盘时运行函数 2.5 调仓函数 三、回测结果分析 3.1 收益净值图与概述 3.2 模型收益概览 3.3 年度收益图 3.4 月度收益的时间序列 3.5 月度收益热力图 3.6 月度收益频次分…

业务动态校验框架应用实现

目录 一、业务背景 二、配置内容展示 三、商品动态配置内容展示 &#xff08;一&#xff09;商品spu校验信息数据 &#xff08;二&#xff09;商品sku校验信息数据 &#xff08;三&#xff09;组包商品校验信息数据 &#xff08;四&#xff09;商品数据校验数据持有者 &…

嵌入式软件工程师入何突破瓶颈?

各位关注嵌入式软件工程师发展的朋友们&#xff0c;下面来探讨一下嵌入式软件工程师该如何突破瓶颈。首先要强调的是&#xff0c;不要仅仅将自己局限在嵌入式软件工程师这一角色定位上。 事实上&#xff0c;嵌入式软件工程师已经掌握了诸多业务层面的内容&#xff0c;完全有能力…

【博客718】时序数据库基石:LSM Tree(log-structured merge-tree)

时序数据库基石&#xff1a;LSM Tree(log-structured merge-tree) 1、为什么需要LSM Tree LSM被设计来提供比传统的B树更好的写操作吞吐量&#xff0c;通过消去随机的本地更新操作来达到这个目标&#xff0c;使得写入都是顺序写&#xff0c;而不是随机写。 那么为什么这是一个…