CUDA共享内存详解

news2024/11/27 6:17:52

为什么需要共享内存?

共享内存的访问速度比访问全局速度快的多,因此对于多次访问全局内存的程序,特别是需要多次将全局内存的运算结果缓存到全局内存的运算,先将临时结果缓存到共享内存再做计算,会提高运算速度。

1、例如累积归并求和,将一串数字从头加到尾,归并求和算法如下:
在这里插入图片描述
如果使用全局内存,每做一次减半运算,都要访问一半的全局内存,总要访问的全局内存次数为 N + N/2 + N/4 +… + 1 次。因此减少全局内存的访问次数可以提高运算速度。
如果提高呢?那就是第一次先将全局内存复制到共享内存中,这时总需要访问N次全局内存,每个线程只需要访问一次。

2、再如直方图统计:
假设直方图统计的bin个数为256,假设统计N 个数,如果使用全局内存,需要将N个全局内存的数累加到256个全局内存中,那么也就是需要访问了2N次全局内存。如果将256 个bin的内存改为共享内存,那么只需要访问N次的全局内存,运算速度得到提升。

什么是共享内存

对于CUDA,一个grid 有多个Block 块,一个block块多个线程。
共享内存只是 Block 块内的线程共享,不同Block块之间的共享内存是不会共享的。
定义在核函数内,加前关键字为__shared__,例如:
shared int sharedata[thread_perblock];

块内同步

在做共享内存时,一般需要使用线程块内同步__syncthreads(),只是让相同block块中的线程都要达到这个位置后才可往下执行。

如何实现

为了使用共享内存,一般定义共享内存的大小为Block 块中的线程个数。这样每个线程都对应到响应的共享内存中。使用线程id 进行对应。
int thread_id = threadIdx.x;
对于不同块中的共享内存,之间不存在共享,因此全局映射到共享内存方式如下:
int tid = threadIdx.x + blockDim.x * blockIdx.x;
sharedata[thread_id] = data[tid];
tid 处于哪个Block 中即映射到哪个Block块中的共享内存。

做完映射和对应后即可进行运算,块内运算以块为基本单元,使用id为块内线程id:
例如规约求和:

 int mid = thread_perblock / 2;  //规约求和, thread_perblock 必须为 2 的 K 次方
    while(mid != 0){
        if(thread_id < mid){
            sharedata[thread_id] += sharedata[thread_id + mid];
        }
        __syncthreads();
        mid /= 2;
    }

每做完一轮块内运算进行一次同步,等待块内所有线程执行完。while里即为循环次数。
等所有块执行完后将共享内存的结果再赋值到全局内存,完成整个过程。

 out[blockIdx.x] = sharedata[0]; // 不同block中的shareddata 互不干扰

代码

1、归并求和:

#define thread_perblock 8
 __global__ void reduce_add(int *data, int *out, int N){
    __shared__ int sharedata[thread_perblock];
    int tid = threadIdx.x + blockDim.x * blockIdx.x;
    int thread_id = threadIdx.x;
    printf("tid = %d, %d\n", tid, data[tid]);
    while (tid < N) // 数据预处理到共享内存,当数组大于线程数量,需要一个线程处理多个数据,跨度(blockDim.x * gridDim.x)
    {
        sharedata[thread_id] += data[tid];
        tid += blockDim.x * gridDim.x;
    }
    __syncthreads();// 块内同步

    int mid = thread_perblock / 2;  //规约求和, thread_perblock 必须为 2 的 K 次方
    while(mid != 0){
        if(thread_id < mid){
            sharedata[thread_id] += sharedata[thread_id + mid];
            printf("blockIdx.x = %d, sharedata[%d] = %d , mid = %d\n " ,blockIdx.x, thread_id, sharedata[thread_id], mid);
        }
        __syncthreads();
        mid /= 2;
    }
    out[blockIdx.x] = sharedata[0]; // 不同block中的shareddata 互不干扰
    printf("blockIdx.x = %d, sharedata[0] = %d \n" , blockIdx.x,  sharedata[0]);
 }

2、直方图统计:

