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:归约reduction
    int 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
        //求和归约值:0
        i *= 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拷贝到GPU
     cudaMalloc(&d_a, N*sizeof(float));
     cudaMemcpyAsync(d_a, a, N*sizeof(float), cudaMemcpyHostToDevice);
    //将数组b[]的数据从CPU拷贝到GPU
     cudaMalloc(&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库实现向量内积

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WiseGiga NAS远程命令执行漏洞复现 [附POC]

文章目录 WiseGiga NAS RCE漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 WiseGiga NAS RCE漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff…

【latex】公式推导等号对齐

使用aligned进行多行公式对齐&#xff0c;&作为对齐的节点&#xff0c;\作为公式换行 \begin{equation} \begin{aligned}a& bc \\& cd \end{aligned} \end{equation}

不懂找伦敦银趋势?3个方法搞定

趋势是我们的朋友&#xff0c;但是这个朋友却很喜欢跟我们开玩笑&#xff0c;如果我们不留意&#xff0c;根本发觉不了它的存在。怎么找到趋势本体并且和它做个好朋友呢&#xff1f;下面我们就来介绍三个方法。 数波段的高点和低点。我们以当前的市场波动价格为轴&#xff0c;向…

Vue项目中如何获取浏览器唯一标识Fingerprint2-浏览器指纹获取-demo

Fingerprint "fingerprintjs2": "^2.1.4", <template><n-card :segmented"{content: true,footer:true}" footer-style"padding:10px"><template #header>通过设备浏览器信息获取浏览器指纹的插件(官方宣称其识别精…

JavaScript 字符处理

1.删除前几个字符 使用 slice console.log(12345.slice(1))// 23452.首字母大写 var word abcconsole.log(word.charAt(0).toUpperCase() word.slice(1))// Abc3.字符为数字时可直接相乘 console.log(2*3) 4.字符串中是否包含某个子字符串 子串既可以为数字也可为字符串 /…

PlayCover“模拟器”作弊解决方案

当下的游戏市场&#xff0c;移动游戏已占据了主导地位&#xff0c;但移动端游戏碍于屏幕大小影响操作、性能限制导致卡顿等因素&#xff0c;开始逐步支持多端互通。但仍有一些游戏存在移动端与 PC 端不互通、不支持 PC 端或没有 Mac 版本&#xff0c;导致 Mac 设备体验游戏不方…

mysql主从搭建(docker)

一、主从概述 MySQL主从又叫Replication、AB复制。简单讲就是A与B两台机器做主从后&#xff0c;在A上写数据&#xff0c;另外一台B也会跟着写数据&#xff0c;实现数据实时同步。有这样几个关键点&#xff1a; 1&#xff09;MySQL主从是基于binlog&#xff0c;主上需开启binl…

掌握Python中classmethod的妙用,提升代码灵活性与可维护性

概要 在Python编程中&#xff0c;classmethod是一种非常有用的装饰器&#xff0c;它可以将一个方法转换为类方法&#xff0c;使得该方法可以通过类名或实例名直接调用&#xff0c;而不需要传入self参数。通过合理使用classmethod&#xff0c;我们可以提高代码的灵活性、复用性…

京东API接口获取京东平台商品详情数据,SKU,价格参数及其返回值说明

做过淘客开发的一定接触过淘宝API开发。 而做京东联盟软件自然离不开京东联盟API。 京东联盟API目前上线的有很多。 参数说明 通用参数说明 url说明 https://api-gw.onebound.cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京东等&#xff0c; API类型:[item_search,ite…

OpenHarmony Meetup北京站招募令

OpenHarmony Meetup城市巡回北京站火热来袭&#xff01;&#xff01;日期&#xff1a;2023年11月25日14:00地点&#xff1a;中国科学院软件园区五号楼B402与OpenHarmony技术大咖近距离互动&#xff0c;分享技术见解&#xff0c;结交志同道合的朋友&#xff01;活动主题聚焦Open…

重要功能丨支持1688API 接口对接一键跨境铺货及采购,解决跨境卖家货源烦恼!

在跨境电商运营中&#xff0c;不少卖家都会优先选择1688平台产品作为跨境店铺货源。 必不可少的1688商品详情接口 阿里巴巴中国站获得1688商品详情 API 返回值说明 item_get-获得1688商品详情 1688.item_get 公共参数 请求地址: 申请调用KEY测试 名称类型必须描述keyStrin…

Threejs_06 多材质的实现

Threejs 同一个几何体如何实现多材质呢&#xff1f; 多材质的实现 1.使用索引绘制一个几何体 //创建几何体(三角形) const geometry new THREE.BufferGeometry();//使用索引绘制 (两个共用的) const vertices new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1…

js高效函数库Lodash.js

Lodash 是一个 JavaScript 的实用工具库&#xff0c;提供了许多实用且高效的函数&#xff0c;可以简化 JavaScript 编程中的常见任务。 Lodash具有高性能、模块化和易用性等特点&#xff0c;表现一致性以及可扩展&#xff0c;下面将介绍一些 Lodash 的重要特性和用法&#xff1…

CRM按行业细分的重要性

很多企业和销售会诟病CRM系统不够贴合行业、功能也不够细分和实用。因为各行各业的业务千差万别&#xff0c;所以功能完备、使用满意度高的CRM一定是与不同行业业务场景高度匹配的&#xff0c;是深度行业化的。因此行业化是CRM发展的重要趋势之一&#xff0c;为什么CRM一定要走…

庖丁解牛:NIO核心概念与机制详解 05 _ 文件锁定

文章目录 Pre概述锁定文件 &#xff08;lock&#xff09;Code文件锁定和可移植性 Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 庖丁解牛&#xff1a;NIO核心概念与机制详解 02 _ 缓冲区的细节实现 庖丁解牛&#xff1a;NIO核心概念与机制详解 03 _ 缓冲区分配、包装和…

2005B 2.4W AB类音频功率放大器应用领域

2005B 2.4W AB类音频功率放大器应用领域&#xff1a;1、便携式DVD&#xff1b;2、笔记本电脑&#xff1b;3、插卡音箱 / USB音箱&#xff1b;4、液晶电视 / 液晶显示器等等。 2005B是一颗单通道AB类音频功率放大器。在5V 电源供电&#xff0c;THDN10%&#xff0c;4欧姆负载上可…

尽快调整心态,切莫自讨苦吃

退休多年的老龄人的本“人民体验官”闲得无聊&#xff0c;怕被闲出更多病痛&#xff0c;更怕被闲死&#xff0c;所以天天上网坚持职业新闻人的老习惯——上网读新闻&#xff0c;并以一孔之见置评&#xff0c;旨在抛砖引玉。 11月8日&#xff0c;本“人民体验官 ”在推广人民日…

python 自动化福音,30行代码手撸ddt模块

用 python 做过自动化的小伙伴&#xff0c;大多数都应该使用过 ddt 这个模块&#xff0c;不可否认 ddt 这个模块确实挺好用&#xff0c;可以自动根据用例数据&#xff0c;来生成测试用例&#xff0c;能够很方便的将测试数据和测试用例执行的逻辑进行分离。 接下来就带大家一起…

2023年亚太杯数学建模亚太赛ABC题思路资料汇总贴

下文包含&#xff1a;2023年亚太杯数学建模亚太赛A- C题思路解析、选题建议、代码可视化及如何准备数学建模竞赛&#xff08;23号发&#xff09; C君将会第一时间发布选题建议、所有题目的思路解析、相关代码、参考文献、参考论文等多项资料&#xff0c;帮助大家取得好成绩。2…

深度学习人体跌倒检测 -yolo 机器视觉 opencv python 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满…