CUDA 学习(2)——CUDA 介绍

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.rhkb.cn/news/38102.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言【文件操作】详解中

引言 介绍和文件操作中文件的顺序读写相关的函数 看这篇博文前&#xff0c;希望您先仔细看一下这篇博文&#xff0c;理解一下文件指针和流的概念&#xff1a;C语言【文件操作】详解上-CSDN博客文章浏览阅读606次&#xff0c;点赞26次&#xff0c;收藏4次。先整体认识一下文件是…

损失函数理解(二)——交叉熵损失

损失函数的目的是为了定量描述不同模型&#xff08;例如神经网络模型和人脑模型&#xff09;的差异。 交叉熵&#xff0c;顾名思义&#xff0c;与熵有关&#xff0c;先把模型换成熵这么一个数值&#xff0c;然后用这个数值比较不同模型之间的差异。 为什么要做这一步转换&…

学习笔记--基于Sa-Token 实现Java项目单点登录+同端互斥检测

目录 同端互斥登录 单点登录SSO 架构选型 模式二: URL重定向传播 前后端分离 整体流程 准备工作 搭建客户端 搭建认证中心SSO Server 环境配置 开放认证接口 启动类 跨域处理 同端互斥登录 同端互斥登陆 模块 同端互斥登录指&#xff1a;同一类型设备上只允许单地…

蓝桥杯 小球反弹

问题描述 有一个长方形&#xff0c;长为 343720 单位长度&#xff0c;宽为 233333 单位长度。 在其内部左上角顶点有一小球&#xff08;无视其体积&#xff09;&#xff0c;其初速度方向如图所示&#xff0c;且保持运动速率不变。分解到长宽两个方向上的速率之比为&#xff1…

PyCharm中使用pip安装PyTorch(从0开始仅需两步)

无需 anaconda&#xff0c;只使用 pip 也可以在 PyCharm 集成环境中配置深度学习 PyTorch。 本文全部信息及示范来自 PyTorch 官网。 以防你是super小白&#xff1a; PyCharm 中的命令是在 Python Console 中运行&#xff0c;界面左下角竖排图标第一个。 1. 安装前置包 numpy …

在刀刃上发力:如何精准把握计划关键节点

关键路径分析是项目管理中的一种重要方法&#xff0c;它通过在甘特图中识别出项目中最长、最关键的路径&#xff0c;来确定项目的最短完成时间。 关键路径上的任务都是项目成功的关键因素&#xff0c;任何延误都可能导致整个项目的延期。关键路径分析对于项目管理者来说至关重要…

Burp Suite 代理配置全流程指南

目录 一、基础环境准备 1.1 安装与启动 1.2 环境变量配置 二、核心代理配置 2.1 Burp 代理监听设置 2.2 浏览器代理配置 Firefox Chrome/Edge 代理插件推荐 三、HTTPS 流量拦截 3.1 证书安装流程 3.2 移动端配置 四、高级功能应用 4.1 流量操作 4.2 HTTP 历史记…

【数据分享】我国乡镇(街道)行政区划数据(免费获取/Shp格式)

行政区划边界矢量数据是我们在各项研究中最常用的数据。之前我们分享过2024年我国省市县行政区划矢量数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff0c;很多小伙伴拿到数据后咨询有没有精细到乡镇&#xff08;街道&#xff09;的行政区划矢量数据&#xff01;…

考研复习之队列

循环队列 队列为满的条件 队列为满的条件需要特殊处理&#xff0c;因为当队列满时&#xff0c;队尾指针的下一个位置应该是队头指针。但是&#xff0c;我们不能直接比较 rear 1 和 front 是否相等&#xff0c;因为 rear 1 可能会超出数组索引的范围。因此&#xff0c;我们需…

如果我没安装office,只安装了wps,python 如何通过win32com.client.Dispatch操作ppt?

文章目录 win32com.client.Dispatch是干嘛的?什么是Windows COM组件COM和dll有关系吗?python 如何通过win32com.client.Dispatch操作ppt?如果我没安装office,只安装了wps,python 如何通过win32com.client.Dispatch操作ppt?附录:完整报错信息win32com.client.Dispatch是干…

介绍一个测试boostrap表格插件的好网站!

