CUDA编程笔记(5)

news2024/11/13 11:01:54

文章目录

  • 前言
  • CUDA的内存组织
    • 全局内存
    • 常量内存
    • 纹理内存和表面内存
    • 寄存器
    • 局部内存
    • 共享内存
    • L1和L2缓存
    • SM的构成
  • API函数查询设备
  • 总结


前言

cuda的内存组织,在使用GPU时尽可能提高性能,合理的使用设备的内存也是十分重要的。

CUDA的内存组织

如表所示:

内存类型物理位置访问权限可见范围生命周期
全局内存在芯片外可读可写所有线程和主机端由主机分配和释放
常量内存在芯片外仅可读所有线程和主机端由主机分配和释放
纹理和表面内存在芯片外一般仅可读所有线程和主机端由主机分配和释放
寄存器内存在芯片内可读可写单个线程所在线程
局部内存在芯片外可读可写单个线程所在线程
共享内存在芯片内可读可写单个线程块所在线程块

全局内存

定义:这里的全局内存,指的是核函数中所有线程都能访问到数据的内存。
作用:保存核函数提供数据,并在主机与设备及设备与与设备之间传递数据。
不在GPU芯片上,所以为核函数提供数据时具有较高的延迟和较低的访问速度。
内存容量基本和GPU的显存差不多。
是可读可写的。
动态全局内存变量:前面cuda数组相加的程序中定义的d_x,d_y,d_z就是动态分配的,要先通过cudaMalloc()为其分配设备内存和cudaMemcpy()将主机上的数据传递到设备上,然后在核函数中访问分配的内存和改变其中的数值。
静态全局内存变量:使用cudaMemcpyToSymbol()进行主机与设备之间的数据传输和cudaMemcpyFromSymbol()进行设备与主机之间的数据传输。在核函数中,可直接对静态全局内存变量进行访问,并不需要将它们以参数的形式传给核函数。
由以下方式在函数外部定义

__device__ T x;  // 单个变量
__device__ T y[N];	// 固定长度的数组

例子:
在这里插入图片描述

常量内存

定义:是有常量缓存的全局内存,数量有限,仅有64kb。
作用:和全局内存一样。
仅可读不可写,而且由于有缓存,常量内存的访问速度比全局内存要高。
使用:cuda数组相加的程序里的const int N,就是使用了常量内存的变量。

纹理内存和表面内存

定义:类似于常量内存
一般仅可读,表面内存也可写。对于计算能力不小于3.5的GPU来说,将某些只读全局内存数据用__ldg()函数通过只读数据缓存读取,既可以达到使用纹理内存的加速效果,又可使代码简洁。

寄存器

定义:在核函数中不加任何限定符的变量一般来说就存放于寄存器中(可能在局部内存中)。
寄存器可读可写。寄存器内存在芯片内,是所有内存中访问速度最高的,但其数量有限。
使用:cuda数组相加的程序里的 int n = blockDim.x * blockIdx.x + threadIdx.x;
其中n就是一个寄存器变量。在核函数中使用z[n] = x[n] + y[n],寄存器变量n并将赋值号右边计算出来的赋值给它。
生命周期与所属线程的生命周期一致,从定义它开始到线程结束。寄存器变量仅仅被一个线程可见,每一个线程不同的线程中该寄存器变量是不同的。

局部内存

定义:和寄存器几乎一样。
寄存器里放不下的变量可能放在局部内存里,这种判断是由编译器自动做。

共享内存

定义:与寄存器类似,但共享内存对整个线程块可见。
作用:减少对全局内存的访问,或者改善对全局内存的访问模式。
其生命周期与整个线程块一致。
使用:在核函数中要将一个变量定义为共享内存变量,就要在定义语句中加上一个限定符__shared__

__shared__ real s_y[128];

L1和L2缓存

从费米架构开始,有了SM层次的L1缓存(一级缓存)和设备层次的L2缓存(二级缓存)。
主要用来缓存全局内存和局部内存的访问,减少延迟。L1和L2缓存是不可编程的缓存(用户最多能引导编译器做一些选择)。

SM的构成

(1)一定数量的寄存器
(2)一定数量的共享内存
(3)常量内存的缓存
(4)纹理和表面内存的缓存
(5)L1缓存
(6)两个线程束调度器,用于在不同线程的上下文之间迅速切换及为准备就绪的线程束发出执行指令。
(7)执行核心:若干整型数运算的核心,若干单精度浮点数运算的核心,若干双精度浮点数运算的核心,若干单精度浮点数超越函数的特殊函数单元,若干混合精度的张量核心。

API函数查询设备

用一些cuda的api程序来查询设备的一些规格。

#include "error.cuh"
#include <stdio.h>

