面向下一代移动视觉计算
- 来源:微型计算机 smarty:if $article.tag?>
- 关键字:ARM,图形架构 smarty:/if?>
- 发布时间:2017-02-10 11:18
ARM新一代图形架构Bifrost及Mail-G71解析
在智能手机等移动设备已经成为用户主流选择的今天,移动GPU的发展显得越来越重要。在2016年早些时候,ARM发布了全新的Bifrost图形架构和顶级的Mali-G71 GPU,在2016年末的时候已经有部分厂商推出了基于全新架构的SoC产品。现在我们需要知道的是,新架构的变化究竟在哪里,现在的移动GPU以及架构和桌面GPU架构有什么差异,我们是否应该对移动GPU的性能、功能等发展抱以更多期待?今天这篇文章应该能够回答这些问题。
从过去几年的情况来看,移动GPU的发展是非常迅速的。从早期英伟达开发的外置移动GPU GoForce开始,到随后高通收购AMD的移动GPU部门并推出Adreno,直到大家熟悉的ARM推出Mali,Imagination推出PowerVR系列等等,移动GPU的发展形成了一个庞大的市场。不过用今天的眼光来看,由于移动SoC对整合性的要求较高,因此外置GPU从一开始就无法获得厂商青睐。另外由于知识产权和研发难度等问题,在今天的Android设备上,GPU已经充分体现出了寡头化—其中的佼佼者高通Adreno和ARM Mali已经成为大家最熟悉的移动GPU产品。
ARM在移动GPU市场上早期表现并不出色。ARM早在2007年之前就推出过移动GPU产品,包括Mali-55、Mali-200、Mali-300等。但Mali真正开始进入用户眼中的产品还是Mali-400家族,包括Mali-450、Mali-470等多款产品。随后ARM在2012年发布了统一渲染的Migdard并使其成为后来多代GPU的核心架构,包括Mali-T600、Mali-T700和Mali-T800家族等。在多年的发展过程中,Migdard架构不断扩充功能,加入了包括曲面细分、10bpc色彩、支持Vulkan、OpenGL ES 3.1/3.2等。
当然从市场角度来看,Migdard架构还不算太老,整体性能和规格依旧是可以接受的。不过考虑到未来的发展和更新的技术,ARM还是早早就公布了他们全新一代的GPU架构,这就是Bifrost,产品型号为Mali-G71。
Bifrost Quad—以线程级并行为核心
现在,ARM新的Bifrost架构顺应时代,已经全面转向标量化和线程级并行。在官方给出的示意图中,ARM开了个玩笑,他们只是把旧的着色器核心向左转了90度,这里的意思并不是说ARM尝试从单个线程提取4个指令集并行,而是指ARM将四个线程捆绑在一起,从每个线程执行单个指令,实现线程级并行。
和指令集并行需要不断地寻找可以进入并行处理的指令集不同的是,线程级并行并不需要这样的编译方式,从而可以几乎做到对着色器核心接近100%高效率的应用。因此这对ARM来说几乎可以起到一箭双雕的作用—一是大幅度提高了效率,尤其是对于现代计算中大量1D或2D的操作来说,全面的标量化、无绑定也能让它们高效运行;二是线程级并行对计算来说是更为友好的一种设计,这一点在今天来说越来越重要,尤其是GPU计算性能将成为现代移动设备的重要考量因素。
此外,芯片利用率的提高还带来了对处理器功耗和芯片面积的正面影响。结合其他地方的架构改进,Bifrost能够带来更高的平均利用率和更出色的每平方毫米性能、每瓦特性能。此外,架构更新还带来了一些全新的设计,比如L1高速缓存的带宽更高了,使得着色器核心能够更有效率地使用高速缓存。
继续来看架构。Bifrost的架构波前被称为Quad—也就是每次发送指令是4指令并行的。Bifrost波前采用了四发送是非常独特的,因为类似的竞争架构一般波前都采用16或者32并行,桌面GPU甚至采用64并行。波前设计一般考虑的是资源/面积密度或者性能之间的平衡。更宽的波前需要更少的控制逻辑,比如一个逻辑控制单元控制32个线程,如果波前只有4并行的话,那么32个线程需要8个逻辑控制单元。与此类似的是,更宽的波前架构在填充上更为困难—这一点对桌面GPU来说问题不大,目前的游戏对像素和着色器要求越来越高,桌面应用中填充32或者64并行的波前难度不大。但是移动应用中更大的波前很可能造成停顿或者空转,这是ARM在设计GPU时非常关注的核心问题之一—尽可能地避免各种无效率的等待或者停顿。通过使用较窄的波前并行,一组线程不太可能出现发散的情况,所谓发散是指如果存在条件语句的话,有可能线程会执行不同的路径,这种情况在比较宽的波前设计中是比较容易出现的,这种发散虽然很容易处理,但是对性能依旧存在负面影响。
在看完了对Bifrost Quad的描述后,我们来看看ARM在线程调度上的创新。除了波前阵列为4并行外,ARM还增加了一个被称为“子语句”的功能。简单来说,所谓的“子语句”是指一种特殊的、被加入了限制条件的波前语句。设立“子语句”的意义在于,可以通过定义排序指令以及识别哪些等待时间不定的指令,ARM能够尽可能地降低指令调度开销。举例来说,当有一个波前阵列被编译器识别为“子语句”时,那么这一组指令将会有一些执行保证,包括已知指令延迟以及会被连续执行而无需检查。本质上一个子语句是一个指令块,编译器已经预先知道其绝对安全,因此从执行开始到结束都不需要额外的检查和操作。
使用“子语句”功能是因为子语句执行起来安全性很高,GPU调度器不需要在Quad的执行中不断检查(这也会耗费一定的性能和能耗),只有在子语句完成后才进行检查。此外当执行子语句时,Bifrost可以将需要访问的相同寄存器指令连接在一起,甚至在某些情况下可以绕过寄存器访问。从功耗的角度来看,寄存器访问是一个相对高功耗的操作,因此避免使用寄存器文件是节省功耗的另一种手段,况且ARM也允许使用更简单的寄存器。
ARM允许使用更简单的寄存器,它被称之为临时寄存器。虽然临时寄存器在很大程度上更像是一个“心理助记符”,也就是说将指令的结果立刻加入到下一条指令的输入中。这种数据的性质意味着它只能在一个子语句中运行,因为结果只能在这个周期内使用,并且“临时”的意思表明超过下一个周期数据就会丢失—不经过寄存器的读写反而降低了功耗。
子语句的功能还不仅如此,它还可以允许可变延迟操作,这种设计对纹理访问比较有效,但有一些边界条件。可变等待时间在操作时会将子语句拆分为两个部分,分别标记子语句的开始和末尾。通过标记,ARM可以调度可变等待时间的子语句。比如后半部分没有准备好开始时,另一个不相关的子语句可以先进入到Quad中。这种交错执行的设计是掩盖延迟的一种经典设计方案,因为它允许Quad在等待高延迟操作的同时执行其他操作以提高效率,Bifrost允许最多8个这样的子语句进行交错执行。
在Midgard中,ARM的管线包含了向量乘法、向量加法、向量特殊功能单元(SFU)、标量加法和标量乘法、标量加法。Bifrost则简化了不少,它的管线只是一个128bit(4×32bit)的FMA(融合乘加运算)SIMD,另外还有一个128bit的SIMD单元用于整数加法和SFU操作。
这种整数加法和SFU操作在同一个SIMD管道上是Bifrost的独特标志,因为绝大多数其他架构都把所有的加法和乘法放在同一个管道上执行。另一方面这意味着Bifrost在某些方面还是和Midgard类似,ARM可以同时执行乘法、FMA(二选一)和单独的加法—这也是为什么Bifrost不能算作“纯粹”的线程级并行的原因。技术上,ARM需要发出一些融合指令或者一个长指令,用于FMA和ADD/SFUSIMD命令。因此,当运行这样的指令时,为了获得GPU最高效率的运行,需要填充两个SIMD。
在一个SIMD内部,Bifrost和Midgard都能够进行指令的分解和融合,这意味着单个SIMD通道可以用作不同的数据类型。比如对浮点运算而言,一个通道可以在每个时钟周期中处理一个FP32或者两个FP16,对于整数操作,每个周期可以处理一个INT32、2个INT16或者4个INT8。因此,与其他厂商单独使用专用的FP16/FP32的ALU单元相比,ARM的设计依旧在充分权衡空间和效率方面显得很灵活。
另外,ARM还确认了每个管道内的寄存器相比Midgard而言更大了,虽然没有制定具体的大小,但是Bifrost的可注册文件大小是Midgard的两倍。ARM声称这样的设计能够提高架构处理长而复杂的着色器计算的能力,往往这些计算在Midgard上会产生溢出而降低效率。
架构改进明显—Bifrost的宏观设计解读
上文我们尽可能多地关注了Bifrost微观方面的设计,比如深入到线程、SIMD等内容中。在这一部分,我们将从宏观方面关注Bifrost的设计。
首先来看核心配置部分。Bifrost每个内核包含三个Quad执行引擎,这意味着一个Bifrost核心可以一次性执行多达12个FMA操作。在管理上,Quad执行引擎和核心的线程管理前端(现在被称为Quad管理单元)相连接,然后Quad管理单元又和其他控制核心、总线连接至整个核心的所有功能模块。
Bifrost执行引擎的数量只有三个,不过这些执行引擎中只有ALU、寄存器和其他一些功能组件—相反,诸如Midgard这样的架构,执行引擎中拥有更多的其他单元,包括加载/存储单元、纹理单元等,在Bifrost中这些单元被独立出来并受到控制单元的统一管理。出现这样的变化主要是由于Bifrost从之前的指令级并行转变为目前的线程级并行后,必须更为精准地衡量如何使用资源。比如那些没有放入Quad引擎的功能性单元,不但不会像ALU那样被频繁使用,而且在着色器程序长度增长的情况下反而更少使用。因此干脆将这些单元独立并统一控制,尽可能节约资源。
当然这样做也存在一定的风险,但实际应用中倒也不是很大的问题。Bifrost这里的设计有点类似英伟达的SM单元,即多个ALU共享加载/存储和纹理单元等功能模块,以提高效率和能耗比。这样做也简化了核心设计—只有少数单元具有L2高速缓存的数据路径,并且所有这些单元放在了Quad执行引擎之外,只有需要使用时才启用。
总的来说,Bifrost这种分离式的设计和Midgard对应的单位没有显著差异,最大的变化来自于执行引擎的简化。相比之下,Bifrost的纹理单元依旧能够提供和Midgard相当的文理吞吐能力和特性。在改进方面,Bifrost相比Midgard最大的改进来自于几何子系统。Bifrost依旧使用了分层Tile来将几何体分解并处理,不过ARM已经在尽可能地降低Tiler对寄存器的使用,目前越来越高的移动设备屏幕分辨率和几何复杂性推高了Tiler对寄存器的占用,并且最终损害到了效能和性能。
在内存方面,Bifrost使用了一个粒度几乎没有最小分配需求的新内存分配系统,通过减少大型缓冲区的开销量来降低内存消耗。但是更重要的一点是,ARM在Bifrost中实现了一个微三角丢弃加速器。所谓微三角是指那些早期出现的、无法被看到的子像素三角形。ARM通过一个丢弃加速器在早期将这些三角形过滤并丢弃,不需要在Tiler中存储这些三角形,进一步降低了内存需求。ARM宣称,Bifrost在Tiler上的变化能够将Tiler的内存消耗降低最高95%。类似的,ARM也针对顶点着色内存消耗进行了优化。Bifrost拥有一个被ARM称为“指针位置着色器”(Index-Driven Position Shading)的功能,这个功能利用到了之前对Tiler上的一些功能改进,ARM估计最多可以降低位置着色器40%的内存带宽。
最后,在渲染管线的另一端,Bifrost的ROP、深度&模板单元、Blending Unit等部分相比Midgard并没有做出特别重大的修改,只有一些小改进。Bifrost的BlendingUnit现在可以执行FP16目标的操作,而Midgard只能对整数目标进行处理。包含浮点的Blend不但节省了一步转换,而且也提高了精度。此外,Bifrost的ROP硬件可以根据配置进行扩展,最高可以达到32像素/周期。
最多可扩展至32核心—Mali-G71架构解读
有关Bifrost的内容我们基本解读完毕,下面来看看Mali-G71(下简称G71)。从发布时间来看,G71和之前我们曾介绍过的Cortex-A73是一起公布的,上一期本刊已经详细介绍了Cortex-A73,有兴趣的读者可以一起参照来看。
和之前ARM所有的GPU核心一样,G71也设计了可变数量的着色器核心,最高可达32个,当然最低是4个,从型号上来说就是G71MP4到G71MP32—当然,32个着色器对于移动设备来说还是有点夸张,尤其是在当前的工艺条件下。不过ARM一向对GPU设计颇具前瞻性,这也是可以理解的。
在缓存系统方面,G71的L2缓存子系统做出了修改。之前Midgard采用的完全分段的高速缓存系统,而G71的L2已经改为了单一逻辑高速缓存。另外更令人关注的是,L2缓存拥有了SoC的一致性互联功能,包括和ARM新的CoreLink、CCI-550等均有互联或者第三方专用互联。目前,G71能够为互联功能提供多达4个完整的ACE(完全一致性)接口,而之前的Midgard只有2个I/O一致性的ACE Lite接口。总而言之,由于GPU架构的变化,架构级别、缓存级别和互联级别的组合,G71目前能够提供和系统其他部分完全一样的缓存一致性,也就是说,G71在和适当的CPU内核搭配时,CPU和GPU都可以互相读取对方的缓存,能够进行高效能的异构计算。
值得一提的是,G71不支持异构系统架构的HSAIL标准—虽然ARM还是HSA基金会的成员。ARM回应G71只是在最严格意义上不是一个完整的HSA平台而已,但依旧是HSA标准下的硬件。一般来说,HSA标准规定了硬件的很多方面,以实现通用的互操作性和更容易的编程,包括信号、队列、浮点数处理和其他方方面面的内容。HSAIL的标准则更关心异构编程的软件方面,虽然有一定帮助,但是对异构计算来说并不是必需品。所以,虽然G71在技术上并不是一个严格意义上的HSA平台,但的确是一个HSA硬件,它遵守HSA规范可以为异构计算提供很好的软硬件环境。而且G71还是第一个非AMD的HSA1.1硬件,这已经足以说明问题了。
最后我们再来看看ARM官方宣称的G71的一些数据。和之前的Mali-T880相比,G71能够带来最高20%的能源效率提升、40%的性能密度和20%的带宽提升,总体来看基本上是1.5倍于T880设备的性能—这个数据是非常模糊的,因为需要综合考虑到工艺、着色器核心数量、Bifrost架构改进等综合因素。另外,ARM还在商业方面给出了一些指引,包括新的Bifrost架构的GPU会被称为Mali-GXX系列,老的Midgard架构会被称为Mali-TXXX系列,最老的Utgard架构的GPU则没有字母前缀,直接称为Mali-XXX系列。用户未来可以根据GPU型号就能快速识别GPU架构和支持的基本规范。
总的来说,Bifrost架构和Mali-G71的推出,是ARM在新时代和新的应用条件下经过深思熟虑的结果,它将会为移动设备带来全新的图形体验,尤其是等到4K、VR等新的需求及功能逐渐铺开,对移动端GPU的要求也会越来越大,ARM适时地改变了架构,提升了性能,推出了能耗比更高、性能更为出色的移动GPU产品,有助于进一步推动移动计算市场的发展,并尽快将这些高科技产品普及到普通用户的手中。
TIPS
VLIW和Midgard架构
ARM在GPU架构代次上有着非常清晰的划分。比如最早的Utgard架构,就是指从Mali-200到Mali-400(Mali-470)以来的所有架构,其主要特点是支持OpenGL ES 2.x,属于典型的非统一渲染架构的产品。随后的Midgard产品则进入了统一渲染架构时代。
相比之下桌面GPU进入统一渲染架构的时间要早得多,从2007年就开始全面铺开。不过早期的桌面统一渲染架构GPU出现了两条截然相反的道路。英伟达从一开始就走向了全面标量化,不再考虑任何指令的搭配和处理,全部进入1D的CUDA Core计算。反观AMD,依旧采用了比较常见的SIMD架构,首款R600采用的5D架构则可以在一次计算中完成5次MAD或者4次MAD加一次特殊计算。这样设计的优势在于能够在指令匹配合理的情况下保持很高的计算效率,比如大量的指令都是4D或者4D+1D的,反之则计算效率降低。
从历史发展的角度来看,移动GPU在架构和特性上总是晚于桌面GPU一段时间。在ARM的Midgard上表现得就非常明显:Midgard核心架构设计和AMD Cayman时期的设计有一定相似性,它也是一个VILW的、以指令集并行为核心的设计。其核心采用了4D设计的方案,天然对应RGBA四个色彩通道,因此具有很高的空间效率和较少的逻辑开销。不过和所有VILW架构一样的是,Midgard架构需要填充大量的ILP-4并行指令才能发挥最佳的效能。
从效率上考虑,更新一些的图形应用通常不能很好地发挥VILW的效能,因为无论是VILW 5D还是4D架构,都需要并行、固定格式的指令来“填满”,现在新的图形算法往往只有1个或者2个指令一起“并行”。虽然一个优秀的着色编译器可以帮助提高效能,但是这并不意味着编译器可以解决所有的问题,尤其是这类能够从众多指令中寻找到可以并行处理、又不降低效率的编译器本身就是一个问题。于是,Midgard这样的架构和之前AMD的Cayman等一样,都逐渐走出了历史的视线。
文/徐少卿