news 2026/4/3 4:47:11

并行编程实战——CUDA编程的事件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
并行编程实战——CUDA编程的事件

一、CUDA中的事件

大家可能在别的开发语言中都学习过事件这个概念,其实在CUDA中事件这个概念与它们都类似。不过,在CUDA中事件更贴近于其字面本身的意义,它是类似一种标志,用来密切监视设备进度即同步工具。同时可以通过让应用程序在程序中的任何点异步记录事件并查询这些事件何时完成来执行准确的计时。当事件之前的所有任务(或可选地,给定流中的所有命令)都已完成时,事件即已完成。在所有流中的所有先前任务和命令完成之后,流零(指空或默认流)中的事件也会完成。
也就是说,在CUDA编程中,事件既可以作为同步工具又可以作为精确测量执行时间的工具。

二、CUDA事件主要应用场景

通过上面的说明,大家可以基本明白CUDA事件的定义,那么对事件来说其应用场景是什么呢?

  1. 性能测量
    利用事件既可以进行内核时间的测量,还可以进行流线的操作(计算重叠等)
cudaEventRecord(start,0);for(inti=0;i<2;++i){cudaMemcpyAsync(inputDev+i*size,inputHost+i*size,size,cudaMemcpyHostToDevice,stream[i]);MyKernel<<<100,512,0,stream[i]>>>(outputDev+i*size,inputDev+i*size,size);cudaMemcpyAsync(outputHost+i*size,outputDev+i*size,size,cudaMemcpyDeviceToHost,stream[i]);}cudaEventRecord(stop,0);cudaEventSynchronize(stop);floatelapsedTime;cudaEventElapsedTime(&elapsedTime,start,stop);
  1. 流的同步
    主要用于控制流间的依赖关系,如多流的同步,不同阶段间的计算同步以及多GPU的数据依赖和Graphic,另外还可以进行动态工作流的控制处理。
