详解GPU硬件架构及运行机制

为什么我们总说gpu比cpu要强大,既然gpu强大,为什么不能取代cpu呢?
答案就是cpu工作方式和gpu的工作方式截然不同,下面的两张图有助于帮助我们理解cpu和gpu的工作方式的不同。
上图有几个重点的元素,也是我们下文重点要阐述的概念,绿色代表的是computational units(可计算单元) 或者称之为 cores(核心),橙色代表memories(内存) ,黄色代表的是control units(控制单元)。
因此想要理解gpu的底层核心构成,就必须明确这几个元素的作用,下文会逐一讲解每个元素的作用。
01. 计算单元(cores)
总的来看,我们可以这样说:cpu的计算单元是“大”而“少”的,然而gpu的计算单元是“小”而“多”的。
这里的大小是指的计算能力,多少指的是设备中的数量。通过观察上图,显然可以看出,计算单元(绿色的部分),cpu“大少”,gpu“小多”的特点。
cpu的cores 比gpu的cores要更加聪明(smarter),这也是所谓“大”的特点。
在过去的很长时间里,cpu的core计算能力增长是得益于主频时钟最大的频率增长。
相反,gpu不仅没有主频时钟的提升,而且还经历过主频下降的情况,因为gpu需要适应嵌入式应用环境,在这个环境下对功耗的要求是比较高的,不能容忍超高主频的存在。
例如英伟达的jetson nano, 安装在室内导航机器人身上,就是一个很好的嵌入式环境应用示例,安装在机器人身上,就意味着使用电池供电,gpu的功耗不可以过高。
cpu比gpu聪明,很大一个原因就是cpu拥有out-of-order exectutions(乱序执行)功能。
出于优化的目的,cpu可以用不同于输入指令的顺序执行指令,当遇到分支的时候,它可以预测在不久的将来哪一个指令最有可能被执行到(multiple branch prediction 多重分支预测)。
通过这种方式,它可以预先准备好操作数,并且提前执行他们(soeculative execution 预测执行),通过上述的几种方式节省了程序运行时间。
显然现代cpu拥有如此多的提升性能的机制,这是比gpu聪明的地方。
相比之下,gpu的core不能做任何类似out-of-order exectutions那样复杂的事情。
总的来说,gpu的core只能做一些最简单的浮点运算,例如 multiply-add(mad)或者 fused multiply-add(fma)指令。
通过上图可以看出mad指令实际是计算a*b+c的值。
实际上,现代gpu结构,core不仅仅可以结算fma这样简单的运算,还可以执行更加复杂的运算操作,例如tensor张量(tensor core)或者光线追踪(ray tracing core)相关的操作。
张量核心 (tensor cores) 的目的在于服务张量操作在一些人工智能运算场合,光纤追踪(ray tracing) 旨在服务超现实主义(hyper-realistic)实时渲染的场合。
上文说到,gpu core最开始只是支持一些简单的浮点运算fma, 后来经过发展又增加了一些复杂运算的机制tensor core以及ray trace,但是总体来说gpu的计算灵活性还是比不上cpu的核心。
值得一提的是,gpu的编程方式是simd(single instruction multiple data)意味着所有core的计算操作完全是在相同的时间内进行的,但是输入的数据有所不同。
显然,gpu的优势不在于核心的处理能力,而是在于他可以大规模并行处理数据。
gpu中每个核心的作用有点像罗马帆船上的桨手:鼓手打着节拍(时钟),桨手跟着节拍一同滑动帆船。
simt编程模型允许加速运行非常多的应用,对图像进行缩放就是一个很好的例子。
在这个例子中,每个core对应图像的一个像素点,这样就可以并行的处理每一个像素点的缩放操作,如果这个工作给到cpu来做,需要n的时间才可以做完,但是给到gpu只需要一个时钟周期就可以完成。
当然,这样做的前提是有足够的core来覆盖所有的图像像素点。这个问题有个显著的特点,就是对一张图像进行缩放操作,各个像素点之间的信息是相互独立的,因此可以独立的放在不同的core中进行并行运算。
我们认为不同的core操作的信息相互独立,是符合simt的模型的,使用simt来解决这样的问题非常方便。
但是,也不是所有的问题都是符合simt模型的,尤其在异步问题中,在这样的问题中,不同的core之间要相互交互信息,计算的结构不规则,负载不均衡,这样的问题交给gpu来处理就会比较复杂。
02. 内存memory
回到这个文章的第一张图中来,我们接下来会讨论gpu和cpu内存方面的差别。
cpu的memory系统一般是基于dram的,在桌面pc中,一般来说是8g,在服务器中能达到数百(256)gbyte。
cpu内存系统中有个重要的概念就是cache,是用来减少cpu访问dram的时间。cache是一片小的内存区域,但是访问速度更快,更加靠近处理器核心的内存段,用来储存dram中的数据副本。
cache一般有一个分级,通常分为三个级别l1,l2,l3 cache,cache离核心越近就越小访问越快,例如 l1可以是64kb l2就是256kb l3是4mb。
cpu cache的内容不再这里展开讲解,感兴趣的读者可以自行查阅资料。
从第一张图可以看到gpu中有一大片橙色的内存,名称为dram,这一块被称为全局内存或者gmem。
gmem的内存大小要比cpu的dram小的多,在最便宜的显卡中一般只有几个g的大小,在最好的显卡中gmem可以达到24g。
gmem的尺寸大小是科学计算使用中的主要限制。十年前,显卡的容量最多也就只有512m,但是,现在已经完全克服了这个问题。
关于cache,从第一张图中不难推断,左上角的小橙色块就是gpu的cache段。然而gpu的缓存机制和cpu是存在一定的差异的,稍后将会证明这一点。
03. gpu的底层结构
为了充分理解gpu的架构,让我们在返回来看下第一张图,一个显卡中绝大多数都是计算核心core组成的海洋。
在图像缩放的例子中,core与core之间不需要任何协作,因为他们的任务是完全独立的,然而,gpu解决的问题不一定这么简单,让我们来举个例子。
假设我们需要对一个数组里的数进行求和,这样的运算属于reductuin family类型,因为这样的运算试图将一个序列“reduce”简化为一个数。
计算数组的元素总和的操作看起来是顺序的,我们只需要获取第一个元素,求和到第二个元素中,获取结果,再将结果求和到第三个元素,以此类推。
令人惊讶的是,一些看起来本质是顺序的运算,其实可以再并行算法中转化。
假设一个长度为8的数组,在第一步中完全可以并行执行两个元素和两个元素的求和,从而同时获得四个元素,两两相加的结果,以此类推,通过并行的方式加速数组求和的运算速度。具体的操作如下图所示:
如上图计算方式,如果是长度为8的数组两两并行求和计算,那么只需要三次就可以计算出结果。
如果是顺序计算需要8次。如果按照两两并行相加的算法,n个数字相加,那么仅需要log2(n)次就可以完成计算。
从gpu的角度来讲,只需要四个core就可以完成长度为8的数组求和算法,我们将四个core编号为0,1,2,3。
那么第一个时钟下,两两相加的结果通过0号core计算,放入了0号core可以访问到的内存中,另外两两对分别由1号2号3号core来计算,第二个个时钟继续按照之前的算法计算,只需要0号和1号两个core即可完成。
以此类推,最终的结果将在第三个时钟由0号core计算完成,并储存在0号core可以访问到的内存中。这样实际三次就能完成长度为8的数组求和计算。
如果gpu想要完成上述的推理计算过程,显然,多个core之间要可以共享一段内存空间以此来完成数据之间的交互,需要多个core可以在共享的内存空间中完成读/写的操作。
我们希望每个cores都有交互数据的能力,但是不幸的是,一个gpu里面可以包含数以千计的core,如果使得这些core都可以访问共享的内存段是非常困难和昂贵的。
出于成本的考虑,折中的解决方案是将各类gpu的core分类为多个组,形成多个流处理器(streaming multiprocessors )或者简称为sms。
04. gpu架构
上图的绿色部分意味着core计算单元,绿色的块就是上文谈到的streaming multiprocessors,理解为core的集合。
黄色的部分名为rt cores画的离sms非常近。单个sm的图灵架构如下图所示
在sm的图灵结构中,绿色的部分core相关的,我们进一步区分了不同类型的core。主要分为int32,fp32,tensor cores。
1. fp32 cores,执行单进度浮点运算,在tu102卡中,每个sm由64个fp32核,图灵102由72个sm因此,fp32 core的数量是 72 * 64。
2. fp64 cores. 实际上每个sm都包含了2个64位浮点计算核心fp64 cores,用来计算双精度浮点运算,虽然上图没有画出,但是实际是存在的。
3. integer cores,这些core执行一些对整数的操作,例如地址计算,可以和浮点运算同时执行指令。在前几代gpu中,执行这些整型操作指令都会使得浮点运算的管道停止工作。tu102总共由4608个integer cores,每个sm有64个intcores。
4. tensor cores,张量core是fp16单元的变种,认为是半精度单元,致力于张量积算加速常见的深度学习操作。
图灵张量core还可以执行int8和int4精度的操作,用于可以接受量化而且不需要fp16精度的应用场景,在tu102中,我们每个sm有8个张量cores,一共有8 * 72个tensor cores。
在大致描述了gpu的执行部分之后,让我们回到上文提出的问题,各个核心之间如何完成彼此的协作?
在四个sm块的底部有一个96kb的l1 cache,用浅蓝色标注的。这个cache段是允许各个core都可以访问的段,在l1 cache中每个sm都有一块专用的共享内存。
作为芯片上的l1 cache他的大小是有限的,但它非常快,肯定比访问gmem快得多。
实际上l1 cache拥有两个功能,一个是用于sm上core之间相互共享内存,另一个则是普通的cache功能。
当core需要协同工作,并且彼此交换结果的时候,编译器编译后的指令会将部分结果储存在共享内存中,以便于不同的core获取到对应数据。
当用做普通cache功能的时候,当core需要访问gmem数据的时候,首先会在l1中查找,如果没找到,则回去l2 cache中寻找,如果l2 cache也没有,则会从gmem中获取数据,l1访问最快 l2 以及gmem递减。
缓存中的数据将会持续存在,除非出现新的数据做替换。从这个角度来看,如果core需要从gmem中多次访问数据,那么编程者应该将这块数据放入功能内存中,以加快他们的获取速度。
其实可以将共享内存理解为一段受控制的cache,事实上l1 cache和共享内存是同一块电路中实现的。编程者有权决定l1 的内存多少是用作cache多少是用作共享内存。
最后,也是比较重要的是,可以储存各个core的计算中间结果,用于各个核心之间共享的内存段不仅仅可以是共享内存l1,也可以是寄存器,寄存器是离core最近的内存段,但是也非常小。
最底层的思想是每个线程都可以拥有一个寄存器来储存中间结果,每个寄存器只能由相同的一个线程来访问,或者由相同的warp或者组的线程访问。
05. 总结
gpu的基本底层构成,主要是以gpu计算核心 cores,以及memory以及控制单元,三大组成要素组成。
core是计算的基本单元,既可以用作简单的浮点运算,又可以做一些复杂的运算例如,tensor 或者ray tracing。
多个core之间通讯的方式:
在特定的应用场合多个core之间是不需要的通讯的,也就是各干各的(例如 图像缩放)。但是也有一些例子,多个core之间要相互通讯配合(例如上文谈到的数组求和问题),每个core之间都可以实现交互数据是非常昂贵的,因此提出了sm的概念,sm是多个core的集合,一个sm里面的cores可以通过l1 cache进行交互信息,完成使用gpu处理数组求和问题的时候,多个核心共享数据的功能。
关于memory,存在全局的内存gmem,但是访问较慢,cores当需要访问gmem的时候会首先访问l1,l2如果都miss了,那么才会花费大代价到gmem中寻找数据。


SystemVerilog中的参数化类
智能型电动机保护器在某水泥厂的应用
多核处理器应用火热,高整合度电源芯片势在必行
苹果13正式发售时间
人脸识别应用为何广受校方青睐
详解GPU硬件架构及运行机制
便携式数据采集存储(SD卡存储)系统中ADC的选用指南手册
8051单片机是几位机_8051单片机共有几个中断源
MIMO的发展趋势以及优势
什么是区块链和比特币
iPhone7,小米5s/plus这几款手机怎么还不降价,销量第二春要来了!
千元内降噪耳机推荐!2020最强降噪耳机推荐
中央空调系统如何进行节能改造 浅谈中央空调系统改造
因光纤技术的普及和成本下降 光纤连接器开始在商业和工业据点出现
基于i.MX27的网络音视频通信的实现
Huawei Share的最全玩法
AM微机保护装置在黄梅县中医医院配电工程中的设计使用
PROFIBUS现场总线技术及发展趋势分析
温度传感器的概念及类型
dfrobot语音识别控制板 介绍