CUDA 学习(2)——CUDA 介绍

news2025/3/31 4:58:17

GeForce 256 是英伟达 1999 年开发的第一个 GPU,最初用作显示器上渲染高端图形,只用于像素计算。

在早期,OpenGL 和 DirectX 等图形 API 是与 GPU 唯一的交互方式。后来,人们意识到 GPU 除了用于渲染图形图像外,还可以做其他的数学计算,但是 OpenGL 和 DirectX 等图形 API 的交互方式比较复杂,不利于程序员设计 GPU 计算程序,这促成了 CUDA 编程框架的开发,它提供了一种与 GPU 交互的简单而高效的方式。

1 CUDA 环境搭建

必要的条件:

  • Nvidia 的 GPU
  • Nvidia 的显卡驱动
  • 标准的 C 编译器
  • CUDA 开发工具

建立好 CUDA 开发环境之后,可以通过以下命令进行检查:

nvidia-smi
nvcc --version

2 CUDA 编程模型简述

2.1 基本概念
  • thread:一个 CUDA 的并行程序会被以许多个 thread 来执行
  • block: 多个线程组成一个线程块(Block),同一个 block 的线程会被调度到同一个 SM 上,即同一个 block 的 thread 可以进行同步并可用 SM 上的 share memory 通信,不同 block 的 thread 无法通信
  • grid: CUDA 的一个函数叫做一个 kernel,一个 kernel 会发起大量执行相同指令的线程

CUDA 编程软件层次:

在这里插入图片描述

这三个概念是 CUDA 编程中最核心的,知道这些,就已经可以写 cuda 代码了,进一步了解硬件结构可以帮助我们更好地对 cuda 代码深度优化。

2.2 helloGPU

尝试编写一个 cuda 程序 hello-gpu.cu,让 GPU 输出Hello World!

#include <stdio.h>

void helloCPU() {
    printf("Hello World!  --From CPU\n");
}

__global__ void helloGPU() {
    printf("Hello World!  --From GPU\n");
}

int main() {
    helloCPU();
    helloGPU<<<1, 1>>>();
    cudaDeviceSynchronize();
}

可以看到 cuda 程序和普通的 c 语言非常相似,也存在一些不一样的地方:

  • __global__:定义这是一个 cuda 的 kernel 函数,从主机 host 发起并在设备 device 上执行。
  • <<<1, 1>>>:定义 block 和 threads,这里表示发起 1 个 block,每个 block 里有 1 个线程
  • cudaDeviceSynchronize:与许多 C/C++ 代码不同,核函数启动方式为异步:CPU 代码将继续执行而无需等待核函数完成启动。调用 CUDA 运行时提供的函数 cudaDeviceSynchronize 将导致主机 (CPU) 代码暂作等待,直至设备 (GPU) 代码执行完成,才能在 CPU 上恢复执行。

写好 cuda 代码后,可以使用 nvcc 对代码进行编译与执行:

nvcc -arch=sm_75 -o hello-gpu hello-gpu.cu -run

# Hello World!  --From CPU
# Hello World!  --From GPU

说明:

  • nvcc 是使用 nvcc 编译器的命令行命令。
  • xxx.cu 作为文件传递以进行编译。
  • -o标志用于指定编译程序的输出文件。
  • arch 标志表示该文件必须编译为哪个架构类型。本示例中,sm_75 将用于专门针对本实验运行的 NVIDIA GeForce GTX 2080 Ti 进行编译。具体参考:https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#options-for-steering-gpu-code-generation
  • 为方便起见,提供 run 标志将执行已成功编译的二进制文件。

从上面的程序,可以知道 GPU 的工作任务是由 CPU 触发的,GPU 自身是无法独立工作的。

cuda 程序整体的工作流程是 CPU 将需要执行的任务异步地交给 GPU,再由 GPU 进行调度,最后再将计算结果同步给 CPU。

在这里插入图片描述

假设想要 GPU 发送 66 个Hello World,可以简单地修改 blocks 和 ThreadsPerBlock 的数量,即可实现这项功能:

#include <stdio.h>

void helloCPU() {
    printf("Hello World!  --From CPU\n");
}

