【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.rhkb.cn/news/377190.html

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

相关文章

前端调试技巧(npm Link,vscode调试,浏览器调试等)

Npm Link 功能&#xff1a; 在本地开发npm模块的时候&#xff0c;我们可以使用npm link命令&#xff0c;将npm 模块链接到对应的运行项目中去&#xff0c;方便地对模块进行调试和测试 断点调试 vscode调试 Debug Vue2 Project 目标&#xff1a;在VSCode中调试项目代码…

巧用 VScode 网页版 IDE 搭建个人笔记知识库!

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] 巧用 VScode 网页版 IDE 搭建个人笔记知识库! 描述&#xff1a;最近自己在腾讯云轻量云服务器中部署了一个使用在线 VScode 搭建部署的个人Markdown在线笔记&#xff0c;考虑到在线 VScode 支持终…

[K8S]一、Flink on K8S

Kubernetes | Apache Flink 先编辑好这5个配置文件&#xff0c;然后再直接执行 kubectl create -f ./ kubectl get all kubectl get nodes kubectl get pods kubectl get pod -o wide kubectl get cm -- 获取所有的configmap 配置文件 kubectl logs pod_name -- 查看…

智能汽车域控制器FOTA升级方案探讨

1.概述 本文探讨的OTA升级仅针对运行linux系统的域控制器&#xff0c;升级方式为FOTA&#xff0c;探究升级文件从OTA服务器下载到域控中以后&#xff0c;如何将升级文件安装到存储系统。 为安全起见&#xff0c;支持FOTA升级的存储区域必须支持AB分区设计&#xff0c;每个分区…

浅学三次握手

数据要完成传输&#xff0c;必须要建立连接。由于建立TCP连接的过程需要来回3次&#xff0c;所以&#xff0c;将这个过程形象的叫做三次握手。 结合上面的图来看更清楚。 先说三次握手吧&#xff0c;连接是后续数据传输的基础。就像我们打电话一样&#xff0c;必须保证我和对方…

c++习题10-骑士得到的金币数

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 二&#xff0c;思路 阅读题目之后可以列出如下的数字&#x1f447; 观察上图有如下思路&#xff08;主要是找到规律&#xff09; 给个for循环包裹住需要处理的语句&#xff0c;循环…

k8s快速部署一个网站

1&#xff09;使用Deployment控制器部署镜像&#xff1a; kubectl create deployment web-demo --imagelizhenliang/web-demo:v1 kubectl get deployment,pods[rootk8s-matser ~]# kubectl get pods NAME READY STATUS RESTARTS A…

The Web3 社区 Web3 产品经理课程

概述 / 深耕区块链行业 11 年&#xff0c;和很多产品经理都打过交道&#xff1b;遇到过优秀的产品经理&#xff0c;也遇到过比较拉垮的产品经理。多年工作中&#xff0c;曾在某些团队&#xff0c;承载技术兼产品经理的角色&#xff1b;也参与过很多 Web3 外包项目&#xff0c;包…

【研路导航】成功保研面试:避免迷惑发言,掌握关键表达技巧

更多保研&#xff0c;夏令营&#xff0c;预推免与信息时间节点资讯可以在文章末尾领取&#xff01; 写在前面 在保研面试的过程中&#xff0c;准备充分是成功的关键。每年的夏令营都是竞争激烈的时刻&#xff0c;而如何在面试中展现出最佳的自我&#xff0c;不仅是一场考验&a…

java实战项目-学生管理系统(附带全套源代码及其登录注册功能的实现)--《进阶篇》

一、前言 新增了登录注册的功能&#xff0c;代码量可能会有点大&#xff0c;所有代码加起来差不多560行。这个项目对于小白来说肯定是一大难关了。文章中的每张图都是作者亲手绘制的&#xff0c;简单明了&#xff0c;如果大家认同作者&#xff0c;希望可以支持一下作者。全套源…

elasticsearch 查询超10000的解决方案

前言 默认情况下&#xff0c;Elasticsearch集群中每个分片的搜索结果数量限制为10000。这是为了避免潜在的性能问题。 但是我们 在实际工作过程中时常会遇到 需要深度分页&#xff0c;以及查询批量数据更新的情况 问题&#xff1a;当请求form size >10000 时&#xff0c…

【从0到1进阶Redis】主从复制 — 主从机宕机测试

上一篇&#xff1a;【从0到1进阶Redis】主从复制 测试&#xff1a;主机断开连接&#xff0c;从机依旧连接到主机的&#xff0c;但是没有写操作&#xff0c;这个时候&#xff0c;主机如果回来了&#xff0c;从机依旧可以直接获取到主机写的信息。 如果是使用命令行&#xff0c;来…

制作显卡版docker并配置TensorTR环境

感谢阅读 相关概念docker准备下载一个自己电脑cuda匹配的docker镜像拉取以及启动镜像安装cudaTensorRT部署教程 相关概念 TensorRT是可以在NVIDIA各种GPU硬件平台下运行的一个模型推理框架&#xff0c;支持C和Python推理。即我们利用Pytorch&#xff0c;Tensorflow或者其它框架…

电影购票小程序论文(设计)开题报告

一、课题的背景和意义 随着互联网技术的不断发展&#xff0c;人们对于购票的需求也越来越高。传统的购票方式存在着排队时间长、购票流程繁琐等问题&#xff0c;而网上购票则能够有效地解决这些问题。电影购票小程序是网上购票的一种新型应用&#xff0c;它能够让用户随时随地…

Vulnhub靶场DC-3-2练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. joomla漏洞查找2. SQL注入漏洞3. 破解hash4. 上传一句话木马5. 蚁剑连接shell6. 反弹shell7. 提权 0x04 总结 0x00 准备 下载链接&#xff1a;https://download.vulnhub.com/dc/DC-3-2.zip 介绍&#…

自适应大气简约健康实木地板生产企业网站模板源码 带完整的安装代码包以及搭建教程

系统概述 在当今数字化时代&#xff0c;企业的在线形象直接关联到其市场竞争力。对于专注于生产高品质、健康环保实木地板的企业而言&#xff0c;一个专业、大气且能完美展示产品特色的官方网站尤为重要。为了满足这一需求&#xff0c;我们精心打造了一款“自适应大气简约健康…

Chromium CI/CD 之Jenkins实用指南2024-如何创建新节点(三)

1. 前言 在前一篇《Jenkins实用指南2024-系统基本配置&#xff08;二&#xff09;》中&#xff0c;我们详细介绍了如何对Jenkins进行基本配置&#xff0c;包括系统设置、安全配置、插件管理以及创建第一个Job。通过这些配置&#xff0c;您的Jenkins环境已经具备了基本的功能和…

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…

HTTP背后的故事:理解现代网络如何工作的关键(一)

一.HTTP是什么 概念 &#xff1a; 1.HTTP ( 全称为 " 超文本传输协议 ") 是一种应用非常广泛的 应用层协议。 2.HTTP 诞生与1991年. 目前已经发展为最主流使用的一种应用层协议. 3.HTTP 往往是基于传输层的 TCP 协议实现的 . (HTTP1.0, HTTP1.1, HTTP2.0 均为 T…

使用 HttpServlet 接收网页的 post/get 请求

前期工作&#xff1a;部署好 idea 和 一个 web 项目 idea(2021),tomcat(9) ->创建一个空的项目 -> 新建一个空的模块 -> 右键单击模块 选择 Add..Fra.. Sup.. -> 勾选Web App...后点击OK -> 点击 file - Project Struc... -> 选择刚刚的模块 -> 点…