通用图形处理器设计GPGPU基础与架构(二)

一、前言

        本系列旨在介绍通用图形处理器设计GPGPU的基础与架构,因此在介绍GPGPU具体架构之前,需要了解GPGPU的编程模型,了解软件层面是怎么做到并行的,硬件层面又要怎么配合软件,乃至定出合适的架构来实现软硬件协同。

二、通用编程背景

       为了满足人们对GPU进行通用编程的需求,NVIDIA 公司于2007年发布了CUDA(Compute Unified Device Architecture,计算统一设备体系结构),支持编程人员利用更为通用的方式对GPU进行编程,更好地发挥底层硬件强大的计算能力,从而高效地解决各领域中的计算问题和任务。随后,苹果、AMD IBM 等公司也推出了OpenCL(Open Computing Language,开放运算语言)标准。该标准成为第一个面向异构系统通用并行编程的免费标准,适用于多核CPU GPGPU等多种异构并行系统。

三、GPGPU计算模型

       本主要以CUDA并行编程中的一些架构概念来展示GPGPU的计算和存储模型。作为首个GPGPU编程模型,CUDA 定义了以主从方式结合单指令多线程(Single Instruction Multiple Threads,SIMT)硬件的多线程计算方式。

        以上图的矩阵乘法为例,矩阵C中每个元素都可以由一个输入矩阵A行向量和另一个输入矩阵B的列向量进行点积运算得到。C中每个元素的计算过程都可以独立进行,不存在依赖关系,因此具有良好的数据并行性。

        在GPGPU中,承担并行计算中每个计算任务的计算单元称为线程(Thread)每个线程在一次计算任务过程中会执行相同的指令。在上例矩阵乘法中,每个线程会从矩阵AB读取对应的行或列构成向量ab, 然后执行向量点积运算,最后将结果c存到结果矩阵C的对应位置。

        虽然每个线程输入数据不同,输出的结果也不同,但是每个线程需要执行的指令完全相同。也就是说, 一条指令被多个线程同时执行,这就是GPGPU 中的单指令多线程(Single Instruction Multiple Threads,SIMT)计算模型。

        为了针对复杂的大规模通用计算场景将不方便处理,CUDA 引入了线程网格(thread grid)、线程块(thread block)、线程(thread)。Thread Block由多个Thread组成,而Grid又由多个Thread Block组成。因此,它们的关系就是Grid > Block > Thread。

       在CUDA编程模型中,通常将代码划分为主机端(host)代码和设备端(device)代码,分别运行在CPUGPGPU上。CPU硬件执行主机端代码,GPGPU硬件将根据编程人员给定的线程网格组织方式将设备端代码分发到线程中。

       主机端代码通常分为三个步骤。①数据复制:CPU将主存中的数据复制到GPGPU中。②GPGPU动:CPU 唤醒GPGPU线程进行运算。③数据写回:GPGPU运算完毕将计算结果写回主机端存储器中。

       设备端代码常常由多个函数组成,这些函数被称为内核函数(kernel)。内核函数会被分配到每个GPGPU的线程中执行,而线程层次则由编程人员根据算法和数据的维度显式指定,如下图所示。

       基于上面的线程层次,编程人员需要知道线程在网格中的具体位置,才能读取合适的数据执行相应的计算。因此,CUDA引入了为每个线程指明其在线程网格中哪个线程块的 blockIdx(线程块索引号)和线程块中哪个位置threadIdx(线程索引号)。blockIdx有三个属性,x、y、z描述了该线程块所处线程网格结构中的位置。threadIdx 也有三个属性,xyz 描述了每个线程所处线程块中的位置。在一个Grid中:根据blockIdx和threadIdx,我们就能唯一锁定到某个线程,进而编程让其做具体计算。例如下面这段代码,调用线程进行了矩阵加法。