__global__ void helloGPU() {
    printf("Hello World!  --From GPU\n");
}

int main() {
    helloCPU();
    helloGPU<<<6, 11>>>();
    cudaDeviceSynchronize();
}

以上代码则发起了 6 个 block,每个 block 里有 11 个线程。当然,也可以改成helloGPU<<<1, 66>>>();,发起了一个 block,这个 block 里有 66 个线程。

3 Warp

具体怎么设置发起 blocks 和 ThreadsPerBlock 完全由程序员自己设置,而发起后这些 block 和线程在 GPU 中如何调度则由 GPU 内部硬件控制,不被程序员所操作。为了更合理地设置 blocks 和 ThreadsPerBlock,还需要了解 GPU 中的调度策略。

  • 首先是 blocks 的调度:同一个 blocks 会被调度到同一个 SM,不同的 blocks 不保证在同一 SM

为了更好地进行调度,blocks 数可以设置为 GPU 中 SM 的整数倍。由于 SM 上的计算单元是有限的,同一个 blocks 中的 threads 会被划分成多个 warp,一个 warp 才是 GPU 调度与执行的基本单元

一般来说,一个 warp 是 32 个线程(尽量是每个 SM 中的流处理器数量的整倍数?),所以 ThreadsPerBlock 一般会设置成 32 的整数倍,可以让资源利用率更高。

了解了 GPU 中的调度逻辑,编写 cuda 程序时我们就可以根据手中的 GPU 硬件配置,合理地设置 blocks 和 ThreadsPerBlock 这两个参数。当前 GPU 硬件配置有很多内容,在初学 CUDA 编程中应该关注到的是 GPU 上 SM 数量,warp size,每个 block 的最大线程数,每个 SM 最大 block 数。通过这段代码将 GPU 硬件信息打印出来:

#include <stdio.h>
#include <iostream>

int main() {
    int dev = 0;
    cudaDeviceProp devProp;
    cudaGetDeviceProperties(&devProp, dev);
    
    std::cout << "使用 GPU device " << dev << ": " << devProp.name << std::endl;
    std::cout << "SM 的数量:" << devProp.multiProcessorCount << std::endl;
    
    int warpSize = devProp.warpSize;
    std::cout << "Warp size: " << warpSize << std::endl;
    std::cout << "每个线程块的共享内存大小:" << devProp.sharedMemPerBlock / 1024.0 << " KB" << std::endl;
    std::cout << "每个线程块的最大线程数:" << devProp.maxThreadsPerBlock << std::endl;
    std::cout << "每个 SM 的最大线程数:" << devProp.maxThreadsPerMultiProcessor << std::endl;
    std::cout << "每个 SM 的最大 block 数:" << devProp.maxThreadsPerMultiProcessor / warpSize << std::endl;
    std::cout << "每个 SM 的寄存器数量:" << devProp.regsPerMultiprocessor << std::endl;
}

编译梦并运行:

nvcc -o get_gpu_hwinfo get_gpu_hwinfo.cu -run

使用 GPU device 0: NVIDIA GeForce RTX 2080 Ti
SM 的数量:68
Warp size: 32
每个线程块的共享内存大小:48 KB
每个线程块的最大线程数:1024
每个 SM 的最大线程数:1024
每个 SM 的最大 block 数:32
每个 SM 的寄存器数量:65536

举一个简单的例子来说明如何根据硬件配置合理分配资源:

假设一个 SM 上有 8192 个寄存器,程序员每个 block 设置了 256 个线程。

假设每个线程会占用 10 个寄存器,那么一个 block 中的线程会占用 256*10=2560 个寄存器,8192/2560=3.2,即一个 SM 可以同时加载 3 个 block 正常运行。

假设每个线程会占用 11 个寄存器,那么一个 block 中的线程会占用 256*11=2816 个寄存器,8192/2816=2.9,即一个 SM 只能加载 2 个 block,一个 SM 上硬件资源就跑不满,会造成资源浪费。

blocks 调度到 SM 上:

在这里插入图片描述

block 被切分成 wrap:

在这里插入图片描述