int main(int argc, char *argv[])
{
    // 设置查询的设备编号.
    int device_id = 0; 
    if (argc > 1) device_id = atoi(argv[1]);
    // cudaSetDevice()函数将对所指定的设备进行初始化
    CHECK(cudaSetDevice(device_id));
	// 定义设备输出规格的一些结构体变量
    cudaDeviceProp prop;
    CHECK(cudaGetDeviceProperties(&prop, device_id));  // 得到了device_id设备的性质,存放在结构体变量中的prop中.

    printf("Device id:                                 %d\n", 
        device_id);
    printf("Device name:                               %s\n",
        prop.name);
    printf("Compute capability:                        %d.%d\n",
        prop.major, prop.minor);
    printf("Amount of global memory:                   %g GB\n",
        prop.totalGlobalMem / (1024.0 * 1024 * 1024));
    printf("Amount of constant memory:                 %g KB\n",
        prop.totalConstMem  / 1024.0);
    printf("Maximum grid size:                         %d %d %d\n",
        prop.maxGridSize[0], 
        prop.maxGridSize[1], prop.maxGridSize[2]);
    printf("Maximum block size:                        %d %d %d\n",
        prop.maxThreadsDim[0], prop.maxThreadsDim[1], 
        prop.maxThreadsDim[2]);
    printf("Number of SMs:                             %d\n",
        prop.multiProcessorCount);
    printf("Maximum amount of shared memory per block: %g KB\n",
        prop.sharedMemPerBlock / 1024.0);
    printf("Maximum amount of shared memory per SM:    %g KB\n",
        prop.sharedMemPerMultiprocessor / 1024.0);
    printf("Maximum number of registers per block:     %d K\n",
        prop.regsPerBlock / 1024);
    printf("Maximum number of registers per SM:        %d K\n",
        prop.regsPerMultiprocessor / 1024);
    printf("Maximum number of threads per block:       %d\n",
        prop.maxThreadsPerBlock);
    printf("Maximum number of threads per SM:          %d\n",
        prop.maxThreadsPerMultiProcessor);

    return 0;
}

查询的一些设备设置:
在这里插入图片描述
从这些输出可以看出GPU的内存组织,和所占各内存的最大容量大小。

总结

cuda程序执行的计时方式和GPU性能加速的分析
参考:
如博客内容有侵权行为,可及时联系删除!
CUDA 编程:基础与实践
https://docs.nvidia.com/cuda/
https://docs.nvidia.com/cuda/cuda-runtime-api
https://github.com/brucefan1983/CUDA-Programming

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

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

相关文章

Docker基本操作

Docker基本操作一、镜像操作1.镜像名称2.镜像命令&#xff08;1&#xff09;拉取、查看镜像&#xff08;2&#xff09;保存、导入镜像二、容器操作1.容器相关命令2.创建并运行一个容器3.进入容器&#xff0c;修改文件4.小结三、数据卷&#xff08;容器数据管理&#xff09;1.什…

Java:枚举类型

Java&#xff1a;枚举类型 每博一文案 师父说&#xff1a;人活一世&#xff0c;每个人都有他的特别&#xff0c;每个人都值得被温柔相待。红尘一遭&#xff0c;每段经历都有它的必然&#xff0c; 每段经历都造就了现在的你&#xff0c;最快乐的事情&#xff0c;就是做自己&…

Java多线程案例之定时器

一. 定时器概述 1. 什么是定时器 定时器是一种实际开发中非常常用的组件, 类似于一个 “闹钟”, 达到一个设定的时间之后, 就执行某个指定好的代码. 比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自…

排序算法: 数据的离散化(排序+去重 C++例题实现)

文章目录数据的离散化例题&#xff1a;电影完整代码数据的离散化 离散化是指将一个无穷大的集合中的若干个元素映射到一个有限的集合中&#xff0c;以便于对那个无穷大的集合进行操作。 在很多情况下&#xff1a;对于一个规定在Z范围内的整数范围&#xff0c;他有可能包含非常…

maven创建自定义web工程模板

一&#xff0c;先搭建好一个项目模板。 注意每个文件夹下都放一个文件占位&#xff0c;否则创建模板时会认为是空目录不进行创建。 注意项目文件夹名字 和 pom.xml 中<artifactId 和 <name 的名字都使用相同的名字&#xff0c;写一个好记的名字&#xff0c;因为后面生…

QT UI布局设置整理-边框设置

一、设置边距的方法 1、设置容器内部的内容控件的边距 //设置容器leftBar&#xff08;QWidget&#xff09;内部marginui->leftBar->setContentsMargins(10,10,0,0); 2、 设置内部控件之间的间距 //editWidget是一个QWidget ui->editWidget->layout()->setSpac…

【云原生kubernetes】k8s中控制器使用详解

一、什么是控制器 控制器是管理pod的中间层&#xff0c;只需要告诉Pod控制器&#xff0c;想要创建多少个什么样的Pod&#xff0c;它会创建出满足条件的Pod &#xff1b;控制器相当于一个状态机&#xff0c;用来控制Pod的具体状态和行为 &#xff1b;controller会自动创建相应的…