最近在开发一个物业管理系统。用到bootstrap的表格插件bootstrap table&#xff0c;官方地址&#xff1a; https://bootstrap-table.com/ 因为是英文界面&#xff0c;对国人不是很友好。后来发现了小书童网站 IT小书童 - 为程序员提供优质教程和文档 网站&#xff1a; IT小…

七、服务器远程桌面报错

&#x1f33b;&#x1f33b;目录&#x1f33b;&#x1f33b; 一、远程桌面报错-用户账户限制&#xff08;例如&#xff0c;时间限制&#xff09;会阻止你登录。 一、远程桌面报错-用户账户限制&#xff08;例如&#xff0c;时间限制&#xff09;会阻止你登录。 原因是被远程的系…

不做颠覆者,甘为连接器,在技术叠层中培育智能新物种

--- 一、技术融合的必然&#xff1a;从“非此即彼”到“兼容共生” 当大模型的热浪撞上传统IT的礁石&#xff0c;企业智能化的真相浮出水面&#xff1a; 新旧技术的“量子纠缠”&#xff1a;MySQL与向量数据库共享数据总线&#xff0c;规则引擎与大模型共处决策链路 需求进…

# [RPA] 使用八爪鱼进行高效网页数据采集

在许多行业中&#xff0c;数据是核心资产。然而&#xff0c;虽然许多网站的文本内容可以免费访问&#xff0c;但手动一条一条采集&#xff0c;不仅耗时耗力&#xff0c;还容易出错。这种情况下&#xff0c;使用自动化工具来提高采集效率就显得尤为重要。本文将介绍 八爪鱼 这一…

Blazor+PWA技术打造全平台音乐播放器-从音频缓存到离线播放的实践之路

基于PWA技术打造全平台音乐播放器&#xff1a;从音频缓存到离线播放的实践之路 这篇文章是自己的想法结合AI之后润色的。在数字音乐领域&#xff0c;用户期望随时随地享受音乐&#xff0c;无论是手机还是电脑&#xff0c;无论是在线还是离线。**渐进式Web应用&#xff08;PWA&…

众乐影音-安卓NAS-Player的安装和设置说明

众乐影音是耘想公司基于原有的安卓NAS&#xff0c;增加影音和图片播放功能后&#xff0c;推出的一款新概念NAS-Player。它不仅可以接收手机端推送的视频&#xff0c;音频和图片文件进行播放&#xff0c;还可以把任何一台安卓设备&#xff0c;比如手机、机顶盒、各种安卓盒子等&…

Linux shell脚本-概述、语法定义、自定义变量、环境变量、预设变量、变量的特殊用法(转义字符、单双引号、大小括号)的验证

目录 1.shell概述 1.1作为应用程序&#xff1a; 1.2 shell 作为一门语言 2.shell 语法 2.1 shell脚本的定义与执行 &#xff08;1&#xff09;新建文件 &#xff08;2&#xff09;程序开头第一行 必须写shell的类型 &#xff08;3&#xff09;程序编写完后&#xff0c…

redis集群的原理是什么?

大家好&#xff0c;我是锋哥。今天分享关于【redis集群的原理是什么?】面试题。希望对大家有帮助&#xff1b; redis集群的原理是什么? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 集群&#xff08;Redis Cluster&#xff09;是一种分布式解决方案&…

PicFlow:一个图片处理与上传工作流工具(图床上传工具)

自从学习搭建网站以来&#xff0c;我就把很多图片托管在七牛云等图床平台上。以前总是通过网页批量上传&#xff0c;需要登录并一步步跳转网页操作&#xff0c;久而久之就厌烦了&#xff0c;于是花了一天时间用 Python 写了一个工具 —— PicFlow&#xff0c;从名字可以看出&am…

常⻅CMS漏洞之一:WordPress

WordPress是⼀个以PHP和MySQL为平台的⾃由开源的博客软件和内容管理系统。WordPress具有插件架构和模板系统。截⾄2018年4⽉&#xff0c;排名前1000万的⽹站中超过30.6%使⽤WordPress。 WordPress是最受欢迎的⽹站 内容管理系统。全球有⼤约30%的⽹站(7亿5000个)都是使⽤WordP…