CPU/GPU实现向量内积

向量内积(点乘/点积/数量积):两个向量对应元素相乘之后求和:

CPU实现: 

//cpu 实现一下向量内积#include<stdio.h>
template<typedef T>
void dot_mul(T *a, T *b, T *c, int n)
{   double tmp = 0;for(int i = 0; i < n; i++){tmp += a[i] * b[i];}*c = tmp;
}int main()
{//定义数组以及数组的大小float a[N], b[N];float c = 0;for(int i = 0; i < N; ++i){a[i] = i * 1.0;b[i] = 1.0}dot_cpu(a, b, &c, N);printf("a dot b output %f\n", c);printf("Hello World!\n");

首次接触bank conflict的概念,在这里补充一下。

bank是shared memory中用来存储数据的特殊组织方式。为了高效存取输入shared memory分为32个存储体(bank), 对应32个线程。每个bank有一个固定的带宽,可以同时服务一个线程的访问。当多个线程在一个时钟周期内访问一个bank的不同地址时,会产生bank conflict。因为bank的读取带宽不能高效的同时服务多个线程,因此需要需要解决bank conflict。有个不解的地方,是什么导致所有的thread都去访问同一个bank?

了解一个bank的属性:bank的宽度是指bank存储器的位宽。位宽是存储器连接的总线一次可以传数的数据量,可以是32bit,也可以是64bit,取决于总线的位数。可以是4字节/8字节。

避免bank conflict的方法有以下几种:

  • 使用不同的bank size,可以通过cudaDeviceSetSharedMemConfig函数来设置bank size为4字节或8字节,这样可以改变shared memory到bank的映射方式,减少冲突的可能性。
  • 使用memory padding,即在shared memory的数组中增加一些空白的元素,使得不同的线程访问不同的bank,从而避免冲突。
  • 使用不同的访问模式,比如使用转置或者重排的方式,使得一个warp中的线程访问不同的bank或者同一个地址,从而避免冲突。

回归正题,用cuda实现向量的内积(点积/点乘/数量积)。

单block分散归约法

 

第一次理解单block分散归约 takes 3 hours!

第一次手撸整理单block分散归约代码 takes one and a half hours!

main 函数 takes half an hour !

以下是我学习整理后的kernel函数:

#include "cuda_runtime.h"
#include "stdio.h"#define threadnums 32
#define N 2048//单block分散归约法
template <typedef T>
__global__ dotmul_gpu_1(T *a, T *b, T *c, int N)
{const int nThreadIdx = threadIdx.x;//当前线程ID索引const int nBlockDimX = blockDim.x;//一个block内开启的线程总数int nTid = nTreadIdx;dobule dTmp = 0.0;//开辟shared memory,大小与线程数量一致__shared__ T tmp[nBlockDimX];//step 1://每个线程负责 N/nBlockDimX 个元素相乘后的累加 while(nTid < N){dTmp += a[nTid] * b[nTid];nTid += nBlockDimX;}//每个线程将以上计算结果放入共享内存中tmp[nThreadIdx] = dTmp;//同步线程,等待所有线程完成以上计算__syncthreads();//step2:归约reductionint i = 2;int j = 1;while(i <= nBlockDimX){if(nThreadIdx / i == 0){//所有线程完成一次求和归约计算dTmp = tmp[nThreadIdx] + tmp[nThreadIdx + j];tmp[nThreadIdx] = dTmp;}__syncthreads();//这个地方利用i和j进行索引比较巧妙//32个线程进行求和归约,每次归约,线程索引的元素下标如下://第一次归约:0+1, 2+3, 4+5, 6+7, 8+9, 10+11, 12+13,14+15, 16+17, 18+19, 20+21, 22+23, 24+25, 26+27, 28+29, 30+31//第二次归约:0+2, 4+6, 8+10, 12+14, 16+18, 20+22, 24+26, 28+30 //第三次归约:0+4, 8+12, 16+20, 24+28//第四次归约:0+8, 16+24//第五次归约:0+16//求和归约值:0i *= 2;j *= 2;}//此处只在一个线程中获取向量内积值,因此需要线程ID判断if(0 == nTreadIdx)*c = tmp[0];
}

 主函数整理如下:

int main()
{float a[N], b[N];//对向量a[], b[]初始化值for(int i = 0; i < N; i++){a[i] = 1.0;b[i] = i * 1.0;}float *d_a=NULL, *d_b=NULL, *d_c=NULL;//将数组a[]的数据从CPU拷贝到GPUcudaMalloc(&d_a, N*sizeof(float));cudaMemcpyAsync(d_a, a, N*sizeof(float), cudaMemcpyHostToDevice);//将数组b[]的数据从CPU拷贝到GPUcudaMalloc(&d_b, N*sizeof(float));cudaMemcpyAsync(d_b, b, N*sizeof(float), cudaMemcpyHostToDevice);//不要忘记了结果也需要存储在显存上!cudaMalloc(&d_c, sizeof(float));//调用kernel函数dim3 blocks(1,0,0);dim3 threadPerBlock(threadnums, 0, 0);dotmul_gpu_1<<<blocks, threadPerBlock>>>(d_a, d_b, d_c, N);//分配的显存需要手动释放cudaFree(d_a);cudaFree(d_b);cudaFree(d_c);return 0;
}

 参考链接:

CUDA学习(十):向量内积的多种方法实现_为向量类增加计算内积的功能。-CSDN博客

拯救你的CUDA!什么是bank,为什么会发生bank conflict???_哔哩哔哩_bilibili

 该方法存在的问题在参考文章中被指出有违背访问对其原则、容易产生bank conflict。后面再一一学习补充。

此外,解决cuda上向量内积的方法还有,留待后续学习补充:

单Block低线程归约向量内积

多block向量内积

cublas库实现向量内积

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

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

相关文章

深度学习人脸表情识别算法 - opencv python 机器视觉 计算机竞赛

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人脸表情识别系…

clickhouse 业务日志告警

一、需求 对入库到clickhouse的业务日志进行告警&#xff0c;达阀值后发送企业微信告警。 方法一、 fluent-bit–>clickhouse(http)<–shell脚本,每隔一分钟获取分析结果 --> 把结果保存到/dev/shm/目录下 <-- node_exporter读取指标入库到prometheus<-- rules…

装备中国功勋企业——兰石重装,建设LTC全流程管理|基于得帆云低代码的CRM案例系列

兰石重型装备股份有限公司 兰石重型装备股份有限公司&#xff08;以下简称“兰石重装”&#xff09;成立于2001年&#xff0c;经营范围为炼油、化工、核电等能源领域所需的装备的设计、制造、安装、成套与服务&#xff1b;工程项目建设与服务&#xff1b;机械加工&#xff1b;检…

用css实现原生form中radio单选框和input的hover已经focus的样式

一.问题描述&#xff1a;用css实现原生form中radio单选框和input的hover已经focus的样式 在实际的开发中&#xff0c;一般公司ui都会给效果图&#xff0c;比如单选按钮radio样式&#xff0c;input输入框hover的时候样式&#xff0c;以及focus的时候样式&#xff0c;等等&#…

vue动态配置路由

文章目录 前言定义项目页面格式一、vite 配置动态路由新建 /router/utils.ts引入 /router/utils.ts 二、webpack 配置动态路由总结如有启发&#xff0c;可点赞收藏哟~ 前言 项目中动态配置路由可以减少路由配置时间&#xff0c;并可减少配置路由出现的一些奇奇怪怪的问题 路由…

C语言-求一个整数储存在内存中的二进制中1的个数

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>int main() {/*求一个整数储存在内存中的二进制中1的个数*/int number;scanf("%d", &number);int i 0;int count 0;for (i 0; i < 32; i){if (1 ((number >> i) & 1)){count;}}printf(…

buildadmin+tp8表格操作(7.1)表格的事件监听(el-table中的事件)

因为buildAdmin是封装的 el-table的组件&#xff0c;所以el-table中的事件&#xff0c; 也是可以使用的&#xff0c; 两者有几个事件是有共同的&#xff08;比如 双击事件&#xff09;&#xff0c; 这时可以根据自己的需要自行选择 以下代码是 buildadmin 使用 el-table中的事…

记录一次较为完整的Jenkins发布流程

文章目录 1. Jenkins安装1.1 Jenkins Docker安装1.2 Jenkins apt-get install安装 2. 关联github/gitee服务与webhook2.1 配置ssh2.2 Jenkins关联2.3 WebHook 3. 前后端关联发布 1. Jenkins安装 1.1 Jenkins Docker安装 Docker很好&#xff0c;但是我没有玩明白如何使用Docke…

通达信的ebk文件

我们在通达信软件中 调出 “自定义板块设置” 这个菜单&#xff0c;点击“导出”&#xff0c;会提示你存储 “自选股.EBK”&#xff0c;其实就是对自定义板块里的目录进行备份的一种方式&#xff0c; 当我们打开 这个文件&#xff0c;你会发现其实就是存储了 股票代码&#xff…

电脑监控软件都有哪些,哪款好用丨全网盘点

电脑监控软件是一种用于监视和控制计算机的软件工具&#xff0c;可以帮助企业和个人了解计算机的使用情况&#xff0c;保护数据安全&#xff0c;提高工作效率等。 电脑监控软件都有哪些&#xff1a; 1、域之盾软件 这是一款功能强大的电脑监控软件&#xff0c;可以实时监控电脑…

极速进化,融合“新“生 | StarRocks Summit 2023 技术交流峰会圆满落幕

2023年11月17日&#xff0c;由 StarRocks 社区发起、镜舟科技主办的 StarRocks 年度大型技术交流峰会 StarRocks Summit 2023 在上海成功举行。 本次峰会以「极速进化&#xff0c;融合"新"生」为主题&#xff0c;40余场分享演讲在全天密集开展&#xff0c;来自平安银…

C++ DAY03 类与对象

概述 对象&#xff1a;真实存在的事物 类&#xff1a; 多个对象抽取其共同点形成的概念 静态特征提取出的概念称为成员变量, 又名属性 动态特征提取出的概念称为成员函数, 又名方法 类与对象的关系 在代码中先有类后有对象 一个类可以有多个对象 多个对象可以属于同一个…