【CUDA】认识CUDA
目录
一、CUDA编程
二、第一个CUDA程序
三、CUDA关键字
四、device管理
4.1 初始化
4.2 Runtime API查询GPU信息
4.3 决定最佳GPU
CUDA C++ 编程指南CUDA C++在线文档:CUDA C++ 编程指南
CUDA是并行计算的平台和类C编程模型,能很容易的实现并行算法。只需配备NVIDIA GPU,就可以在许多设备上运行并行程序
一、CUDA编程
CUDA编程允许程序执行在异构系统上,即CUP和GPU,二者有各自的存储空间,并由PCI-Express 总线区分开。注意二者术语上的区分:
- Host:CPU and itsmemory (host memory)
- Device: GPU and its memory (device memory)
device 可以独立于 host 进行大部分操作。当一个 kernel 启动后,控制权会立刻返还给 CPU 来执行其他额外的任务。所以CUDA编程是异步的。一个典型的CUDA程序包含由并行代码补足的串行代码,串行代码由host执行,并行代码在device中执行
host 端代码是标准C,device 是CUDA C代码。可以把所有代码放到一个单独的源文件,也可以使用多个文件或库。NVIDIA C编译器(nvcc)可以编译 host 和 device 端代码生成可执行程序
一个典型的CUDA程序结构包含五个主要步骤:
- 分配GPU空间
- 将数据从CPU端复制到GPU端
- 调用CUDA kernel来执行计算
- 计算完成后将数据从GPU拷贝回CPU
- 清理GPU内存空间
二、第一个CUDA程序
若是第一次使用CUDA,在Linux下可以使用下面的命令来检查CUDA编译器是否安装正确:

还需检查下机器上的GPU

