news 2026/2/3 2:04:32

并行编程实战——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/2/3 3:01:42

基于VUE的残疾人就业系统[VUE]-计算机毕业设计源码+LW文档

摘要&#xff1a;残疾人就业是社会公平与和谐发展的重要体现&#xff0c;然而当前残疾人就业面临着信息不对称、就业渠道有限等诸多问题。本文旨在设计并实现一个基于VUE的残疾人就业系统&#xff0c;以改善这一现状。该系统采用前后端分离架构&#xff0c;前端运用VUE框架及相…

作者头像 李华
网站建设 2026/2/3 7:12:11

【Java源码】基于SpringBoot的在线考试系统

1项目介绍本课程演示的是一套基于SpringBoot的在线考试系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料带你从零开始部署运行本套系统该项目附带的源码资料可…

作者头像 李华
网站建设 2026/2/1 3:30:22

‌测试自动化新星:AI驱动的视觉测试工具盘点

AI如何重塑视觉测试领域‌ 在软件测试的演进历程中&#xff0c;视觉测试&#xff08;Visual Testing&#xff09;一直是确保用户界面&#xff08;UI&#xff09;一致性和用户体验的关键环节。传统方法依赖脚本化的像素比对&#xff0c;但面对动态内容、响应式设计和跨设备兼容…

作者头像 李华
网站建设 2026/1/30 13:34:34

突发!前端框架Astro被收购,Bun 创始人第一时间发来贺电!

就在刚刚&#xff0c;前端圈传来一则重磅消息&#xff1a;Astro 官方宣布正式被 Cloudflare 收购&#xff01;Astro 的核心团队将全员加入 Cloudflare&#xff0c;继续负责 Astro 的开发和维护。消息一出&#xff0c;连 Bun 的创始人 Jarred Sumner 也在第一时间赶到现场&#…

作者头像 李华
网站建设 2026/1/29 1:43:31

梁文峰去年进账50亿,DeepSeek粮草充足

来源&#xff1a;量子位R1横空出世一年后&#xff0c;DeepSeek依然没有新融资。在大模型玩家上市的上市、融资的融资的热闹中&#xff0c;DeepSeek还是那么高冷&#xff0c;并且几乎没有任何商业化的动作。即便如此&#xff0c;AGI也没有落下——持续产出高水平论文&#xff0c…

作者头像 李华