高性能计算-CUDA单流多流控制

news/2025/1/8 12:38:32/文章来源:https://www.cnblogs.com/anluo8/p/18656498

1. 介绍:

(1) 用CUDA计算 pow(sin(id),2)+ pow(cos(id),2)的结果
(2) 对比单流(同步传输、异步传输)、多流深度优先调度、多流广度优先调度的效率(包含数据传输和计算)

核心代码

1. 用CUDA计算 pow(sin(id),2)+ pow(cos(id),2)的结果
2. 对比单流(同步传输、异步传输)、多流深度优先调度、多流广度优先调度的效率(包含数据传输和计算)
3. 使用接口错误检查宏
*/#include <stdio.h>#define CUDA_ERROR_CHECK    //API检查控制宏#define BLOCKSIZE 256
int N = 1<<28;              //数据个数
int NBytes = N*sizeof(float); //数据字节数//宏定义检查API调用是否出错
#define CudaSafecCall(err) __cudaSafeCall(err,__FILE__,__LINE__)
inline void __cudaSafeCall(cudaError_t err,const char* file,const int line)
{#ifdef CUDA_ERROR_CHECKif(err!=cudaSuccess){fprintf(stderr,"cudaSafeCall failed at %s:%d :(%d) %s\n",file,line,err,cudaGetErrorString(err));exit(-1);}#endif
}//宏定义检查获取流中的执行错误,主要是对核函数
#define CudaCheckError() _cudaCheckError(__FILE__,__LINE__)
inline void _cudaCheckError(const char * file,const int line)
{#ifdef CUDA_ERROR_CHECKcudaError_t err = cudaGetLastError();if(err != cudaSuccess){fprintf(stderr,"cudaCheckError failed at %s:%d :(%d) %s\n",file,line,err,cudaGetErrorString(err));exit(-1);}#endif
}__global__ void kernel_func(float * arr,int offset,const int n)
{int id = offset + threadIdx.x + blockIdx.x * blockDim.x;if(id<n)arr[id] = pow(sinf(id),2) + pow(cosf(id),2);
}//单流主机非锁页内存,同步传输
float gpu_base()
{//开辟主机非锁页内存空间float* hostA,*deviceA;hostA = (float*)calloc(N,sizeof(float));CudaSafecCall(cudaMalloc((void**)&deviceA,NBytes));float gpuTime = 0.0;cudaEvent_t start,end;CudaSafecCall(cudaEventCreate(&start));CudaSafecCall(cudaEventCreate(&end));CudaSafecCall(cudaEventRecord(start));CudaSafecCall(cudaMemcpy(deviceA,hostA,NBytes,cudaMemcpyHostToDevice));kernel_func<<<(N-1)/BLOCKSIZE + 1,BLOCKSIZE>>>(deviceA,0,N);CudaCheckError();CudaSafecCall(cudaEventRecord(end));CudaSafecCall(cudaEventSynchronize(end));CudaSafecCall(cudaEventElapsedTime(&gpuTime,start,end));CudaSafecCall(cudaEventDestroy(start));CudaSafecCall(cudaEventDestroy(end));CudaSafecCall(cudaMemcpy(hostA,deviceA,NBytes,cudaMemcpyDeviceToHost));printf("gpu_base 单流非锁页内存,数据传输和计算耗时 %f ms\n",gpuTime);CudaSafecCall(cudaFree(deviceA));free(hostA);return gpuTime;
}//单流主机锁页内存,异步传输
float gpu_base_pinMem()
{//开辟主机非锁页内存空间float* hostA,*deviceA;CudaSafecCall(cudaMallocHost((void**)&hostA,NBytes));CudaSafecCall(cudaMalloc((void**)&deviceA,NBytes));float gpuTime = 0.0;cudaEvent_t start,end;CudaSafecCall(cudaEventCreate(&start));CudaSafecCall(cudaEventCreate(&end));CudaSafecCall(cudaEventRecord(start));CudaSafecCall(cudaMemcpy(deviceA,hostA,NBytes,cudaMemcpyHostToDevice));kernel_func<<<(N-1)/BLOCKSIZE + 1,BLOCKSIZE>>>(deviceA,0,N);CudaCheckError();CudaSafecCall(cudaEventRecord(end));CudaSafecCall(cudaEventSynchronize(end));CudaSafecCall(cudaEventElapsedTime(&gpuTime,start,end));CudaSafecCall(cudaEventDestroy(start));CudaSafecCall(cudaEventDestroy(end));CudaSafecCall(cudaMemcpy(hostA,deviceA,NBytes,cudaMemcpyDeviceToHost));printf("gpu_base_pinMem 单流锁页内存,数据传输和计算耗时 %f ms\n",gpuTime);CudaSafecCall(cudaFreeHost(hostA));CudaSafecCall(cudaFree(deviceA));return gpuTime;
}//多流深度优先调度
float gpu_MStream_deep(int nStreams)
{//开辟主机非锁页内存空间float* hostA,*deviceA;//异步传输必须用锁页主机内存CudaSafecCall(cudaMallocHost((void**)&hostA,NBytes));CudaSafecCall(cudaMalloc((void**)&deviceA,NBytes));float gpuTime = 0.0;cudaEvent_t start,end;cudaStream_t* streams = (cudaStream_t*)calloc(nStreams,sizeof(cudaStream_t));for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamCreate(streams+i));CudaSafecCall(cudaEventCreate(&start));CudaSafecCall(cudaEventCreate(&end));CudaSafecCall(cudaEventRecord(start));//传输、计算,流间最多只有一个传输和一个计算同时进行// 每个流处理的数据量int nByStream = N/nStreams;for(int i=0;i<nStreams;i++){int offset = i * nByStream;CudaSafecCall(cudaMemcpyAsync(deviceA+offset,hostA+offset,nByStream*sizeof(float),cudaMemcpyHostToDevice,streams[i]));kernel_func<<<(nByStream-1)/BLOCKSIZE + 1,BLOCKSIZE,0,streams[i]>>>(deviceA,offset,(i+1)*nByStream);CudaCheckError();CudaSafecCall(cudaMemcpyAsync(hostA+offset,deviceA+offset,nByStream*sizeof(float),cudaMemcpyDeviceToHost,streams[i]));}for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamSynchronize(streams[i]));CudaSafecCall(cudaEventRecord(end));CudaSafecCall(cudaEventSynchronize(end));CudaSafecCall(cudaEventElapsedTime(&gpuTime,start,end));CudaSafecCall(cudaEventDestroy(start));CudaSafecCall(cudaEventDestroy(end));printf("gpu_MStream_deep %d个流深度优先调度,数据传输和计算耗时 %f ms\n",nStreams,gpuTime);for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamDestroy(streams[i]));CudaSafecCall(cudaFreeHost(hostA));CudaSafecCall(cudaFree(deviceA));free(streams);return gpuTime;
}//多流广度优先调度
float gpu_MStream_wide(int nStreams)
{//开辟主机非锁页内存空间float* hostA,*deviceA;//异步传输必须用锁页主机内存CudaSafecCall(cudaMallocHost((void**)&hostA,NBytes));CudaSafecCall(cudaMalloc((void**)&deviceA,NBytes));float gpuTime = 0.0;cudaEvent_t start,end;cudaStream_t* streams = (cudaStream_t*)calloc(nStreams,sizeof(cudaStream_t));for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamCreate(streams+i));CudaSafecCall(cudaEventCreate(&start));CudaSafecCall(cudaEventCreate(&end));CudaSafecCall(cudaEventRecord(start));//传输、计算,流间并行// 每个流处理的数据量int nByStream = N/nStreams;for(int i=0;i<nStreams;i++){int offset = i * nByStream;CudaSafecCall(cudaMemcpyAsync(deviceA+offset,hostA+offset,nByStream*sizeof(float),cudaMemcpyHostToDevice,streams[i]));}for(int i=0;i<nStreams;i++){int offset = i * nByStream;kernel_func<<<(nByStream-1)/BLOCKSIZE + 1,BLOCKSIZE,0,streams[i]>>>(deviceA,offset,(i+1)*nByStream);CudaCheckError();}for(int i=0;i<nStreams;i++){int offset = i * nByStream;CudaSafecCall(cudaMemcpyAsync(hostA+offset,deviceA+offset,nByStream*sizeof(float),cudaMemcpyDeviceToHost,streams[i]));}for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamSynchronize(streams[i]));CudaSafecCall(cudaEventRecord(end));CudaSafecCall(cudaEventSynchronize(end));CudaSafecCall(cudaEventElapsedTime(&gpuTime,start,end));CudaSafecCall(cudaEventDestroy(start));CudaSafecCall(cudaEventDestroy(end));printf("gpu_MStream_wide %d个流广度优先调度,数据传输和计算耗时 %f ms\n",nStreams,gpuTime);for(int i=0;i<nStreams;i++)CudaSafecCall(cudaStreamDestroy(streams[i]));CudaSafecCall(cudaFreeHost(hostA));CudaSafecCall(cudaFree(deviceA));free(streams);return gpuTime;
}int main(int argc,char* argv[])
{int nStreams = argc==2? atoi(argv[1]):4;//gpu默认单流,主机非锁页内存,同步传输float gpuTime1 = gpu_base();//gpu默认单流,主机锁页内存,异步传输float gpuTime2 = gpu_base_pinMem();//gpu多流深度优先调度,异步传输float gpuTime3 = gpu_MStream_deep(nStreams);//gpu多流广度优先调度,异步传输float gpuTime4 = gpu_MStream_wide(nStreams);printf("相比默认单流同步传输与计算,单流异步传输及运算加速比为 %f\n",nStreams,gpuTime1/gpuTime2);printf("相比默认单流同步传输与计算,%d 个流深度优先调度异步传输及运算加速比为 %f\n",nStreams,gpuTime1/gpuTime3);printf("相比默认单流同步传输与计算,%d 个流广度优先调度异步传输及运算加速比为 %f\n",nStreams,gpuTime1/gpuTime4);return 0;
}