以上输出显示仅有一个GPU显卡安装在机器上
CUDA 为许多常用编程语言提供扩展,如 C、C++、Python 和 Fortran 等语言。CUDA 加速程序的文件扩展名是.cu
下面包含两个函数,第一个函数将在 CPU 上运行,第二个将在 GPU 上运行
void CPUFunction()
{printf("This function is defined to run on the CPU.\n");
}
__global__ void GPUFunction()
{printf("This function is defined to run on the GPU.\n");
}int main()
{CPUFunction();GPUFunction<<<1, 1>>>();cudaDeviceSynchronize();return 0;
}
- __global__ void GPUFunction()
__global__ 关键字表明以下函数将在 GPU 上运行并可全局调用
将在 CPU 上执行的代码称为主机代码,而将在 GPU 上运行的代码称为设备代码
注意返回类型为 void,使用 __global__ 关键字定义的函数要求返回 void 类型
- GPUFunction<<<1, 1>>>();
当调用要在 GPU 上运行的函数时,将此种函数称为已启动的核函数
启动核函数时,必须提供执行配置,即在向核函数传递任何预期参数之前使用 <<< … >>> 语法完成的配置。在宏观层面,程序员可通过执行配置为核函数启动指定线程层次结构,从而定义线程组(称为线程块)的数量,以及要在每个线程块中执行的线程数量
- cudaDeviceSynchronize();
与许多 C/C++ 代码不同,核函数启动方式为异步:CPU 代码将继续执行而无需等待核函数完成启动。调用 CUDA 运行时提供的函数 cudaDeviceSynchronize 将导致主机 (CPU) 代码暂作等待,直至设备 (GPU) 代码执行完成,才能在 CPU 上恢复执行
三、CUDA关键字
_global__关键字
__global__执行空间说明符将函数声明为内核。 其功能是:
- 在设备上执行
- 可从主机调用,可在计算能力为 3.2或更高的设备调用
- __global__ 函数必须具有 void 返回类型,并且不能是类的成员函数
- 对 global 函数的任何调用都必须指定其执行配置
- 对 global 函数的调用是异步的,这意味着其在设备完成执行之前返回
__device__关键字
- 在设备上执行
- 只能从设备调用
- __global__ 和 __device__ 执行空间说明符不能一起使用
__host__关键字
- 在主机上执行
- 只能从主机调用
- __global__ 和 __host__ 执行空间说明符不能一起使用
- __device__ 和 __host__ 执行空间说明符可以一起使用,此时该函数是为主机和设备编译的
四、device管理
4.1 初始化
当第一次调用任何CUDA运行时API(如cudaMalloc、cudaMemcpy等)时,CUDA Runtime会被初始化。这个初始化过程包括设置必要的内部数据结构、分配资源等,以便CUDA运行时能够管理后续的CUDA操作
每个CUDA设备都有一个与之关联的主上下文。主上下文是设备上的默认上下文,当没有显式创建任何上下文时,所有的CUDA运行时API调用都会在该主上下文中执行。主上下文包含了设备上的全局资源,如内存、纹理、表面等
开发者可以在程序启动时显式地指定哪个GPU成为"默认"设备。这个变化通常通过设置环境变量CUDA_VISIBLE_DEVICES或在程序中使用CUDA API(如cudaSetDevice)显式选择设备来实现。一旦选择了设备,随后的CUDA运行时初始化就会在这个指定的设备上创建主上下文
在没有显式指定设备的情况下,CUDA程序会默认在编号为0的设备(通常是第一个检测到的GPU)上执行操作
可以设置环境变量CUDA_VISIBLE_DEVICES-2来屏蔽其他GPU,这样只有GPU2能被使用。也可以使用CUDA_VISIBLE_DEVICES-2,3来设置多个GPU,其 device ID 分别为0和1
cudaDeviceReset
其作用是重置当前线程所关联的CUDA设备的状态,并释放该设备上所有已分配并未释放的资源
使用场景:
- 在程序结束时,调用该函数可以确保所有已分配的GPU资源都被正确释放,避免内存泄漏
- 若在程序的执行过程中遇到错误或需要中途退出,可释放已分配的资源,确保设备状态正确
- 在某些情况下,若设备状态出错(如由于之前的错误操作导致设备进入不可预测的状态),调用该函数可以尝试恢复设备到一个可用的状态
注意:
- 在调用该函数前,应确保所有已分配的设备内存和其他资源都已被正确地处理(如过cudaFree释放内存)。尽管其会释放这些资源,但最好还是在代码中显式地进行释放,以提高代码的可读性和可维护性
- 调用该函数后,当前线程与设备的关联关系可能会被重置。若需要继续使用设备,可能需要重新调用cudaSetDevice来设置当前线程要使用的设备
4.2 Runtime API查询GPU信息
cudaError_t cudaGetDeviceProperties(cudaDeviceProp *prop, int device);
GPU的信息被存放在cudaDeviceProp结构体中
#include <cuda_runtime_api.h>
#include <iostream>
#include <cmath>
using namespace std;int main()
{// 获取GPU数量int deviceCount = 0;cudaError_t errorId = cudaGetDeviceCount(&deviceCount);if (errorId != cudaSuccess) {printf("cudaGetDeviceCount returned %d\n-> %s\n", static_cast<int>(errorId), cudaGetErrorString(errorId));printf("Result = FAIL\n");exit(EXIT_FAILURE);}if (deviceCount == 0) {printf("There are no available device(s) that support CUDA\n");} else {printf("Detected %d CUDA Capable device(s)\n", deviceCount);}// 指定第一个GPUint device = 0;cudaSetDevice(device);// 获取GPU信息cudaDeviceProp deviceProp;cudaGetDeviceProperties(&deviceProp, device);int driverVersion = 0, runtimeVersion = 0;cudaDriverGetVersion(&driverVersion);cudaRuntimeGetVersion(&runtimeVersion);// 打印信息printf(" Device %d: \"%s\"\n", device, deviceProp.name);printf(" CUDA Driver Version / Runtime Version %d.%d / %d.%d\n", driverVersion/1000, (driverVersion%100)/10,runtimeVersion/1000, (runtimeVersion%100) / 10);printf(" CUDA Capability Major/Minor version number: %d.%d\n", deviceProp.major, deviceProp.minor);printf(" 全局内存总量: %.2f MBytes (%llu bytes)\n", (float)deviceProp.totalGlobalMem/(pow(1024.0,3)), static_cast<unsigned long long>(deviceProp.totalGlobalMem));printf(" GPU Clock rate: %.0f MHz (%0.2f GHz)\n", deviceProp.clockRate * 1e-3f, deviceProp.clockRate * 1e-6f);printf(" Memory Clock rate: %.0f Mhz\n", deviceProp.memoryClockRate * 1e-3f);printf(" Memory Bus Width: %d-bit\n", deviceProp.memoryBusWidth);if (deviceProp.l2CacheSize) {printf(" L2 Cache Size: %d bytes\n",deviceProp.l2CacheSize);}printf(" Max Texture Dimension Size (x,y,z) 1D=(%d), 2D=(%d,%d), 3D=(%d,%d,%d)\n",deviceProp.maxTexture1D , deviceProp.maxTexture2D[0],deviceProp.maxTexture2D[1],deviceProp.maxTexture3D[0], deviceProp.maxTexture3D[1],deviceProp.maxTexture3D[2]);printf(" Max Layered Texture Size (dim) x layers 1D=(%d) x %d, 2D=(%d,%d) x %d\n",deviceProp.maxTexture1DLayered[0], deviceProp.maxTexture1DLayered[1],deviceProp.maxTexture2DLayered[0], deviceProp.maxTexture2DLayered[1],deviceProp.maxTexture2DLayered[2]);printf(" 常量内存总量: %lu bytes\n",deviceProp.totalConstMem);printf(" 每个块的共享内存总量: %lu bytes\n",deviceProp.sharedMemPerBlock);printf(" 每个块可用的寄存器总数: %d\n",deviceProp.regsPerBlock);printf(" Warp size: %d\n", deviceProp.warpSize);printf(" 每个多处理器的最大线程数: %d\n",deviceProp.maxThreadsPerMultiProcessor);printf(" 每个块的最大线程数: %d\n",deviceProp.maxThreadsPerBlock);printf(" 块各维度的最大尺寸: %d x %d x %d\n", deviceProp.maxThreadsDim[0], deviceProp.maxThreadsDim[1], deviceProp.maxThreadsDim[2]);printf(" 网格每个维度的最大尺寸: %d x %d x %d\n", deviceProp.maxGridSize[0], deviceProp.maxGridSize[1], deviceProp.maxGridSize[2]);printf(" Maximum memory pitch: %lu bytes\n", deviceProp.memPitch);return 0;
}