由于 GPU 没有复杂的控制单元,在 warp 中所有线程都会执行相同的指令,这意味着在遇到分支时,warp 需要一些特殊的处理。

如下图所示,当遇到分支时,warp 中 32 个线程也许有些线程满足条件,有些线程不满足条件,但一个 warp 中所有线程执行指令的时序是一致的,不满足分支条件的线程必须等待需要执行指令的其他线程,这也意味着分支指令会影响 GPU 的运行效率,在程序设计时应该尽量少用,或者在写分支条件时尽可能保证一个 warp 中所有线程同时满足条件或者同时不满足条件。

在这里插入图片描述

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

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

相关文章

棱镜七彩受邀出席“供应链安全国家标准贯标应用深度行”活动并做主题分享

近日&#xff0c;“供应链安全国家标准贯标应用深度行”活动在北京顺利举办&#xff0c;此次活动汇聚了行业内的众多专家和企业代表&#xff0c;深入探讨了供应链安全国家标准的制定与实施路径。棱镜七彩副总裁黄浩东受邀出席&#xff0c;并发表了题为《国家标准实施路径下的企…

系统转换、系统维护、净室软件工程、构件软件工程(高软51)

系列文章目录 系统转换、系统维护、净室软件工程、构件软件工程 文章目录 系列文章目录前言一、系统转换二、系统维护三、净室软件工程四、基于构件的软件工程总结 前言 本节讲明遗留系统的系统转换、系统维护、净室软件工程、基于构件软件工程相关知识。 一、系统转换 就是讲…

联核防爆无人叉车:高危环境中的安全搬运守护者

联核防爆AGV无人叉车是专为易燃易爆环境设计的智能搬运设备&#xff0c;其特点、功能与应用场景均围绕“安全”与“智能”核心展开&#xff1a;联核科技官网-AGV叉车十大品牌-无人叉车厂家-自动化叉车-智能搬运码垛机器人-智能叉车系统解决方案专家 一、核心特点 防爆设计电气…

23种设计模式-责任链(Chain of Responsibility)设计模式

责任链设计模式 &#x1f6a9;什么是责任链设计模式&#xff1f;&#x1f6a9;责任链设计模式的特点&#x1f6a9;责任链设计模式的结构&#x1f6a9;责任链设计模式的优缺点&#x1f6a9;责任链设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是…

Linux使用集群服务器查看已安装conda环境,且环境名无显示、系统环境混乱等问题

一、问题 在使用集群服务器前可以查看导入&#xff0c;module load不需要安装。我都是自己重新下载Anaconda3-2024.10-1-Linux-x86_64.sh&#xff0c;然后安装&#xff0c;导致混乱。下面是情况 1.创建的环境名跑到目录下了 2.多个base,且有个base无显示 二、解决办法 1.删…

python蓝桥杯刷题的重难点知识笔记

1、datetime模块 datetime.date&#xff1a;代表日期&#xff0c;包含年、月、日信息。datetime.time&#xff1a;代表时间&#xff0c;包含时、分、秒、微秒信息。datetime.datetime&#xff1a;结合了日期和时间&#xff0c;包含年、月、日、时、分、秒、微秒信息。datetime.…

Android平台毫秒级低延迟HTTP-FLV直播播放器技术探究与实现

一、前言 在移动互联网蓬勃发展的今天&#xff0c;视频播放功能已成为众多Android应用的核心特性之一。面对多样化的视频格式和传输协议&#xff0c;开发一款高效、稳定的视频播放器是许多开发者追求的目标。FLV&#xff08;Flash Video&#xff09;格式&#xff0c;尽管随着H…

极光优化PLO-Transformer-LSTM多变量时序

极光优化算法(PLO)于2024年8月发表于SCI期刊《Neurocomputing》&#xff0c;利用算法极光优化算法PLO优化Transformer-LSTM模型&#xff0c;同时提供与未优化模型的对比&#xff0c;包含柱状图、两张雷达图、二维散点图等等。 &#xff08;一&#xff09;LSTM模型LSTM是一种在时…

基于javaweb的SpringBoot智能无人仓库管理设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

python处理音频相关的库