// Kernel定义
__global__ void MatAdd(float A[N][N], float B[N][N], float C[N][N]) 
{ int i = blockIdx.x * blockDim.x + threadIdx.x; int j = blockIdx.y * blockDim.y + threadIdx.y; if (i < N && j < N) C[i][j] = A[i][j] + B[i][j]; 
}

        矩阵加法计算时,数据之间没有依赖性,每个线程都是并行独立地操作数据。

        到此,可能会有个疑问,既然通用计算追根到底是索引到单个thread再做计算,那么假设没有block,我纯靠threadidx也能唯一索引到某个线程,block存在的意义到底是什么?。这就要引入共享存储器全局存储器的概念了

        首先,共享存储器的访问比全局存储器更快,共享存储器作用于一个线程块(thread block)内部,可以为同一个线程块内部的线程提供更快的数据访问。因此,通过合理划分块(block)的大小,可以充分利用数据的局部性原理减少对设备端全局存储器的访问,从而提高运算性能。此外,线程之间由于应用的特点可能不能完全独立。比如归约(reduction)操作需要邻近的线程之间频繁地交互数据,以协作的方式产生最终的结果,多个线程之间还可能需要相互同步,block的存在提高了线程之间的协作能力。

四、自线程到硬件结构

       为了实现对大量线程的分配,GPGPU 对硬件功能单元进行了层次化的组织,如图所示。

       它主要由流多处理器(Streaming MultiProcessor,SM)阵列和存储系统组成,两者由片上网络连接到L2高速缓存和设备端存储器上。每个流多处理器内部有多个流处理器(Streaming Processor,SP单元,构成一套完整的指令流水线,包含取指、译码、寄存器文件及数据加载/存储(load/store)单元等,并以SIMT 架构的方式进行组织。GPGPU的整体结构、SM 硬件 SP 硬件对应了线程网格、线程块和线程的概念,实现了线程硬件的对应分配规则。

五、存储模型                                    

       GPGPU利用大量的线程来提高运算的并行度,这些线程需要到全局存储器中索引相应的数据。为了减少对全局存储器的访问,GPGPU架构提供了多种存储器类型和多样的存储层次关系来提高kernel函数的执行效率,如下表所示。

Memory Description

CUDA Memory Name

所有的线程(或所有work-items)均可访问

global memory

只读存储器

constant memory

线程块(或work-group)内部线程访问

shared memory

单个线程(或work-item)可以访问

local memory

       CUDA 支持多种存储器类型,线程代码可以从不同的存储空间访问数据,提高内核函数的执行性能。每个线程都拥有自己独立的存储空间,包括寄存器文件(Register File)局部存储器(Local Memory),这些存储空间只有本线程才能访问。每个线程块允许内部线程访问共享存储器(Shared Memory)在块内进行线程间通信。线程网格内部的所有线程都能访问全局存储器(Global Memory),也可以访问纹理存储器(Texture Memory)常量存储器(Constant Memory)中的数据。

       ① 寄存器文件(Register File)是 SM 片上存储器中最为重要的一个部分,它提供了与计算内核相匹配的数据访问速度。大容量的寄存器文件能够让更多的线程同时保持在活跃状态。这样当流水线遇到一些长延时的操作时,GPGPU可以在多个线程束之间快速地切换来保持流水线始终处于工作状态。这种特性在GPGPU中被称为零开销线程束切换(zero-cost warp switching),可以有效地掩藏长延时操作,避免流水线的停顿。

       ② 局部存储器(Local Memory)是每个线程自己独立的存储空间局部存储器是私有的,只有本线程才能进行读写。

       ③ 共享存储器(Shared Memory)也是SM 片内的高速存储资源,它由一个线程块内部的所有线程共享。相比于全局存储器,共享存储器能够以类似于寄存器的访问速度读写其中的内容。

       ④ 全局存储器(Global Memory)位于设备端。GPGPU核函数的所有线程都可对其进行访问,但其访存时间开销较大。

       ⑤ 常量存储器(Constant Memory)位于设备端存储器中,其中的数据还可以缓存在SM部的常量缓存(Constant Cache)中,所以从常量存储器读取相同的数据可以节约带宽,对相同地址的连续读操作将不会产生额外的存储器通信开销。

       ⑥ 纹理存储器(Texture Memory)位于设备端存储器上,其读出的数据可以由纹理缓存(Texture Cache)进行缓存,也属于只读存储器

六、同步机制

       在SIMT 计算模型中,每个线程的执行都是相互独立的。然而在实际的应用和算法中,除向量加这种可完全并行的计算之外,并行的线程之间或多或少都需要某种方式进行协同和通信,例如:

① 某个任务依赖于另一个任务产生的结果,例如生产者-消费者关系;

② 若干任务的中间结果需要汇集后再进行处理,例如归约操作。

       这就需要引入某种形式的同步操作,以Thread Block中的线程同步为例:

       在CUDA 编程模型中,__syncthreads()可用于同一线程块内线程的同步操作,它对应PTX 指令为bar 指令。该指令会在其所在程序计数器(Programe Counter,PC)位置产生一个同步栅栏(barrier),并要求线程块内所有的线程都到达这一栅栏位置才能继续执行,这可以通过监控线程的PC来实现。在线程同步的要求下,即便有些线程运行比较快而先到达bar指令处也要暂停,直到整个线程块的所有线程都达到bar指令才能整体继续执行。

七、总结

       本文介绍了GPGPU编程的背景、CUDA编程实现步骤、软件到硬件的过度以及存储模型等内容,为后续介绍GPGPU架构提供理论基础。

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

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

相关文章

15- 微分方程

对三角函数不敏感

Linux - 基础开发工具(yum、vim、gcc、g++、make/Makefile、git、gdb)

目录 Linux软件包管理器 - yum Linux下安装软件的方式 认识yum 查找软件包 安装软件 如何实现本地机器和云服务器之间的文件互传 卸载软件 Linux编辑器 - vim vim的基本概念 vim下各模式的切换 vim命令模式各命令汇总 vim底行模式各命令汇总 vim的简单配置 Linux编译器 - gc…

提高记忆力7种自然(高效)的方法

你的记忆力如何?你的认知功能是否如你所希望的那样强大? 如果没有,那么你肯定会对将在本文中与你分享的记忆改善技巧感兴趣的。 不管你怎么想,或者别人怎么说,提高你记忆信息的能力是完全有可能的。只要知道正确的方法即可。(别担心,你并不需要做出任何重大的生活方式改…

10 个 OKR 提示将改变您执行 OKR 的方式

我们都喜欢好的表情包&#xff0c;因为它们很有趣&#xff0c;可以分享&#xff0c;非常适合与同事们一起开怀大笑。表情包可以为工作场所带来一种友情和轻松的感觉&#xff0c;从而建立一种健康的团队文化&#xff0c;这一点很重要。然而&#xff0c;我们都知道它们也会分散注…

怎么减少pdf格式的内存,怎么减少pdf文件大小

在数字化时代&#xff0c;pdf文件因其格式稳定、兼容性强等特点&#xff0c;成为工作与学习中的常用文档格式。然而&#xff0c;较大的pdf文件往往给存储和传输带来不便。本文将为你详细介绍如何巧妙减小pdf文件内存&#xff0c;助你轻松解决文件传输和存储的烦恼。 让我们来看…

基于SpringBoot的招生管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 个人中心 学生管理 专…

[C/C++入门][ifelse]19、制作一个简单计算器

简单的方法 我们将假设用户输入两个数字和一个运算符&#xff08;、-、*、/&#xff09;&#xff0c;然后根据所选的运算符执行相应的操作。 #include <iostream> using namespace std;int main() {double num1, num2;char op;cout << "输入 (,-,*,/): &quo…

OWASP 移动应用 2024 十大安全风险

1. OWASP 移动应用 2024 十大安全风险 开放全球应用程序安全项目 &#xff08;OWASP&#xff09; 是一个非营利性基金会&#xff0c;致力于提高软件的安全性。自 2014、2016 年两次发布了移动应用的十大风险后&#xff0c;今年再次发布2024版。这对移动应用软件的检查工具有着…

xcode下swift .infinity报Invalid frame dimension (negative or non-finite)错误

xcode又报错了&#xff1a;Invalid frame dimension (negative or non-finite) 报错原因 xcode升级后&#xff0c;调整frame的时候不建议使用width: .infinity或者height: .infinity 解决办法 1.使用 maxWidth 属性&#xff1a; 通过将 frame 的宽度属性更改为 maxWidth&am…

数据结构之细说链表

1.1顺序表的问题以及思考 经过上一篇顺序表的学习&#xff0c;我们知道顺序表还是有很多缺点 顺序表的缺点&#xff1a; 1.中间/头部的插入删除&#xff0c;实际复杂度为O(N) 2.增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗 3.扩容一般…

3.5、matlab打开显示保存点云文件(.ply/.pcd)以及经典点云模型数据

1、点云数据简介 点云数据是三维空间中由大量二维点坐标组成的数据集合。每个点代表空间中的一个坐标点&#xff0c;可以包含有关该点的颜色、法向量、强度值等额外信息。点云数据可以通过激光扫描、结构光扫描、摄像机捕捉等方式获取&#xff0c;广泛应用于计算机视觉、机器人…

用了6年git,不知道cherry-pick是啥意思

背景 可能是测试开发角色原因&#xff0c;平时很少有代码冲突或多人协同的编码场景。今天有个协同项目&#xff0c;需要提交自己的代码到其它业务的代码库中&#xff0c;这个代码库是分支开发分支上线模式&#xff0c;同时会有多个同事提交代码&#xff0c;然后模块负责的同学…

AG32 的MCU与FPGA的主频可以达到568MHz吗

Customers: AG32/ AGRV2K 这个芯片主频和定时器最高速度是多少&#xff1f;用户期望 CPLD计时器功能0.1ns以下。 AGM RE: CPLD做不到 0.1ns的速率&#xff0c;这个需要10G以上的时钟。 那AGRV2K最高多少MHz呢&#xff1f; 一般200MHZ比较容易实现。 进一步说明&#xff1…

昇思25天学习打卡营第29天 | 文本解码原理--以MindNLP为例

今天是29天&#xff0c;学习了文本解码原理--以MindNLP为例。 MindNLP 是一个基于 MindSpore 的开源自然语言处理&#xff08;NLP&#xff09;库。它具有以下特点&#xff1a; 支持多种 NLP 任务&#xff1a;如语言模型、机器翻译、问答、情感分析、序列标记、摘要等&#xff…

如何在 Python 中使用 CSV 文件进行读写?

如何在 Python 中使用 CSV 文件进行读写&#xff1f; 文章目录 一、说明二、什么是 CSV&#xff1f;三、使用 csv.reader 在 Python 中读取 CSV 文件的步骤四、使用 with&#xff08;&#xff09; 语句实现代码五、如何使用 .readlines&#xff08;&#xff09; 在 Python 中读…

YOLOv5和LPRNet的车牌识别系统

车牌识别系统 YOLOv5和LPRNet的车牌识别系统结合了深度学习技术的先进车牌识别解决方案。该系统整合了YOLOv5目标检测框架和LPRNet文本识别模型 1. YOLOv5目标检测框架 YOLO是一种先进的目标检测算法&#xff0c;以其实时性能和高精度闻名。YOLOv5是在前几代基础上进行优化的…

硅谷裸机云多IP服务器怎么样?

硅谷裸机云多IP服务器是一种在硅谷地区提供的、具有多个IP地址的裸机云服务器。这种服务器结合了裸机服务器的高性能和云服务器的灵活性&#xff0c;同时提供了多个IP地址&#xff0c;为用户的各种需求提供了支持。以下是关于硅谷裸机云多IP服务器的一些详细信息&#xff0c;ra…

关于git clone速度极慢的解决方法

关于git clone速度极慢的解决方法 前言 如果没有一个可靠且稳定的魔法&#xff0c;接下来的就不用看了 尝试过的方法(未成功) 既然有成功&#xff0c;那么在探索过程中也必定会有失败的方法&#xff0c;下面也介绍一下我试过的没啥用的方法&#xff0c;给各位避雷&#xff…

Ubuntu安装virtualbox(win10)

virtualbox下载安装 1、下载virtualbox 下载路径&#xff1a;Linux_Downloads – Oracle VM VirtualBox 根据自己的Ubuntu版本选择对应的安装包下载 2、安装virtualbox 到下载路径&#xff08;一般为~/Download&#xff09;打开终端输入命令 sudo dpkg -i xxx.deb 继续执…

Web前端知识视频教程分享

资料下载地址: https://545c.com/f/45573183-1323782723-42d3b2?p7526 (访问密码: 7526)