4.3 决定最佳GPU
对于支持多GPU的系统,需从中选择一个来作为device,抉择出最佳计算性能GPU的一种方法就是由其拥有的处理器数量决定
int main()
{int numDevices = 0;cudaGetDeviceCount(&numDevices);if (numDevices > 1) {int maxMultiprocessors = 0, maxDevice = 0;for (int device=0; device < numDevices; ++device) {cudaDeviceProp props;cudaGetDeviceProperties(&props, device);if (maxMultiprocessors < props.multiProcessorCount) {maxMultiprocessors = props.multiProcessorCount;maxDevice = device;}}cudaSetDevice(maxDevice);} return 0;
}
相关文章:
【CUDA】认识CUDA
目录 一、CUDA编程 二、第一个CUDA程序 三、CUDA关键字 四、device管理 4.1 初始化 4.2 Runtime API查询GPU信息 4.3 决定最佳GPU CUDA C 编程指南CUDA C在线文档:CUDA C 编程指南 CUDA是并行计算的平台和类C编程模型,能很容易的实现并行算法。只…...
Linux(CentOS)yum update -y 事故
CentOS版本:CentOS 7 事情经过: 1、安装好CentOS 7,系统自带JDK8,版本为:1.8.0_181 2、安装好JDK17,版本为:17.0.13 3、为了安装MySQL执行了 yum update -y(这个时候不知道该命令的…...
AI绘画赚钱秘籍!掌握ai绘画赚钱技巧,开启副业新篇章,ai绘画赚钱实战指南!
AI绘画赚钱:方法与策略 一、引言 随着人工智能技术的日益发展,AI绘画作为新兴领域,正逐渐成为赚钱的新途径。本文将从多个角度探讨AI绘画赚钱的完整策略,帮助读者深入了解并把握这一领域的商机。 二、AI绘画赚钱的主要方式…...
HCIP-HarmonyOS Application Developer V1.0 笔记(四)
平板/折叠屏设计 自适应动态布局:相对拉伸、相对缩放、延伸布局 响应式动态布局:挪移布局、重复布局、瀑布布局 Sketch 插件 设计系统:提供了 HarmonyOS 设计语言中定义的视觉参数和设计资源文件。 控件库:按类别组织控件&…...
【前端】Svelte:组件封装与使用
在 Svelte 中,组件化是开发的核心理念。将页面的不同部分封装成独立组件,不仅可以提升代码的复用性,还能让项目的结构更加清晰。在本文中,我们将介绍如何创建、封装、引入和使用 Svelte 组件,帮助你快速上手 Svelte 的…...
STM32标准库-待机模式
1.1 STM32待机模式简介 STM32单片机具有低功耗模式,包括睡眠、停止和待机三种。 运行状态下,HCLK为CPU提供时钟。HCLK由AHB预分频器分频后直接输出得到。 低功耗模式选择需考虑电源消耗、启动时间和唤醒源。 睡眠模式停CPU不停外设时钟; 停止…...
【论文笔记】The Power of Scale for Parameter-Efficient Prompt Tuning
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: The Power of Scale for P…...
几个docker可用的镜像源
几个docker可用的镜像源 💐The Begin💐点点关注,收藏不迷路💐 sudo rm -rf /etc/docker/daemon.json sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://d…...
Spring学习笔记_27——@EnableLoadTimeWeaving
EnableLoadTimeWeaving 1. 介绍 在Spring框架中,EnableLoadTimeWeaving 是一个注解,它用于启用加载时织入(Load-Time Weaving, LTW) LWT[Spring学习笔记_26——LWT-CSDN博客] 2. 场景 AOP:在Spring框架中…...
【数据分析】如何构建指标体系?
有哪些指标体系搭建模型?五个步骤教你从0开始搭建指标体系 一、企业指标体系搭建存在什么问题 许多企业在搭建数据指标体系时遇到了诸多难题,如问题定位不准确、数据采集不完整、目标不一致、报表无序、指标覆盖不全面以及报表价值未充分利用等。 1、…...
大数据程序猿不可不看的资料大全
随着大数据技术的发展,大数据程序猿在数据采集、处理、分析、存储等方面的技能需求不断增加。要在这个领域保持竞争力,系统性地学习和掌握大数据工具、技术架构和行业趋势是非常重要的。以下为您提供一份围绕大数据程序猿不可不看的资料大全…...
【架构设计常见技术】
EJB EJB是服务器端的组件模型,使开发者能够构建可扩展、分布式的业务逻辑组件。这些组件运行在EJB容器中,EJB将各功能模块封装成独立的组件,能够被不同的客户端应用程序调用,简化开发过程,支持分布式应用开发。 IOC …...
LLMs之MemFree:MemFree的简介、安装和使用方法、案例应用之详细攻略
LLMs之MemFree:MemFree的简介、安装和使用方法、案例应用之详细攻略 目录 MemFree的简介 1、MemFree的价值 2、MemFree 配备了强大的功能,可满足各种搜索和生产力需求 3、MemFree AI UI生成器功能 MemFree 安装和使用方法 1. 前端安装 2. 向量服务…...
Hive简介 | 体系结构
Hive简介 Hive 是一个框架,可以通过编写sql的方式,自动的编译为MR任务的一个工具。 在这个世界上,会写SQL的人远远大于会写java代码的人,所以假如可以将MR通过sql实现,这个将是一个巨大的市场,FaceBook就这…...
[C++] GDB的调试和自动化检测
文章目录 GDB基本使用1. bazel的debug过程2. line-tables-only的使用 Reference GDB基本使用 参考文档: https://zhuanlan.zhihu.com/p/655719314 1. bazel的debug过程 需要带--copt-g --copt-ggdb选项进行编译 // bazel build --stripnever --copt-g --copt-ggd…...
车机版 Android Audio 框架笔记
车机版Android Audio 框架涉及的知识点很多,在工作中涉及的功能板块也及其繁杂,后面我会根据工作中的一些实际遇到的实例,逐步拆解 Android Audio的知识点,这里从网上整理了一些思维导图,可以做为未来的一个研究方向&a…...
【NLP自然语言处理】深入解析Encoder与Decoder模块:结构、作用与深度学习应用
目录 🍔 Encoder模块 1.1 Encoder模块的结构和作用 1.2 关于Encoder Block 1.3 多头自注意力层(self-attention) 🍔 Decoder模块及Add & Norm模块 3.1 Decoder模块介绍 3.2 Add & Norm模块 3.3 位置编码器Positional Encoding 3.4 Decod…...
【JAVA EE】多线程、锁、线程池的使用
目录 创建线程 方法一:继承Thread类来创建一个线程类 方法二:实现Runnable,重写run 线程等待 获取当前线程引用 休眠当前线程 线程的状态 synchronized synchronized的特性 1、互斥 2、刷新内存 死锁 死锁的四个必要条件 避免死…...
云计算:定义、类型及对企业的影响
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 云计算:定义、类型及对企业的影响 云计算:定义、类型及对企业的影响 云计算:定义、类型及对企…...
大数据面试题--kafka夺命连环问
1、kafka消息发送的流程? 在消息发送过程中涉及到两个线程:一个是 main 线程和一个 sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给双端队列,sender 线程不断从双端队列 RecordAccumulator 中拉取…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