3. 测试结果

各项测试耗时及与单流同步传输和计算加速比

项目\流数量 4 8 16 32 64
单流同步传输(耗时ms) 312.43 298.41 305.48 306.54 310.75
单流异步传输(耗时ms/加速比) 197.15/1.58 195.89/1.52 201.88/1.51 202.87/1.51 201.53/1.54
多流深度优先调度(耗时ms/加速比) 151.04/2.06 129.95/2.29 131.49/2.32 123.08/2.49 126.48/2.45
多流广度优先调度(耗时ms/加速比) 149.29/2.09 129.6/2.3 134.55/2.27 122.82/2.49 126.42/2.45

4. 结果分析

(1) 单流异步传输比同步传输明显效率更高,这是因为同步传输PCIE 通过 DMA 只能访问锁页内存,同步传输使用的主机内存地址是虚拟非锁页内存地址,相比异步传输同步传输额外增加了非锁页向锁页内存转换的开销;

(2) 多流的连个该测试中随着流数量的增加,加速比会提升;

(3) 多流广度优先相比深度优先调度在 228数据规模下效率几乎一致,可能因为数据规模较大,硬件资源紧张无法真正实现多流并发的优势。经多次测试,使用数据规模220,流2-8个时 ,广度优先的加速比能提升 2%左右,随着流数的增加广度优先效率反而不如深度优先。

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

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