【数据库概论】3.2 SQL的查询、更新和删除语句

一、 数据查询 SQL提供SELECT语句用于查询&#xff0c;一般格式为&#xff1a; 根据WHERE子句条件表达式从FROM子句指定的基本表、视图中找出满足条件的元组 GROUP BY语句则用作将结果按照<列名1>的值进行分组&#xff0c;该属性列值相等的元组为一个组&#xff1b;ORD…

Essential C++第五章习题

目录 5.1 5.2 5.3 5.4 5.1 C代码&#xff1a; //Stack.h#include<vector> #include<string> #include<iostream> using namespace std;#pragma once#ifndef _STACK_H_ #define _STACK_H_typedef string elemType;class Stack { public://基类的析构函数…

【JavaSE专栏5】Java 基本数据类型和取值范围

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

Mine Goose Duck 0.2版本发布

本次我增加了模组的1.16.5和1.18.2的适用版本&#xff0c;新增了一些职业和装扮 1.新职业 1.冒险家 你不会死于摔伤、溺水、火烧、冰冻。 2.工程师 你可以修改888范围内红石设备的状态。 3.模仿者 怪物认为你是他们的一员。 4.加拿大鹅 你会自动报警并召唤警车。 5.…

深度卷积对抗神经网络 基础 第三部分 (WGAN-GP)

深度卷积对抗神经网络 基础 第三部分 (WGAN-GP&#xff09; Wasserstein GAN with Gradient Penalty (WGAN-GP) 我们在训练对抗神经网络的时候总是出现各种各样的问题。比如说模式奔溃 (mode collapse)和 梯度消失&#xff08;vanishing gradient&#xff09;的问题。 比如说…

在linux下安装docker

文章目录 目录 文章目录 前言 一、docker 二、使用步骤 1.环境准备 2.安装 三、配置阿里云镜像加速 四、卸载 总结 前言 一、docker 镜像&#xff08;image&#xff09;&#xff1a; docker镜像就好比是一个模板&#xff0c;可以通过这个模板来创建容器服务&#xff0c;tomc…

【攻坚克难】详解k8s持久化存储数据pv、pvc存储问题

问题 如图:pod中的容器,创建一个包含文件的目录,重启pod或系统重启后,此目录及其文件都会丢失,如何保证其不会丢失? 图 1 创建包含文件的目录 方法 分析:用pv、pvc为k8s持久化存储数据是最好的选择,可解决上述问题。流程:pv → pvc → pod把创建的目录挂载到pvc上步…

路由 OSPF 优化(FA地址、路由汇总、路由过滤、区域认证、接口认证)

1.2.0 路由 OSPF 优化&#xff08;FA地址、路由汇总、路由过滤、区域认证、接口认证&#xff09; 一、FA地址 该文章介绍的FA地址说辞简单易懂&#xff1a;路由协议系列之六&#xff1a;OSPF FA地址 产生条件 ASBR在其连接外部网络的接口&#xff08;外部路由的出接口&#xf…

CS61A 2022 fall HW 01: Functions, Control

CS61A 2022 fall HW 01: Functions, Control 文章目录CS61A 2022 fall HW 01: Functions, ControlQ1: A Plus Abs BQ2: Two of ThreeQ3: Largest FactorQ4: HailstoneHW01对应的是Textbook的1.1和1.2 Q1: A Plus Abs B 题目&#xff1a; Fill in the blanks in the following f…

Java | 解决并发修改异常问题【CurrentModificationException】

今日碰到Java中的一个异常&#xff0c;名为CurrentModificationException&#xff0c;从属于RunTimeException运行时异常&#xff0c;故作此记录 异常解析 首先来说明一下什么是【并发修改异常】❓ 因为迭代器依赖集合而存在&#xff0c;因为当你在操作集合中元素的时候&#…

springboot中restful风格请求的使用

springboot中restful风格请求的使用restful风格springboot中的使用1.创建html表单页面2.在yml配置文件中开启rest表单支持3.编写controller层及对应映射处理4.启动服务&#xff0c;逐个访问restful风格 Rest风格支持&#xff08;使用HTTP请求方式动词来表示对资源的操作&#…

【手写 Vue2.x 源码】第四十二篇 - 组件部分 - 组件挂载流程简述

一&#xff0c;前言 上篇&#xff0c;组件部分-生成组件的真实节点&#xff1b; 本篇&#xff0c;组件部分-组件挂载流程分析&#xff1b; 二&#xff0c;组件挂载流程分析 1&#xff0c;示例 全局组件&#xff1a;my-button&#xff0c;name&#xff1a;‘全局组件’&…

什么是软件架构中的ASRs(架构需求文档)?

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件工程》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 专栏地址 软件工程专栏地址 专栏系列文章 软件工程复习01&#xff1a;软件工程概述 软件工程复习02&#xf…