__global__voidfoo1(char*A){*A=0x1;}__global__voidfoo2(char*B){printf("%d\n",*B);// *B == *A == 0x1 assuming foo2 waits for foo1// to complete before launching}cudaMemcpyAsync(B,input,size,stream1);// Aliases are allowed at// operation boundariesfoo1<<<1,1,0,stream1>>>(A);// allowing foo1 to access A.cudaEventRecord(event,stream1);cudaStreamWaitEvent(stream2,event);foo2<<<1,1,0,stream2>>>(B);cudaStreamWaitEvent(stream3,event);cudaMemcpyAsync(output,B,size,stream3);// Both launches of foo2 andcudaMemcpy (which both read)// wait for foo1 (which writes) to complete before proceeding

注:上面代码来自CUDA官网

三、流和流同步

虽然事件可以进行流同步,但与流同步还是有一些不同之处,主要有:

  1. 事件的同步机制更灵活,可以多流间控制。而流同步一般是整个流内部
  2. 事件控制比流同步更精确,上文也提到了,事件可以进行点的控制,而流同步一般是整个流
  3. 事件与流同步相比,开销更低
  4. 事件应用比流同步要广泛,除了同步外还可以进行计时等处理

技术概念间互相对比,可以更好的加强学习理解的深刻性。

四、例程

针对上面的说明,可以看下面的例程:

#include"cuda_runtime.h"#include"device_launch_parameters.h"#include<stdio.h>#include<stdlib.h>__global__voidkernelFunc(float*data,intnum,floatfactor){intidx=blockIdx.x*blockDim.x+threadIdx.x;if(idx<num){data[idx]=data[idx]*factor+idx*0.001f;}}intmain(){constintN=1<<20;// 100wconstintnumStreams=4;constintchunkSize=N/numStreams;constsize_tchunkBytes=chunkSize*sizeof(float);constsize_ttotalBytes=N*sizeof(float);printf("mul stream sync test...\n");float*hData=NULL;cudaMallocHost(&hData,totalBytes);for(inti=0;i<N;i++){hData[i]=(float)rand()/RAND_MAX;}float*dData=NULL;cudaMalloc(&dData,totalBytes);cudaStream_tstreams[numStreams];for(inti=0;i<numStreams;i++){cudaStreamCreate(&streams[i]);}//1 cacl timecudaEvent_tstartEvent,stopEvent;cudaEvent_tkernelEvents[numStreams];cudaEventCreate(&startEvent);cudaEventCreate(&stopEvent);for(inti=0;i<numStreams;i++){cudaEventCreateWithFlags(&kernelEvents[i],cudaEventDisableTiming);}cudaEventRecord(startEvent,0);intthreadsPerBlock=256;intblocksPerChunk=(chunkSize+threadsPerBlock-1)/threadsPerBlock;for(inti=0;i<numStreams;i++){intoffset=i*chunkSize;cudaMemcpyAsync(&dData[offset],&hData[offset],chunkBytes,cudaMemcpyHostToDevice,streams[i]);kernelFunc<<<blocksPerChunk,threadsPerBlock,0,streams[i]>>>(&dData[offset],chunkSize,(float)(i+1)*0.5f);cudaGetLastError();cudaEventRecord(kernelEvents[i],streams[i]);cudaMemcpyAsync(&hData[offset],&dData[offset],chunkBytes,cudaMemcpyDeviceToHost,streams[i]);}for(inti=0;i<numStreams;i++){cudaStreamSynchronize(streams[i]);}// record finish timepointcudaEventRecord(stopEvent,0);cudaEventSynchronize(stopEvent);floattotalTime=0.f;cudaEventElapsedTime(&totalTime,startEvent,stopEvent);printf("sum time: %.3f ms\n",totalTime);//2 stream dependedprintf("\n stream sync :\n");cudaEvent_tsyncEvent;cudaEventCreate(&syncEvent);kernelFunc<<<blocksPerChunk,threadsPerBlock,0,streams[0]>>>(dData,chunkSize,2.0f);cudaEventRecord(syncEvent,streams[0]);for(inti=1;i<numStreams;i++){cudaStreamWaitEvent(streams[i],syncEvent,0);kernelFunc<<<blocksPerChunk,threadsPerBlock,0,streams[i]>>>(&dData[i*chunkSize],chunkSize,1.5f);}for(inti=0;i<numStreams;i++){cudaStreamSynchronize(streams[i]);}printf("sync finish \n");printf("\n event query:\n");cudaEvent_tqueryEvent;cudaEventCreate(&queryEvent);kernelFunc<<<blocksPerChunk,threadsPerBlock>>>(dData,chunkSize,1.0f);cudaEventRecord(queryEvent,0);intmaxChecks=100;intcheckCount=0;while(cudaEventQuery(queryEvent)==cudaErrorNotReady){checkCount++;if(checkCount<maxChecks){intdummy=0;for(intj=0;j<1000;j++){dummy+=j;}}else{cudaEventSynchronize(queryEvent);break;}}printf("event query count: %d\n",checkCount);cudaEventDestroy(syncEvent);cudaEventDestroy(queryEvent);cudaEventDestroy(startEvent);cudaEventDestroy(stopEvent);for(inti=0;i<numStreams;i++){cudaEventDestroy(kernelEvents[i]);cudaStreamDestroy(streams[i]);}cudaFree(dData);cudaFreeHost(hData);cudaDeviceReset();printf("\n all finish!\n");return0;}

上面代码的功能主要用于多流间的同步,同时对整体的操作时间进行计算。有前面代码的基础,应该不难。如果有什么不太清楚的,上机运行,增加一些打印日志就明白了。

五、总结

在前面CUDA流的学习中,对CUDA事件进行了顺带的说明。本文则展开事件,对其具体的内容和应用进行阐述。通过实际的例程让大家可以更清楚的明白事件的运行机制。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 20:23:41

Django+vue3课程教学作业批改系统 远程在线教育系统

目录摘要开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;摘要 该系统基于Django后端框架与Vue3前端框架&#xff0c;构建了一个支持远程在线教育、课程教学与作业批改的综合性平台。通过模块…

作者头像 李华
网站建设 2026/3/31 23:41:14

vue3+python+django的典当行抵押信息管理系统的设计与实现

目录典当行抵押信息管理系统的设计与实现摘要开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;典当行抵押信息管理系统的设计与实现摘要 该系统基于Vue3前端框架、Python编程语言及Django后端…

作者头像 李华
网站建设 2026/3/29 18:29:40

PostgreSQL实战:psql命令行的高效使用技巧

文章目录一、概述1.1 为什么要掌握 psql ?1.2 如何深入掌握 psql ?一、psql 基础&#xff1a;连接与启动1.1 安装与验证1.2 基本连接语法1.3 使用连接 URI1.4 快速进入与退出二、核心元命令&#xff08;Meta-Commands&#xff09;&#xff1a;psql 的灵魂2.1 数据库与对象浏览…

作者头像 李华
网站建设 2026/3/28 23:06:35

基于springboot的动物保护宣传网站

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

作者头像 李华
网站建设 2026/3/26 22:45:47

【程序源代码】旅游小程序(2026年最新含源码)

关键字&#xff1a;旅游小程序&#xff08;2026年最新含源码&#xff09; &#xff08;一&#xff09;系统介绍 1.1 系统介绍 旅游小程序&#xff08;2026年最新含源码&#xff09; 包含&#xff1a;首页&#xff0c;智能助手AI、行程管理、个人管理四个主要模块。分为…

作者头像 李华