相关文章

SwanLab最全使用教程:看这篇就够了

SwanLab是一个用于可视化和监控深度学习模型的工具。本文介绍了SwanLab的安装、启动和使用方法,并提供了参考链接。前言 机器学习通常涉及在训练期间可视化和度量模型的性能。 有许多工具可用于此任务。 在本文中,我们将重点介绍 SwanLab 开源工具,它可以服务于各种深度学习…

维修ABB IRB6700机器人的平衡缸3HAC043477出现异响

当ABB IRB6700机器人的平衡缸3HAC043477出现异响时,可能需要进行内部零件的检查和更换。以下是一些建议的步骤:1、检查IRB6700机械臂平衡缸的密封性:确保平衡缸的密封性良好,没有气体泄漏。如果发现有气体泄漏,可能需要更换密封件。2、检查活塞和缸体的磨损情况:如果活塞…

探索编程知识的宝库:www.readview.site 深度揭秘

在当今这个数字化浪潮汹涌澎湃的时代,编程技能已经如同基石一般,支撑着各行各业的创新与变革。无论是开发炫酷的手机应用、构建智能的物联网系统,还是投身于热门的大数据分析领域,扎实的编程功底都是迈向成功的关键一步。而在众多的学习资源中,www.readview.site 脱颖而出…

