cuda reductionreduce

cuda reduction&reduce

概念

reduction

是一种并行计算中的操作概念或技术,指的是将一组数据通过某种特定的操作(如加法、乘法、求最大值、求最小值等)进行聚合,最终得到一个或几个汇总结果的过程。它强调的是这种数据处理的模式或任务类型,是一个较为宽泛的概念,在各种并行计算场景和框架中都可能存在。

reduce

通常是指 CUDA 中实现 reduction 操作的具体函数或方法。在 CUDA 的编程接口中,“reduce” 是用于执行归约操作的具体函数名或函数模板,是实现 “reduction” 概念的具体工具,是一个具体的编程元素。

代码1-初始

假设处理N个元素,划分M个block,然后每个线程处理一个元素,每个block一共M个thread

__global__ void reduce0(float *d_in,float *d_out){__shared__ float sdata[THREAD_PER_BLOCK];//申请共享内存,大小存放的是一个block里的thread数量//each thread loads one element from global memory to shared memunsigned int i=blockIdx.x*blockDim.x+threadIdx.x;//当前线程要索引的数据对应全局数组位置unsigned int tid=threadIdx.x;//当前线程在block里面的位置sdata[tid]=d_in[i];//这个过程是global到share__syncthreads();//同步,因为有依赖关系// do reduction in shared mem ,这里就是简单的二分合并,share对于一个block的所有线程可见,所以可以这样在share上合并去做。for(unsigned int s=1; s<blockDim.x; s*=2){if(tid%(2*s) == 0){sdata[tid]+=sdata[tid+s];}__syncthreads();//计算有依赖所以同步}// write result for this block to global memif(tid==0)d_out[blockIdx.x]=sdata[tid];//最后合并的值放在数组的最开始
}

假设32M数据,每个thread处理一个数据,一个block256个thread,
1M=1024K,所以一共32*1024/256=128个block

代码2-减少warp内分支

对于cuda来说,假设代码存在分支AB,因为是simt,所以会先执行A,再执行B,而不是并行执行AB,所以对于代码1的优化先是减少分支

__global__ void reduce1(float *d_in,float *d_out){__shared__ float sdata[THREAD_PER_BLOCK];//each thread loads one element from global memory to shared memunsigned int i=blockIdx.x*blockDim.x+threadIdx.x;unsigned int tid=threadIdx.x;sdata[tid]=d_in[i];__syncthreads();// do reduction in shared memfor(unsigned int s=1; s<blockDim.x; s*=2){int index = 2*s*tid;if(index < blockDim.x){sdata[index]+=sdata[index+s];}__syncthreads();}// write result for this block to global memif(tid==0)d_out[blockIdx.x]=sdata[tid];
}

这里的思路是256个数据有八个warp,为了不让warp出现较少分支,比如第一个循环,只让warp0~3的线程去做累加计算,4·7的warp执行另外一个分支,这样虽然空转的线程数没有减少,但是warp内没有分支,性能提升。

代码3-减少bank冲突

__global__ void reduce2(float *d_in,float *d_out){__shared__ float sdata[THREAD_PER_BLOCK];//each thread loads one element from global memory to shared memunsigned int i=blockIdx.x*blockDim.x+threadIdx.x;unsigned int tid=threadIdx.x;sdata[tid]=d_in[i];__syncthreads();// do reduction in shared memfor(unsigned int s=blockDim.x/2; s>0; s>>=1){if(tid < s){sdata[tid]+=sdata[tid+s];}__syncthreads();}// write result for this block to global memif(tid==0)d_out[blockIdx.x]=sdata[tid];
}

需要以warp为单位去避免bank

当朴素的将数据搬运到share的时候,一个数据占一个bank,那么第一轮循环中,code2的thread0占用为了索取01数据占据01bank,thread16为了索引数据3233也占据了bank01,这两个thread此时就发生了两路bank冲突。
如果不改变数据存放的方式,就需要改变索引。
对于朴素存放,数据在share中如下
0 ~ 31
32 ~ 63
64 ~ 95
96 ~127
128~159
160~191
192~223
224~255

第一轮循环:
对于修改代码,第一轮循环thread索引0和128,而这两个元素都在bank0上,对于底层代码来说,这部分计算设计两个load,第一个load,warp0的每个线程都去load0~31,这里不会冲突,并且底层会优化为128bit的大load。第二个load同理,只不过换了不同行。
第一个循环将128-255的值加到了0-128位置上
第二轮循环:
thead0 : 0+64:同理,也是不同行
第三轮循环:
thread 0:0+32:同理
第四轮循环
thread 0:0+16,但此时因为tid<16才计算,所以也没有冲突
第五轮循环
0+8

