【CUDA】CUDA中缓存机制对计时的影响

笔者在阅读知乎上一个关于CUDA编程的专栏时,发现作者写的很多文章中都会附带计时的模块用于评估程序的运行效率,然而笔者发现,在运行这篇文章中的代码时时,得到的结果和作者的结果有较大差异,主要体现在:使用第三种thrust库的方法得到的结果比第二种使用共享内存的结果要差。
观察每次的运行时间,发现第三种方法首次运行的时间大约是后续运行时间的7倍,而第二种方法的每次运行时间基本一致,因此造成了结果的不一致,笔者将文中的代码进行修改,展示两个版本,其中version1是前20次的结果(即原文结果),version2是第1次到第21次的运行结果(即后20次的结果,不包括第一次),可以看到,此时第三种方法的结果比第二种方法的结果快,且三种方法的结果差距不大,那么可以说在计算层面,对该程序的优化提升不大,而在访存方面,thrust使用的方法效率要比共享内存低。

#include <stdio.h>
#include "error.cuh"
#include <thrust/scan.h>
#include <thrust/execution_policy.h>#ifdef USE_DPtypedef double real;
#elsetypedef float real;
#endifconst int N = 1000000;
const int M = sizeof(int) * N;
const int NUM_REAPEATS = 20;
const int BLOCK_SIZE = 1024;
const int GRID_SIZE = (N - 1) / BLOCK_SIZE + 1;__global__ void globalMemScan(real *d_x, real *d_y) {real *x = d_x + blockDim.x * blockIdx.x;const int n = blockDim.x * blockIdx.x + threadIdx.x;real y = 0.0;if (n < N) {for (int offset = 1; offset < blockDim.x; offset <<= 1) {if (threadIdx.x >= offset) y = x[threadIdx.x] + x[threadIdx.x - offset];__syncthreads();if (threadIdx.x >= offset) x[threadIdx.x] = y;}if (threadIdx.x == blockDim.x - 1) d_y[blockIdx.x] = x[threadIdx.x];} 
}__global__ void addBaseValue(real *d_x, real *d_y) {const int n = blockDim.x * blockIdx.x + threadIdx.x;real y = blockIdx.x > 0 ? d_y[blockIdx.x - 1] : 0.0;if (n < N) {d_x[n] += y;} 
}__global__ void sharedMemScan(real *d_x, real *d_y) {extern __shared__ real s_x[];const int n = blockDim.x * blockIdx.x + threadIdx.x;s_x[threadIdx.x] = n < N ? d_x[n] : 0.0;__syncthreads();real y = 0.0;if (n < N) {for (int offset = 1; offset < blockDim.x; offset <<= 1) {if (threadIdx.x >= offset) y = s_x[threadIdx.x] + s_x[threadIdx.x - offset];__syncthreads();if (threadIdx.x >= offset) s_x[threadIdx.x] = y;}d_x[n] = s_x[threadIdx.x];if (threadIdx.x == blockDim.x - 1) d_y[blockIdx.x] = s_x[threadIdx.x];} 
}void scan(real *d_x, real *d_y, real *d_z, const int method) {switch (method){case 0:globalMemScan<<<GRID_SIZE, BLOCK_SIZE>>>(d_x, d_y);globalMemScan<<<1, GRID_SIZE>>>(d_y, d_z);addBaseValue<<<GRID_SIZE, BLOCK_SIZE>>>(d_x, d_y);break;case 1:sharedMemScan<<<GRID_SIZE, BLOCK_SIZE, sizeof(real) * BLOCK_SIZE>>>(d_x, d_y);sharedMemScan<<<1, GRID_SIZE, sizeof(real) * GRID_SIZE>>>(d_y, d_z);addBaseValue<<<GRID_SIZE, BLOCK_SIZE>>>(d_x, d_y);break;case 2:thrust::inclusive_scan(thrust::device, d_x, d_x + N, d_x);break;default:break;}
}void timing(const real *h_x, real *d_x, real *d_y, real *d_z, real *h_ret, const int method) {float tSum = 0.0;float t2Sum = 0.0;float tSumVersion2 = 0.0;float t2SumVersion2 = 0.0;for (int i=0; i<=NUM_REAPEATS; ++i) {CHECK(cudaMemcpy(d_x, h_x, M, cudaMemcpyHostToDevice));cudaEvent_t start, stop;CHECK(cudaEventCreate(&start));CHECK(cudaEventCreate(&stop));CHECK(cudaEventRecord(start));cudaEventQuery(start);scan(d_x, d_y, d_z, method);CHECK(cudaEventRecord(stop));CHECK(cudaEventSynchronize(stop));float elapsedTime;CHECK(cudaEventElapsedTime(&elapsedTime, start, stop));if(i == 0) {// do nothing} else {tSumVersion2 += elapsedTime;t2SumVersion2 += elapsedTime * elapsedTime;}if(i == NUM_REAPEATS) {// do nothing} else {tSum += elapsedTime;t2Sum += elapsedTime * elapsedTime;}printf("%g\t", elapsedTime);CHECK(cudaEventDestroy(start));CHECK(cudaEventDestroy(stop));}printf("\n======version1======\n");printf("\n%g\t", tSum);float tAVG = tSum / NUM_REAPEATS;float tERR = sqrt(t2Sum / NUM_REAPEATS - tAVG * tAVG);printf("Time = %g +- %g ms.\n", tAVG, tERR);printf("\n======version2======\n");printf("\n%g\t", tSumVersion2);float tAVGVersion2 = tSumVersion2 / NUM_REAPEATS;float tERRVersion2 = sqrt(t2SumVersion2 / NUM_REAPEATS - tAVGVersion2 * tAVGVersion2);printf("Time = %g +- %g ms.\n", tAVGVersion2, tERRVersion2);CHECK(cudaMemcpy(h_ret, d_x, M, cudaMemcpyDeviceToHost));
}int main() {real *h_x = new real[N];real *h_y = new real[N];    real *h_ret = new real[N];for (int i=0; i<N; i++) h_x[i] = 1.23;real *d_x, *d_y, *d_z;CHECK(cudaMalloc((void **)&d_x, M));CHECK(cudaMalloc((void **)&d_y, sizeof(real) * GRID_SIZE));CHECK(cudaMalloc((void **)&d_z, sizeof(real)));printf("using global mem:\n");timing(h_x, d_x, d_y, d_z, h_ret, 0);for (int i = N - 10; i < N; i++) printf("%f  ", h_ret[i]);printf("\n");printf("using shared mem:\n");timing(h_x, d_x, d_y, d_z, h_ret, 1);for (int i = N - 10; i < N; i++) printf("%f  ", h_ret[i]);printf("\n");printf("using thrust lib:\n");timing(h_x, d_x, d_y, d_z, h_ret, 2);for (int i = N - 10; i < N; i++) printf("%f  ", h_ret[i]);printf("\n");CHECK(cudaFree(d_x));CHECK(cudaFree(d_y));CHECK(cudaFree(d_z));delete[] h_x;delete[] h_y;delete[] h_ret;
}

贴一张运行结果:
在这里插入图片描述
局部放大图:
在这里插入图片描述
可以看到,三种方法在计算层面基本上都稳定到0.03-0.04ms这个数量级。

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

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

相关文章

Python - Word转TXT文本,或TXT文本转Word

Word文档&#xff08;.doc或.docx&#xff09;和纯文本文件&#xff08;.txt&#xff09;是两种常用的文件格式。Word文档通常用于复杂的文档处理和排版&#xff0c;而纯文本文件则用于存储和传输纯文本信息。了解如何在这两种格式之间进行转换能提高工作效率&#xff0c;并便于…

Pytorch使用Dataset加载数据

1、前言&#xff1a; 在阅读之前&#xff0c;需要配置好对应pytorch版本。 对于一般学习&#xff0c;使用cpu版本的即可。参考教程点我 导入pytorch包&#xff0c;使用如下命令即可。 import torch # 注意虽然叫pytorch&#xff0c;但是在引用时是引用torch2、神经网络获取…

【UE5.3】笔记11

一、变量的SET&&GET 1、创建变量保存数据&#xff0c;如下图&#xff0c;找到左侧我的蓝图下的变量&#xff0c;新增一个&#xff0c;并选择类型。使用的时候直接将变量拖到蓝图中&#xff0c;此时会显示两个选项一个是获取一个是设置。 选择获取就是个GET蓝图&#x…

2024文件加密软件有哪些丨超好用的文件加密软件排行榜

文件加密软件在现代数字生活中扮演着至关重要的角色&#xff0c;尤其是在保护个人隐私、商业机密和敏感数据方面。 加密软件可以防止未经授权的访问和数据泄露。即使设备丢失或被盗&#xff0c;加密后的文件也不会轻易被破解&#xff0c;从而保护了数据的安全。 对于企业而言…

鸿蒙next 数据缓存 你不知道的事情

《鸿蒙next ArkUI专栏》系列前言: 作者:徐庆 团队:坚果派 公众号:“大前端之旅” 润开鸿生态技术专家,华为HDE,CSDN博客专家,CSDN超级个体,CSDN特邀嘉宾,InfoQ签约作者,OpenHarmony布道师,电子发烧友专家博客,51CTO博客专家,擅长HarmonyOS/OpenHarmony应用开发、熟…

计算机网络之因特网

1.因特网简介 1.1因特网的提出 1957年&#xff0c;苏联发射了人类第一颗人造地球卫星"Sputnik"。作为响应&#xff0c;美国国防部(DoD)组建了高级研究计划局(ARPA)&#xff0c;开始将科学技术应用于军事领域 。 1961年7月&#xff0c;MIT的Leonard Kleinrock…

Zabbix6.0监控Freeswitch状态

一、前提环境说明 1、最终实现Freeswitch监控指标信息&#xff1a; 2、环境需求&#xff1a; &#xff08;1&#xff09;需要使用Zabbix6.0及以上 &#xff08;2&#xff09;需要使用zabbix_agent2 二、实现步骤 1、zabbix_agent2添加监控键值 cat /etc/zabbix/conf.d/fr…

「豆包Marscode体验官」我用豆包Marscode画数据大屏

认识豆包Marscode 豆包 MarsCode IDE 是一个 AI 原生的云端集成开发环境&#xff08;IDE&#xff09;。内置的 AI 编程助手和开箱即用的开发环境让我们可以更加专注于各种项目的开发。豆包 MarsCode 编程助手&#xff0c;具备以智能代码补全为代表的 AI 功能。支持了多种编程语…

【Android面试八股文】请描述一下 android 的系统架构?

Android 是一个基于 Linux 的开源软件堆栈,针对多种不同设备类型打造。下图显示了 Android 平台的主要组件。 早期的Android架构如下图所示 官方网站最新的Android平台架构图,如下所示: Linux 内核 Android 平台的基础是 Linux 内核。例如,Android 运行时 (ART) 依赖…

【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验18 边界网关协议BGP

一、实验目的 1.验证边界网关协议BGP的作用&#xff1b; 2.学习在思科路由器上该协议的使用方法。 二、实验要求 1.使用Cisco Packet Tracer仿真平台&#xff1b; 2.观看B站湖科大教书匠仿真实验视频&#xff0c;完成对应实验。 三、实验内容 1.构建网络拓扑&#xff1b; …

全栈智能家居系统设计方案:STM32+Linux+多协议(MQTT、Zigbee、Z-Wave)通信+云平台集成

1. 项目概述 随着物联网技术的快速发展,智能家居系统正在成为现代生活中不可或缺的一部分。本文介绍了一个基于STM32微控制器和Linux系统的智能家居解决方案,涵盖了硬件设计、软件架构、通信协议以及云平台集成等方面。 该系统具有以下特点: 采用STM32作为终端设备的控制核心…

C#与PLC通信——如何设置电脑IP地址

前言&#xff1a; 我们与PLC通过以太网通信时&#xff0c;首先要做的就是先设置好电脑的IP&#xff0c;这样才能实现上位机电脑与PLC之间的通信&#xff0c;并且电脑的ip地址和PLC的Ip地址要同处于一个网段&#xff0c;比如电脑的Ip地址为192.168.1.1&#xff0c;那么PLC的Ip地…

Hadoop-20 Flume 采集数据双写至本地+HDFS中 监控目录变化 3个Agent MemoryChannel Source对比

章节内容 上一节完成了如下的内容&#xff1a; 编写Agent Conf配置文件收集Hive数据汇聚到HDFS中测试效果 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0…

【开源】开源数据库工具推荐

Mysql开源工具推荐 dbeaver下载网速太慢了&#xff0c;这么好用的开源工具&#xff0c;可以从镜像站中下载&#xff1a; 下载地址&#xff1a; https://mirrors.nju.edu.cn/github-release/dbeaver/dbeaver/24.1.1/ Redis开源工具推荐 好看好用&#xff0c;UI真是做的很不…

独立开发者系列(25)——大白话进程

很多小型的规模场景限制下&#xff0c;复杂概念弊端大于利端。不同模式的实现&#xff0c;是根据具体需求来判定&#xff0c;但是理解底层最基础的原理有助于理解很多工具背后的诞生。比如php的swoole workerman 要解决的问题。 首先理解&#xff0c;进程概念&#xff0c;进程…

【C语言】深入解析归并排序

文章目录 什么是归并排序&#xff1f;归并排序的基本实现代码解释归并排序的优化归并排序的性能分析归并排序的实际应用结论 在C语言编程中&#xff0c;归并排序是一种高效且稳定的排序算法。它采用分治法将问题分解成更小的子问题进行解决&#xff0c;然后合并结果。本文将详细…

Qt基础 | Qt Creator的基本介绍与使用 | 在Visual Studio中创建Qt项目

文章目录 一、Qt Creator的基本介绍与使用1.新建一个项目2.项目的文件组成3.项目文件介绍3.1 项目管理文件3.2 界面文件3.3 主函数文件3.4 窗体相关的文件 4.项目的编译、调试与运行 二、在Visual Studio中创建Qt项目 Qt C开发环境的安装&#xff0c;请参考https://liujie.blog…

maven私有镜像仓库nexus部署使用

maven私有镜像仓库nexus部署使用 1、Nexus部署 #查找镜像 docker search sonatype/nexus3 #拉取镜像 docker pull sonatype/nexus3 #持久化目录 mkdir -p /data/nexus/data chmod 777 -R /data/nexus/data #启动服务 docker run -d --name nexus3 -p 8081:8081 --restart alw…

MyBatis where标签内嵌foreach标签查询报错‘缺失右括号‘或‘命令未正确结束‘

MyBatis <where>标签内嵌<foreach>标签查询报错’缺失右括号’或’命令未正确结束’ <where>标签内嵌<foreach>标签 截取一段脱敏xml&#xff0c;写明大概意思 <select id"queryLogByIds" resultMap"BaseResultMap">SELE…

深度学习基础:Numpy 数组包

数组基础 在使用导入 Numpy 时&#xff0c;通常给其一个别名 “np”&#xff0c;即 import numpy as np 。 数据类型 整数类型数组与浮点类型数组 为了克服列表的缺点&#xff0c;一个 Numpy 数组只容纳一种数据类型&#xff0c;以节约内存。为方便起见&#xff0c;可将 Nu…