__global__ void histo_kernel(unsigned char *buffer, long size, unsigned int *histo) {
    __shared__ unsigned int temp[256];
    temp[threadIdx.x] = 0;
    //这里等待所有线程都初始化完成
    __syncthreads();
    int i = threadIdx.x + blockIdx.x * blockDim.x;
    int offset = blockDim.x * gridDim.x;
    while (i < size) {
        atomicAdd(&temp[buffer[i]], 1); // 先在共享内存中操作,减少全局内存访问
        i += offset;
    }
    __syncthreads();//等待所有线程完成计算,统计完一个块
    //将每个块结果统计到全局内存
    atomicAdd(&(histo[threadIdx.x]), temp[threadIdx.x]);
}

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

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

相关文章

C语言使用Wininet库网络编程跳坑记 —— cookies篇

笔者尝试C语言使用Wininet库进行网络编程时&#xff0c;我尝试使用 InternetSetCookieA() 或 HttpAddRequestHeadersA() 设置 cookie。 HttpAddRequestHeadersA(Request, headers, header_len, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); InternetSetCookieA(url, NU…

基于SpringBoot+Vue的电影分享平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 当代社会&#xff0c;…

Linux(环境准备)VMware与CentOS及XShell的安装

目录 第 1 章 VMware 1.1 VMware 安装 1.1.1 VMware Workstation Pro 15.5 安装包 ​1.2.2 欢迎界面 1.2.3 同意许可证 1.2.4 选择安装路径 1.2.5 用户体检计划 1.2.6 快捷方式 1.2.7 开始安装 1.2.8 等待安装完成 1.2.9 安装完成 1.2.10 输入许可证 1.2.11 VM…

工欲善其事,必先利其器--Vscode嵌入式Linux开发远程开发设置(适用于多平台)

点击上方“嵌入式应用研究院”&#xff0c;选择“置顶/星标公众号” 干货福利&#xff0c;第一时间送达&#xff01; 来源 | 嵌入式应用研究院 整理&排版 | 嵌入式应用研究院 最近搭了一台Ubuntu18.04版本的桌面PC&#xff0c;不得不说比起Window搭虚拟机搞起来爽多了&…

python文件首行

类似于一切脚本文件一样&#xff0c;首行可用于指定解释器用于执行文件&#xff1b; 常见的是linux系统下的各个解释器。比如&#xff1a; #!/bin/sh– 使用Bourne shell或兼容的 shell执行文件&#xff0c;假定位于 /bin 目录中#!/bin/bash– 使用Bash shell执行文件#!/usr/…

会声会影如何抠图换背景 会声会影抠图后人物变透明

抠图换背景&#xff0c;大家可能会在图片编辑上应用得比较多。实际上&#xff0c;视频也能通过抠图的方式换背景&#xff0c;其困难程度与背景类型有关。纯色背景会比较简单&#xff0c;非纯色背景会比较难&#xff0c;接下来&#xff0c;一起来看看会声会影如何抠图换背景&…

Cocos Creator3D:制作可任意拉伸的 UI 图像

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 制作可任意拉伸的 UI 图像 UI 系统核心的设计原则是能够自动适应各种不同的设备屏幕尺寸&#xff0c;因此我们在制作 UI 时需要正确设置每个控件元素的尺寸&#xff08;size&#…

java项目之病人跟踪治疗信息管理系统(ssm+vue)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的病人跟踪治疗信息管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

【C语言复习】第五篇、关于C语言变量,常量,字符串,转义字符的知识

目录 第一部分、关于变量 1、什么是变量&#xff1f;变量的分类&#xff1f; 2、变量的作用域&#xff1f;变量的生命周期&#xff1f; 第二部分、关于常量 1、什么是常量&#xff1f; 2、如何定义常量&#xff1f; 第三部分、关于字符串 1、什么是字符串&#xff1f; …

2023年春季学期NLP总结作业

自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是计算机科学&#xff0c;人工智能&#xff0c;语言学关注计算机和人类&#xff08;自然&#xff09;语言之间的相互作用的领域。自然语言处理是计算机科学领域与人工智能领域中的一个重要方向…

