当前位置: 首页 > news >正文

并行编程实战——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事件进行了顺带的说明。本文则展开事件,对其具体的内容和应用进行阐述。通过实际的例程让大家可以更清楚的明白事件的运行机制。

http://www.jsqmd.com/news/262332/

相关文章:

  • 不可篡改环境下的测试新挑战
  • 探寻空间计算服务商公司概况,广东省空间计算科技集团合作案例分享 - 工业品牌热点
  • vue3+python+django电影影视剧本创作论坛交流系统
  • vue3+python+django的中草药销售系统的设计与开发
  • vue3+python+django的乡镇中学网上办公自动化系统
  • 航空调度系统灾备切换可靠性测试框架‌——面向测试工程师的实战方法论
  • vue3+python+django的典当行抵押信息管理系统的设计与实现
  • CC教程
  • Android与iOS跨平台UI一致性验收实战指南:从挑战到自动化避坑
  • vue3+python+django的农村智慧社区系统设计与开发
  • 可信平台成“帮凶”?2025年10月钓鱼与勒索攻击激增,Tycoon 2FA绕过MFA引发新警报
  • 2025年目前知名的节能门窗生产厂家找哪家,智能门窗/被动式窗/别墅装修/家居设计/高端定制门窗源头厂家推荐 - 品牌推荐师
  • “MFA已过时?”Tycoon 2FA钓鱼套件掀起会话劫持风暴,全球超6万账户沦陷
  • 2026-1-18 humann工作流总结
  • vue3+python+django的流量卡售卖系统的设计与实现
  • 一封“2FA更新”邮件,险些让数亿开发者中招——NPM供应链钓鱼事件揭示开源生态的致命软肋
  • 揭秘专业的渠道经理吴嘉林怎样拓展渠道,有何独特方法? - 工业品牌热点
  • 总结2026年宁波镇海实力强的刑事律师事务所,浙杭律师事务所实力雄厚 - 工业品牌热点
  • Django+vue3课程教学作业批改系统 远程在线教育系统
  • 当“猎头私信”变成钓鱼入口:LinkedIn成企业安全新盲区,AitM攻击绕过MFA引发警报
  • python+vue3非遗手工品展示与商城交易平台
  • 当“图片”会执行代码:SVG钓鱼载荷引爆新型供应链攻击,Amatera窃密与PureMiner挖矿暗流涌动
  • 【中国科学院光电研究所-张建林组-AAAI26】追踪不稳定目标:基于外观引导的运动建模在无人机拍摄视频中实现稳健的多目标跟踪
  • vue3+python +django 的茶文化交流平台
  • Java微服务连接同个MySQL实例报错“Too many connections”
  • 2026年市场上评价好的船用减压阀公司口碑排行,船用疏水阀/船舶配件/船用舷侧阀/船用安全阀,船用减压阀直销厂家口碑排行 - 品牌推荐师
  • 2104.25万,深圳市气象局数字孪生(CIM)创新应用项目
  • spring webflux响应式编程学习
  • 2026年市场评价好的实心钢棒定制加工怎么选择,不锈钢带/不锈钢冷轧板/不锈钢天沟,实心钢棒生产厂家怎么选择 - 品牌推荐师
  • 1.17-1.23日博客之星投票,每日可投