0+4

0+2

0+1
得到结果存在0

标准写法

#include <iostream>
#include <cuda_runtime.h>// CUDA 内核函数:规约加法
__global__ void reductionAdd(float *input, float *output, int n) {__shared__ float partialSum[256];// 线程索引int tid = threadIdx.x;int idx = blockIdx.x * blockDim.x + threadIdx.x;// 加载数据到共享内存partialSum[tid] = (idx < n) ? input[idx] : 0.0f;__syncthreads();// 规约操作for (int s = blockDim.x / 2; s > 0; s >>= 1) {if (tid < s) {partialSum[tid] += partialSum[tid + s];}__syncthreads();}// 将每个块的部分和写入全局内存if (tid == 0) {output[blockIdx.x] = partialSum[0];}
}// 主机端函数:计算最终结果
float finalSum(float *output, int numBlocks) {float sum = 0.0f;for (int i = 0; i < numBlocks; i++) {sum += output[i];}return sum;
}int main() {const int n = 1024;float *h_input = new float[n];float *d_input, *d_output;// 初始化输入数据for (int i = 0; i < n; i++) {h_input[i] = static_cast<float>(i + 1);}// 分配设备内存cudaMalloc((void**)&d_input, n * sizeof(float));cudaMalloc((void**)&d_output, (n / 256) * sizeof(float));// 将数据从主机复制到设备cudaMemcpy(d_input, h_input, n * sizeof(float), cudaMemcpyHostToDevice);// 定义线程块和网格的维度dim3 blockSize(256);dim3 gridSize((n + blockSize.x - 1) / blockSize.x);// 调用 CUDA 内核函数reductionAdd<<<gridSize, blockSize>>>(d_input, d_output, n);// 同步设备cudaDeviceSynchronize();// 将部分和从设备复制到主机float *h_output = new float[gridSize.x];cudaMemcpy(h_output, d_output, gridSize.x * sizeof(float), cudaMemcpyDeviceToHost);// 计算最终结果float result = finalSum(h_output, gridSize.x);// 输出结果std::cout << "The sum of the array is: " << result << std::endl;// 释放内存delete[] h_input;delete[] h_output;cudaFree(d_input);cudaFree(d_output);return 0;
}

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

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

相关文章