【网络原理】TCP连接管理机制(三次握手四次挥手)

&#x1f94a;作者&#xff1a;一只爱打拳的程序猿&#xff0c;Java领域新星创作者&#xff0c;CSDN、阿里云社区优质创作者。 &#x1f93c;专栏收录于&#xff1a;计算机网络原理 在使用TCP协议进行网络交互时&#xff0c;TCP会进行三次握手即建立连接&#xff0c;TCP四次挥手…

Stable Diffusion局部重绘功能,如何完美抹掉不想要的物体?

网上一堆文生图教程&#xff0c;这种抽卡式东西玩几天就没有意思了&#xff0c;怎么按照自己的意愿生成自己的图是非常有意思的东西&#xff0c;所以我对局部重绘特别感兴趣&#xff0c;借助 SD 的扩散算法&#xff0c;如何利用它的扩散算法来向着自己期望的方向上呈现&#xf…

分享5款十分小众的软件,不好用你找我

今天推荐5款十分小众的软件&#xff0c;但是每个都是非常非常好用的&#xff0c;用完后觉得不好用你找我。 网络测速——NetSpeedMonitor NetSpeedMonitor是一款用于测量和显示你的网络速度的工具。它可以让你在任务栏上看到你的实时上传和下载速度&#xff0c;并提供多种功能…

Win10任务栏一直转圈圈不能操作怎么办?

Win10任务栏一直转圈圈不能操作怎么办&#xff1f;Win10电脑用户遇到了任务栏一直转圈圈不能操作的问题&#xff0c;不知道怎么操作才能解决&#xff0c;这时候用户可以打开桌面上的控制面板&#xff0c;点击卸载更新补丁&#xff0c;也可以通过打开命令提示符窗口&#xff0c;…

【业务功能篇30】代码重构--卫语句/idea内置工具抽象方法

业务场景&#xff1a; 当前我们项目在发布流水线的时候&#xff0c;codecheck 圈复杂度高于10的&#xff0c;或者14的&#xff0c;需要进行一些整改&#xff0c; 什么是圈复杂度&#xff1f; 圈复杂度&#xff08;Cyclomatic complexity&#xff0c;CC&#xff09;也称为条件复…

【Leetcode60天带刷】day07哈希表——454.四数相加II , 383. 赎金信 ,15. 三数之和 , 18. 四数之和

题目&#xff1a;454.四数相加II 454. 四数相加 II 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < nnums1[i] nums2[j] nums3[k] nums4[l] 0 …

进阶面向对象

面向对象的意义在于 将日常生活中习惯的思维方式引入程序设计中 将需求中的概念直观的映射到解决方案中 以模块为中心构建可复用的软件系统 提高软件产品的可维护性和可拓展性 类和对象是面向对象中的两个基本概念 类&#xff1a;指的是一类事务&#xff0c;是一个抽象的概…

【Python 随练】学生成绩等级划分

题目&#xff1a; 利用条件运算符的嵌套来完成此题&#xff1a;学习成绩 ≥ 90 分的同学用 A 表示&#xff0c;60-89 分之间的用 B 表示&#xff0c;60 分以下的用 C 表示。 简介&#xff1a; 在本篇博客中&#xff0c;我们将使用条件运算符的嵌套来划分学生成绩的等级。根据…

Redis安装说明(黑马程序员)

Redis安装说明&#xff08;黑马程序员&#xff09; 笔者的redis(Linux版)的下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87926624 笔者的redis图形化桌面客户端&#xff0c;下载链接地址为&#xff1a;https://download.csdn.net/download/w…

朴素贝叶斯算法

文章目录 1. 贝叶斯定理2. 朴素贝叶斯2.1 朴素贝叶斯原理2.2 朴素贝叶斯适用范围2.3 朴素贝叶斯常用模型 3. 朴素贝叶斯算法的特点4. 朴素贝叶斯的Python应用5. 源码仓库地址 1. 贝叶斯定理 先验概率&#xff1a;即基于统计的概率&#xff0c;是基于以往历史经验和分析得到的结…