【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 中拉取…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...