HTB:Support[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用ldapsearch…

洛谷P1017 [NOIP2000 提高组] 进制转换

题目链接&#xff1a;P1017 [NOIP2000 提高组] 进制转换 - 洛谷 | 计算机科学教育新生态 题目难度&#xff1a;普及一 题目分析&#xff1a;这是道数学题&#xff0c;我们都知道&#xff0c;首先按照10进制转成n进制的做法&#xff1a;对这个数不断除以n&#xff0c;将余数一一…

php代码审计2 piwigo CMS in_array()函数漏洞

php代码审计2 piwigo CMS in_array()函数漏洞 一、目的 本次学习目的是了解in_array()函数和对项目piwigo中关于in_array()函数存在漏洞的一个审计并利用漏洞获得管理员帐号。 二、in_array函数学习 in_array() 函数搜索数组中是否存在指定的值。 in_array($search,$array…

【2024年华为OD机试】(A卷,200分)- 查找树中元素 (JavaScriptJava PythonC/C++)

一、问题描述 题目解析 题目描述 题目要求根据输入的坐标 (x, y) 在树形结构中找到对应节点的内容值。其中: x 表示节点所在的层数,根节点位于第0层,根节点的子节点位于第1层,依此类推。y 表示节点在该层内的相对偏移,从左至右,第一个节点偏移为0,第二个节点偏移为1,…

WPS数据分析000006

一、排序 开始→ 排序 同文件→选项→自定义序列→输入序列 二、筛选 高级筛选 条件区域要与列表区域一样。 三、条件格式

基于微信小程序的英语学习交流平台设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

记录一个连不上docker中的mysql的问题

引言 使用的debian12,不同发行版可能有些许差异&#xff0c;连接使用的工具是navicat lite 本来是毫无思绪的&#xff0c;以前在云服务器上可能是防火墙的问题&#xff0c;但是这个桌面环境我压根没有使用防火墙。 直到 ying192:~$ mysql -h127.0.0.1 -uroot ERROR 1045 (28…

SpringBoot基础概念介绍-数据源与数据库连接池

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 毛毛张今天介绍的SpringBoot中的基础概念-数据源与数据库连接池&#xff0c;同时介绍SpringBoot整合两种连接池的教程 文章目录 1 数据库与数据库管理系统2 JDBC与数…

深度学习 Pytorch 单层神经网络

神经网络是模仿人类大脑结构所构建的算法&#xff0c;在人脑里&#xff0c;我们有轴突连接神经元&#xff0c;在算法中&#xff0c;我们用圆表示神经元&#xff0c;用线表示神经元之间的连接&#xff0c;数据从神经网络的左侧输入&#xff0c;让神经元处理之后&#xff0c;从右…

GCC之编译(8)AR打包命令

GCC之(8)AR二进制打包命令 Author: Once Day Date: 2025年1月23日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-C…

SpringBoot统一功能处理

一.拦截器 1.拦截器的简单介绍 拦截器是Spring框架提供的核⼼功能之⼀,主要⽤来拦截⽤⼾的请求,在指定⽅法前后,根据业务需要执⾏预先设定的代码. 2.使用 (i).定义拦截器&#xff1a; (ii).注册拦截器 (iii).拦截路径 (iv).实行流程 3.登录校验 4.DispatcherServlet源码&…

31、Java集合概述

目录 一.Collection 二.Map 三.Collection和Map的区别 四.应用场景 集合是一组对象的集合&#xff0c;它封装了对象的存储和操作方式。集合框架提供了一组接口和类&#xff0c;用于存储、访问和操作这些对象集合。这些接口和类定义了不同的数据结构&#xff0c;如列表、集合…

Unity|小游戏复刻|见缝插针1(C#)

准备 创建Scenes场景&#xff0c;Scripts脚本&#xff0c;Prefabs预制体文件夹 修改背景颜色 选中Main Camera 找到背景 选择颜色&#xff0c;一种白中透黄的颜色 创建小球 将文件夹里的Circle拖入层级里 选中Circle&#xff0c;位置为左右居中&#xff0c;偏上&…

Word 中实现方框内点击自动打 √ ☑

注&#xff1a; 本文为 “Word 中方框内点击打 √ ☑ / 打 ☒” 相关文章合辑。 对第一篇增加了打叉部分&#xff0c;第二篇为第一篇中方法 5 “控件” 实现的详解。 在 Word 方框内打 √ 的 6 种技巧 2020-03-09 12:38 使用 Word 制作一些调查表、检查表等&#xff0c;通常…

Android Studio:视图绑定的岁月变迁(2/100)

一、博文导读 本文是基于Android Studio真实项目&#xff0c;通过解析源码了解真实应用场景&#xff0c;写文的视角和读者是同步的&#xff0c;想到看到写到&#xff0c;没有上帝视角。 前期回顾&#xff0c;本文是第二期。 private Unbinder mUnbinder; 只是声明了一个 接口…

第13章 深入volatile关键字(Java高并发编程详解:多线程与系统设计)

1.并发编程的三个重要特性 并发编程有三个至关重要的特性&#xff0c;分别是原子性、有序性和可见性 1.1 原子性 所谓原子性是指在一次的操作或者多次操作中&#xff0c;要么所有的操作全部都得到了执行并 且不会受到任何因素的干扰而中断&#xff0c;要么所有的操作都不执行…

算法中的移动窗帘——C++滑动窗口算法详解

1. 滑动窗口简介 滑动窗口是一种在算法中常用的技巧&#xff0c;主要用来处理具有连续性的子数组或子序列问题。通过滑动窗口&#xff0c;可以在一维数组或字符串上维护一个固定或可变长度的窗口&#xff0c;逐步移动窗口&#xff0c;避免重复计算&#xff0c;从而提升效率。常…

基于SpringBoot的网上考试系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【java数据结构】map和set

【java数据结构】map和set 一、Map和Set的概念以及背景1.1 概念1.2 背景1.3 模型 二、Map2.1 Map说明2.2 Map的常用方法 三、Set3.1 Set说明3.2 Set的常用方法 四、Set和Map的关系 博客最后附有整篇博客的全部代码&#xff01;&#xff01;&#xff01; 一、Map和Set的概念以及…

基于迁移学习的ResNet50模型实现石榴病害数据集多分类图片预测

完整源码项目包获取→点击文章末尾名片&#xff01; 番石榴病害数据集 背景描述 番石榴 &#xff08;Psidium guajava&#xff09; 是南亚的主要作物&#xff0c;尤其是在孟加拉国。它富含维生素 C 和纤维&#xff0c;支持区域经济和营养。不幸的是&#xff0c;番石榴生产受到降…