1 音频信号采集与播放 pyaudio import sys import pyaudio import wave import timeCHUNK 1024 FORMAT pyaudio.paInt16 CHANNELS 1#仅支持单声道 RATE 16000 RECORD_SECONDS 3#更改录音时长#录音函数&#xff0c;生成wav文件 def record(file_name):try:os.close(file_…

网络爬虫-2:基础与理论

一.同步加载与异步加载 1.1同步加载定义: 页面所有内容一起加载出来,当某一个数据加载有问题,整个页面就不会加载出来(如HiFiNi音乐网站),所以又叫阻塞模式 1.2爬取步骤: 看netword->document 2.1异步加载定义: 数据是分开加载的,当某一份数据有异常时,不影响其他数据…

[项目]基于FreeRTOS的STM32四轴飞行器: 十一.MPU6050配置与读取

基于FreeRTOS的STM32四轴飞行器: 十一.MPU6050 一.芯片介绍二.配置I2C三.编写驱动四.读取任务的测试五.MPU6050六轴数据的校准 一.芯片介绍 芯片应该放置在PCB中间&#xff0c;X Y轴原点&#xff0c;敏感度131表示范围越小越灵敏。理想状态放置在地面上X&#xff0c;Y&#xf…

后端学习day1-Spring(八股)--还剩9个没看

一、Spring 1.请你说说Spring的核心是什么 参考答案 Spring框架包含众多模块&#xff0c;如Core、Testing、Data Access、Web Servlet等&#xff0c;其中Core是整个Spring框架的核心模块。Core模块提供了IoC容器、AOP功能、数据绑定、类型转换等一系列的基础功能&#xff0c;…

【赵渝强老师】在Docker中运行达梦数据库

Docker是一个客户端服务器&#xff08;Client-Server&#xff09;架构。Docker客户端和Docker守护进程交流&#xff0c;而Docker的守护进程是运作Docker的核心&#xff0c;起着非常重要的作用&#xff08;如构建、运行和分发Docker容器等&#xff09;。达梦官方提供了DM 8在Doc…

Python电影市场特征:AR模型时间序列趋势预测、热图可视化评分影响分析IMDb数据|附数据代码

原文链接&#xff1a;https://tecdat.cn/?p41214 分析师&#xff1a;Zhiheng Lin 在数字时代&#xff0c;电影产业的数据分析已成为洞察市场趋势与用户偏好的重要工具。本专题合集聚焦印度电影市场&#xff0c;通过IMDb数据集&#xff08;IMDb Movies Dataset&#xff09;的深…

扭蛋机小程序开发,潮玩娱乐消费风口下的机遇

随着Z世代消费能力的提升和盲盒经济的火爆&#xff0c;扭蛋文化正迎来爆发式增长。 扭蛋机作为一种充满惊喜感的消费模式&#xff0c;正从线下走向线上&#xff0c;并借助移动互联网实现了数字化转型。线上扭蛋机小程序不仅延续了传统扭蛋的趣味性&#xff0c;还通过数字化手段…

各类神经网络学习:(五)LSTM 长短期记忆(上集),结构详解

上一篇下一篇RNN&#xff08;下集&#xff09;待编写 LSTM&#xff08;长短期记忆&#xff09; 参考知乎文章《人人都能看懂的LSTM介绍及反向传播算法推导&#xff08;非常详细&#xff09; - 知乎》&#xff0c;部分图片也进行了引用。 参考视频教程《3.结合例子理解LSTM_哔哩…

计算机网络-2 物理层

【考纲内容】 &#xff08;一&#xff09;通信基础 信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念&#xff1b; 奈奎斯特定理与香农定理&#xff1b;编码与调制&#xff1b; 电路交换、报文交换与分组交换&#xff1b;数据报与虚电路① 视频讲解 &#xff08;二…

Redis集群哨兵相关面试题

目录 1.Redis 主从复制的实现原理是什么? 详解 补充增量同步 replication buffer repl backlog buffer 2.Redis 主从复制的常见拓扑结构有哪些? 3.Redis 复制延迟的常见原因有哪些? 4.Redis 的哨兵机制是什么? 主观下线和客观下线 哨兵leader如何选出来的&#x…