3.6.cuda运行时API-共享内存的学习

news2024/11/25 12:35:04

目录

    • 前言
    • 1. 共享内存
    • 2. shared memory案例
    • 3. 补充知识
    • 总结

前言

杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。

本次课程学习精简 CUDA 教程-共享内存

课程大纲可看下面的思维导图

在这里插入图片描述

1. 共享内存

对于共享内存(shared_memory)你需要知道:

  1. 共享内存因为更靠近计算单元,所以访问速度更快(越近越快,越近越贵
  2. 共享内存通常可以作为访问全局内存的缓存使用
  3. 可以利用共享内存是实现线程间的通信
  4. 通常与 __syncthreads() 同时出现,这个的函数是同步 block 内的所有线程,全部执行到这一行才往下走
  5. 常用方式,通常是在线程 ID 为 0 的时候从 global memory 取值,然后 syncthreads,然后再使用

2. shared memory案例

shared memory 案例的 main.cpp 示例代码如下:


#include <cuda_runtime.h>
#include <stdio.h>

#define checkRuntime(op)  __check_cuda_runtime((op), #op, __FILE__, __LINE__)

bool __check_cuda_runtime(cudaError_t code, const char* op, const char* file, int line){
    if(code != cudaSuccess){    
        const char* err_name = cudaGetErrorName(code);    
        const char* err_message = cudaGetErrorString(code);  
        printf("runtime error %s:%d  %s failed. \n  code = %s, message = %s\n", file, line, op, err_name, err_message);   
        return false;
    }
    return true;
}

void launch();

int main(){

    cudaDeviceProp prop;
    checkRuntime(cudaGetDeviceProperties(&prop, 0));
    printf("prop.sharedMemPerBlock = %.2f KB\n", prop.sharedMemPerBlock / 1024.0f);

    launch();
    checkRuntime(cudaPeekAtLastError());
    checkRuntime(cudaDeviceSynchronize());
    printf("done\n");
    return 0;
}

shared memory 案例的 main.cpp 示例代码如下:

#include <cuda_runtime.h>
#include <stdio.h>

//demo1 //
/* 
demo1 主要为了展示查看静态和动态共享变量的地址
 */
const size_t static_shared_memory_num_element = 6 * 1024; // 6KB
__shared__ char static_shared_memory[static_shared_memory_num_element]; 
__shared__ char static_shared_memory2[2]; 

__global__ void demo1_kernel(){
    extern __shared__ char dynamic_shared_memory[];      // 静态共享变量和动态共享变量在kernel函数内/外定义都行,没有限制
    extern __shared__ char dynamic_shared_memory2[];
    printf("static_shared_memory = %p\n",   static_shared_memory);   // 静态共享变量,定义几个地址随之叠加
    printf("static_shared_memory2 = %p\n",  static_shared_memory2); 
    printf("dynamic_shared_memory = %p\n",  dynamic_shared_memory);  // 动态共享变量,无论定义多少个,地址都一样
    printf("dynamic_shared_memory2 = %p\n", dynamic_shared_memory2); 

    if(blockIdx.x == 0 && threadIdx.x == 0) // 第一个thread
        printf("Run kernel.\n");
}

/demo2//
/* 
demo2 主要是为了演示的是如何给 共享变量进行赋值
 */
// 定义共享变量,但是不能给初始值,必须由线程或者其他方式赋值
__shared__ int shared_value1;

__global__ void demo2_kernel(){
    
    __shared__ int shared_value2;
    if(threadIdx.x == 0){

        // 在线程索引为0的时候,为shared value赋初始值
        if(blockIdx.x == 0){
            shared_value1 = 123;
            shared_value2 = 55;
        }else{
            shared_value1 = 331;
            shared_value2 = 8;
        }
    }

    // 等待block内的所有线程执行到这一步
    __syncthreads();
    
    printf("%d.%d. shared_value1 = %d[%p], shared_value2 = %d[%p]\n", 
        blockIdx.x, threadIdx.x,
        shared_value1, &shared_value1, 
        shared_value2, &shared_value2
    );
}

void launch(){
    
    demo1_kernel<<<1, 1, 12, nullptr>>>();
    demo2_kernel<<<2, 5, 0, nullptr>>>();
}

运行效果如下:

在这里插入图片描述

图2-1 shared memory案例运行效果

在主函数中我们通过调用 cudaGetDeviceProperties 函数获取当前设备的属性,并打印出设备的共享内存的大小,一般为 48KB。

上述示例代码依次展示了使用共享内存 (shared memory)的两个示例:demo1_kerneldemo2_kernel

demo1_kernel

这个示例主要用于展示静态共享变量和动态共享变量的地址。在这个示例中,我们使用了两个静态共享变量和两个动态共享变量,二者在 kernel 函数内外定义都行,没有限制。我们启动的核函数只有一个线程块,每个线程块只有一个线程,因此只有一个线程会执行这个 kernel 函数,并打印对应的共享变量的地址。

通过打印语句,我们可以看到静态共享变量的地址会依次增加,而动态共享变量的地址始终是一样的

demo2_kernel

这个示例主要演示如何给共享变量赋值,可看 图2-2 的示意图

在这里插入图片描述

图2-2 demo2_kernel说明示意图

在这个示例中,我们定义的两个共享变量 shared_value1shared_value2,我们启动的核函数有两个线程块,每个线程块有 5 个线程,每个线程块的第一个线程会进行共享变量的赋值操作,因此当执行到 __syncthreads() 这一步时,每个 block 的其它 4 个线程会等待第一个线程完成赋值操作。

第一个 block 对应的共享变量赋值为 123 和 55,第二个 block 对应的共享变量赋值为 331 和 8,又由于共享内存(shared memory)是在块(block)级别上进行共享的,因此第一个 block 中所有线程打印的共享变量结果为 123 和 55,第二个 block 中所有线程打印的共享变量结果为 331 和 8,这点可以从运行结果中看到。

共享内存案例展示了使用共享内存的基本概念和用法。共享内存可以在同一个线程块中的线程之间共享数据,并且具有低延迟和高带宽的特性。在实际的 CUDA 程序中,共享内存常用于提高访存效率和实现协作式算法。

3. 补充知识

关于共享内存的知识点:(from 杜老师)

  1. sharedMemPerBlock 指示了 block 中最大可用的共享内存
  • 所以可用使得 block 内的 threads 可以相互通信
    • sharedMemPerBlock的应用例子如下图

在这里插入图片描述

在这里插入图片描述

  1. 共享内存是片上内存,更靠近计算单元,因此比 globalMem 速度更快,通常可以充当缓存使用
  • 数据先读入到 sharedMem,做各类计算时,使用 sharedMem 而非 globalMem
  1. demo_kernel<<<1, 1, 12, nullptr>>>();其中第三个参数 12,是指定动态共享内存 dynamic_shared_memory 的大小
  • dynamic_shared_memory 变量必须使用 extern __shared__ 开头
  • 并且定义为不确定大小的数组 []
  • 12 的单位是 bytes,也就是可以安全存放 3 个 float
  • 变量放在函数外面和里面是一样的
  • 其指针由 cuda 调度器执行时赋值
  1. static_shared_memory 作为静态分配的共享内存
  • 不加 extern,以 __shared__ 开头
  • 定义时需要明确数组的大小
  • 静态分配的地址比动态分配的地址低
  1. 动态共享变量,无论定义多少个,地址都一样
  2. 静态共享变量,定义几个地址随之叠加
  3. 如果配置的各类共享内存总和大于 sharedMemPerBlock,则核函数执行错误,Invalid argument
  • 不同类型的静态共享变量定义,其内存划分并不一定是连续的
  • 中间会有内存对齐策略,使得第一个和第二个变量之间可能存在间隙
  • 因此你的变量之间如果存在空隙,可能小于全部大于的共享内存就会报错

总结

本次课程学习了共享内存的使用,shared memory 可以在一个线程块共享数据,由于它靠近计算单元,因此访问速度相比于 global memory 更快。共享内存通常与 __syncthreads 同时出现,为了同步 block 中的所有线程。共享内存变量有静态和动态之分,静态共享内存变量,定义几个地址随之叠加,而动态共享变量,无论定义多少个,地址都一样。定义的共享变量并不能给初始值,必须由线程或者其它方式赋值。

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

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

相关文章

前端vue入门(纯代码)32_编程式路由导航

星光不问赶路人&#xff0c;时光不负有心人 【30.Vue Router--编程式导航】 除了使用 <router-link> 创建 a 标签来定义导航链接&#xff0c;我们还可以借助 $router 的实例方法&#xff0c;通过编写代码来实现。 编程式路由导航的5种方法 我们先看一下组件实例中的t…

掌握这几招,让你的CTA按钮更吸引人点击

CTA全称Call-To-Action&#xff0c;是行为召唤按钮&#xff0c;是App和网页设计中的关键元素。 在落地页设计制作中&#xff0c;CTA按钮是用户在访问页面后引导用户去点击并且跳转至下一个流程&#xff08;如购买、联系、提交等行为&#xff09;的按钮控件。其核心目标是引导用…

函数图形化显示练习(进阶)

运行代码: //函数图形化显示练习&#xff08;进阶&#xff09; #include"std_lib_facilities.h" #include"GUI/Simple_window.h" #include"GUI/GUI.h" #include"GUI/Graph.h" #include"GUI/Point.h" //定义函数 double one…

【Spring Cloud系列】Hystrix应用详解

【Spring Cloud系列】Hystrix应用详解 文章目录 【Spring Cloud系列】Hystrix应用详解一、概述二、什么是Hystix三、Hystrix作用四、Hystrix设计原则五、Hystrix实现原理5.1 隔离5.2 熔断5.3 降级服务降级主要用于什么场景呢实现服务降级需要考虑几个问题降级分类 5.4 缓存请求…

使用Hugging Face预训练Bert处理下游任务显存占用过多

在使用HuggingFace的transformer下的BertForMaskedLM进行预训练语言模型的load时&#xff0c;bert会占用很大的显存。 这里可以考虑使用TinyBERT&#xff0c;速度和显存上都能得到很大的优化。 具体的方法进入https://huggingface.co/huawei-noah/TinyBERT_General_4L_312D/tr…

day01——项目导入+环境搭建

目录 软件开发整体介绍 软件开发流程 需求分析 设计阶段 编码阶段 测试阶段 上线运维 角色分工 软件环境 苍穹外卖项目介绍 项目介绍 功能架构 产品原型 ​编辑 技术选型 开发环境搭建——前端环境搭建 开发环境搭建——后端环境搭建 熟悉项目结构 ​编辑 使…

入门开发教程之网站品质教程

目录 网站品质 教程 网站品质教程 背景 要素 可访问性 可用性 可靠性 可维护性 提升网站品质 针对性调整 优化网页速度 提供多种访问方法 结论 网站品质教程 背景 在今天这个数字化时代&#xff0c;网站已经成为了各个行业展示产品和服务的重要媒介。而网站品质是…

百分点科技苏萌受邀出席首届全国统计与数据科学联合会议

7月11-13日&#xff0c;首届全国统计与数据科学联合会议在北京举行&#xff0c;会议由中国现场统计研究会、中国数学会概率统计分 会、全国工业统计学教学研究会和中国商业统计学会联合主办&#xff0c;北京大学统计科学中心承办&#xff0c;旨在促进统计与数据科学领域发展&a…

H3C-Cloud Lab实验-IPv6实验

实验拓扑图&#xff1a; 实验需求&#xff1a; 1、在R1和PC3上开启IPv6链路本地地址自动生成&#xff0c;测试是否能够使用链路本地地址互通 2、为R1配置全球单播地址2001::1/64&#xff0c;使PC3能够自动生成与R1同一网段的IPv6地址3、测试R1和PC3是否能够使用全球单播地址互…

【UE4 塔防游戏系列】05-制作可跟踪旋转的炮塔

目录 效果 步骤 一、设置游戏观察视角 二、设置PlayerController 三、制作可跟踪旋转的炮塔 效果 步骤 一、设置游戏观察视角 在视口中调整好位置&#xff0c;能够看到敌人行走的全部路线即可。然后在此处创建CameraActor 打开关卡蓝图&#xff0c;设置使用这个相机的…

【Kaggle】初学者几个冷门的操作总结

文章目录 一、如何看当前的目录&#xff1f;二、Kaggle如何切换路径&#xff1f;三、与包安装或设置有关的错误四、如何把 Kaggle 上的 input 数据转到 output 中&#xff1f; 一、如何看当前的目录&#xff1f; 在 Linux 中&#xff0c;你可以使用 pwd 命令来查看当前所在的目…

UML与SYSML的关系

UML与SysML的联系 UML&#xff08;统一建模语言&#xff09;和SysML&#xff08;系统建模语言&#xff09;是两种与建模相关的语言&#xff0c;它们之间存在联系和区别。 SysML的图分类如下图所示。 联系 SysML是基于UML的&#xff0c;它重用了UML 2的子集&#xff0c;并提…

MySQL持久化数据——主从分离 Linux下创建2个MySQL的Docker容器 挂载方式启动 配置主从

目录 引出数据库的事务1.原子性2.一致性3.隔离性4.持久性 MySQL持久化数据0.在宿主机centos创建主的文件夹1.拷贝my.cnf配置文件2.挂载方式启动主mysql3.修改my.cnf文件的权限【bug】mysql: [ERROR] unknown variable server-id200. 3.修改主的my.cof文件4.创建主从账号slave5.…

Mysql索引实战

Mysql索引实战 一&#xff1a;概述1.1 索引如何提高查询效率&#xff1a; 二&#xff1a;结构2.1 主要索引结构2.2 详解BTree2.2.1 二叉树2.2.2 红黑树2.2.3 B-Tree2.2.4 BTree2.2.5 为什么InnoDB存储引擎选择使用Btree索引结构&#xff1f; 三&#xff1a;索引分类3.1 按照作用…

使用fast测试的错误

错误&#xff1a;Connection refused: connect 分析&解决 检查服务的端口号和fast生成请求时的端口号是否一致&#xff0c;不一致会报上面的错误 分析&#xff1a;设置服务配置的方法很多&#xff0c;可以写在配置文件里&#xff0c;也可以写在命令行里&#xff0c;当有多…

windows nodejs 版本切换

一、按健winR弹出窗口&#xff0c;键盘输入cmd,然后敲回车。然后进入命令控制行窗口&#xff0c;并输入where node查看之前本地安装的node的路径。 二、找到上面找到的路径&#xff0c;将node.exe所在的父目录里面的所有东西都删除。 三、从官网下载安装包 https://github.com/…

轻量级性能测试工具 wrk 应该如何使用?

项目设计之初或者是项目快要结束的时候&#xff0c;大佬就会问我们&#xff0c;这个服务性能测试的结果是什么&#xff0c;QPS 可以达到多少&#xff0c;RPS 又能达到多少&#xff1f;接口性能可以满足未来生产环境的实际情况吗&#xff1f;有没有自己测试过自己接口的吞吐量&a…

MongoDB安装配置教程(详细版)

前言&#xff1a;MongoDB是前端开发人员普遍使用的数据库&#xff0c;因为MongoDB不需要图形界面&#xff0c;是一个基于分布式文件存储的开源数据库系统。MongoDB 将数据存储为一个文档&#xff0c;数据结构由键值对(key>value)组成&#xff1b;MongoDB 文档类似于 JSON 对…

Flutter:自定义错误显示

为什么要自定义错误处理 以下面数组越界的错误为例&#xff1a; class _YcHomeBodyState extends State<YcHomeBody> {List<String> list [苹果, 香蕉];overrideWidget build(BuildContext context) {return Center(child: Column(children: [Text(list[0]),Tex…

小区物业管理信息系统设计与实现(论文+源码)

小区物业管理信息系统设计与实现(论文源码) 本篇 论文源码私我 以上内容只是精简版 还有很多原创类型论文 摘 要 随着互联网的发展&#xff0c;网络技术的发展变得极其重要&#xff0c;所以依靠计算机处理业务成为了一种社会普遍的现状。管理方式也自然而然的向着现代化技术方…