探索编程知识的宝库:[www.readview.site](http://www.readview.site) 深度揭秘

在当今这个数字化浪潮汹涌澎湃的时代,编程技能已经如同基石一般,支撑着各行各业的创新与变革。无论是开发炫酷的手机应用、构建智能的物联网系统,还是投身于热门的大数据分析领域,扎实的编程功底都是迈向成功的关键一步。而在众多的学习资源中,www.readview.site 脱颖而出…

Mysql连接报错排查解决记录

Mysql连接报错排查解决记录 背景:系统:uos server-1060e​ 运行环境kvm虚拟机​ mysql版本:5.7.44, for Linux (x86_64)问题现象: 宿主机重启后,kvm虚拟机内的mysql服务无法远程连接了。通过不同的客户端工具连接,报错现象分别如下: dbeaver-ce 工具连接报错: Can no…

CDS标准视图:维修工单工艺数据 I_MAINTORDEROPERATIONDATA

视图名称:维修工单工艺数据 I_MAINTORDEROPERATIONDATA 视图类型:基础 视图代码:点击查看代码 @EndUserText.label: Maintenance Order Operation Data @VDM.viewType: #COMPOSITE @AccessControl.authorizationCheck: #CHECK @AbapCatalog.sqlViewName: IPMORDOPERDATA @Cl…

关于const的使用

1、修饰整型变量const int a 就是声明了一种常量表示该变量的内容不可改变 2、对于修饰指针的const就有说法了 const int *a 和int* const a这是两种不同的用法 第一种: const int *a表示定义了一个指向const变量的指针,但是指针本身不是const类型,也就是说指针本身可以修改…

UOS系统mysql服务安装

UOS系统mysql服务安装 背景 1、安装环境:kvm虚拟机2、运行环境:uos server-1060e3、架构:x864、安装mysql版本:mysql-5.71、安装准备 # Mysql官网 https://downloads.mysql.com/archives/community/ # 下载安装包 wget -i -c http://dev.mysql.com/get/mysql57-community-…

使用Docker搭建npm私有仓库

由于文章格式和图片解析问题,为了更好的阅读体验,读者可前往 阅读原文在公司团队内一般都会拥有私有的工具包或者其他依赖,这些东西又是比较敏感的信息,因此如npm私库的搭建在公司内部必不可少。 私库搭建方式有很多,本篇通过docker+nexus3的进行搭建。 本人使用ARM架构Ce…

认识Token和Cookie

认识Token和Cookie 1、token和cookie有什么区别? ​ 1.1 存储位置及方式:Cookie是浏览器用来存储本地信息的文件,有一定的存储限制,而Token是由服务器按一定算法生成的密令,可以由前端指定存放到localStorage、sessionStorage或cookie中。 ​ 1.2 功能特性:每次浏览器…

开发微信小程序游戏,有没有类似Debug真机图形的方法

1)开发微信小程序游戏,有没有类似Debug真机图形的方法2)Unity中如何实现动态实时的车削效果3)动态创建的Texture,有什么办法可以让他保持ASTC么4)Unity转微信小游戏的日志问题这是第416篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术…