在上一期中,我们详细讲解了ARM Mali GPU架构的发展历程,以及新的Midgard架构的设计方向、架构概览、无固定硬件单元的曲面细分功能设计等内容。而在本期中,我们将继续带你深入ARM Midgard架构的内部,去进一步地探索这个非常重要的移动GPU架构的方方面面。
目前的SoC产品受到诸如电源、芯片尺寸、内存带宽等诸多规格参数的影响,但是毫无疑问,内存带宽比任何参数都更能直接的影响到产品的性能。为了进一步优化内存带宽使用并提高效率,Midgard提出了一种名为Hierarchical Tiling system(层级区块体系)的算法,顾名思义—这种算法来自于将Midgard所要渲染的目标根据层级进一步的分块,终使得每个区块达到了所需要的、能够直接在GPU内部处理的尺寸,这样可以进一步节约资源。
所谓“区块”,是目前绝大部分移动GPU采用的一种数据处理和渲染方式,Midgard自然也不例外。简单来说,传统的GPU在数据处理时,会使用一整张大贴图对画面进行计算。但这样做贴图受制于体积,必须存放在内存中,这样一来频繁的GPU和内存间的数据交换会很快耗尽极为有限的带宽资源。因此,Mali以及高通的Adreno、IT的PowerVR等厂商都采用了Tile(区块)的贴图方式。这种方式是将整个场景先划分为一个个小小的区块(一般是16×16尺寸),由于区块很小因此可以直接放在GPU的缓存中,然后GPU再对这个区块进行处理,这样一来就极大的避免了数据传输对系统总线带来的巨大压力,同时也节约了资源。
除了有关Tile技术外,Midgard还在加强工作效率、降低无谓的性能消耗上做出了很多努力。Midgard在内核架构中添加了两个Z轴检查模块,分别为前置Z轴检查和后置Z轴检查。早期Z轴模块被放置在每个着色器核心中,它用于检测是否存在一些多边形被覆盖或者不可见但进入了渲染管线,前置Z轴模块会将其剔除。当然这还是不够的,在Mail-T620以后的Midgard架构GPU上,又加入了一个名为“前置像素剔除(Forward Pixel Kill)”的模块,用于进一步检查一些无用的、被遮挡的像素,大效率地节省带宽和资源。
再来看看Midgard的功耗优化方面。Midgard采用了一些新技术来优化功耗。比如加入了大量的门控时钟和细粒度的电源门控来优化整个GPU的电能使用。而在GPU空闲时,Midgard允许GPU空闲部分(甚至可以是部分核心)休眠或者关闭;每个着色器单元都拥有自己的电源控制模块,着色器本身的频率根据需要降低以同时控制功耗。此外,Midgard还拥有一些比较常见的频率调节技术,比如拥有动态频率,可以在不同的状态下自动调节频率以节约能量。总之,Midgard的能耗控制是比较出色的。
双精度和异构计算—Midgard为未来计划
接下来,我们来谈谈有关Midgard在计算能力和内存访问上的一些问题。ARM一直以来都是以设计高性能功耗比的CPU模块为主的,尤其是目前非常火爆的ARM 64架构。在CPU上,ARM的目标是全面扩展到64位计算架构,而在GPU上ARM也这样做了。目前Midgard完全支持64位计算,包括64位整数计算、双精度计算(FP64)使用、使用64位内存地址等。
一般来说,在一款移动SoC GPU上实现64位计算的意义并不大,尤其是FP64,但ARM考虑的显然并非只是计算精度。Midgard可以调用64位存储器地址,和ARMv8系列CPU使用相同的64位地址空间—这样一来意义就变得非同凡响了。这种能力使得Midgard和ARMv8架构的CPU在I/O上实现一定的一致性,比如Midgard直接去读取CPU的缓存。虽然Midgard和ARMv8 CPU之间不一定存在缓存一致性,但是这个功能主要是用于让GPU更有效率的访问CPU的缓存,数据在CPU和GPU之间的传递可以更为直接、高效。当然,完整的缓存一致性显然也是ARM的目标之一。
作为一款移动SoC GPU,Midgard在电能控制上主要使用了功耗门控和频率门控两种技术。
ARM一直都非常关心有关异构计算的内容。因此,Midgard加入了64位寻址和I/O的一致性功能后,ARM可以在有关GPU和CPU的异构计算方面更为有效率—别忘了ARM一直都是HAS异构计算联盟的一员。虽然目前看起来ARM依旧处于单一的CPU或者GPU计算的阶段,但是路要一步一步走,ARM为了节约电能、提高计算效率,在异构计算上做出的努力应该会有成果展示的。
我们在比较宏观的角度描述了Midgard的架构内容。接下来的部分,需要继续深入Midgard GPU的心脏部分,它的核心单元设计。一般来说,判断GPU设计是否优秀并非只是一些漂亮的参数,而是它的核心单元方案。
Midgard的核心单元设计采用了VLIW超长指令集方案,拥有SIMD单指令多数据流特性。这样的设计需要ARM在指令层面有非常强的指令调配能力。在下图中,展示了一个Midgard的核心算术单元,图中以FP32操作为例。在一个算术管线中,Midgard混合了标量和矢量ALU,每个部分含有3个矢量ALU和2个标量ALU,每种都会负责一个特定类型的操作。
在计算能力方面,之前我们曾提到过Midgard可以支持64位计算,猜猜看它是如何实现的呢?实际上Midgard是通过一个完整的128位的SIMD来分解操作较小位宽的计算。比如一个128位的SIMD可以分解成2个64位操作,也可以分解成4个32位操作甚至8个16位操作。这样的设计一方面增加了灵活性,另一方面使得尽可能多的相同操作可以填充SIMD流水线,提高了效率。
一般来说,使用SIMD或者类似SIMD设计的GPU还是比较多的,但是设计得如此灵活的SIMD架构非常少见。其它体系架构师都在强调效率和强调灵活之间做出权衡:当灵活性很高的时候,效率肯定有所损失,反之亦然。不过ARM采用这样的设计,肯定是考虑到需要满足所有的计算需求,因此才设计了这样一个128bit的灵活SIMD。
在计算能力方面,一个完整的Midgard计算单元每时钟能够输出17FLOPS FP32的性能,它包含了4个矢量加、4个矢量乘法、1个标量加法、一个标量乘法、一个点积(7FLOPS)。除了上述内容外,每个架构还有一些SFU单元用于处理点积、微积分以及其他复杂的计算。这些特殊计算单元的计算能力往往不会被统计在FLOPS中。大多数架构统计FLOPS都是通过统计大量的MAD指令来完成。比如Tegra K1拥有192个FP32 ALU,每个ALU每周期可以执行2次MAD计算,因此它的总计算能力达到了384 FLOPS每周期。
除了常见的FP32外,FP64双精度计算也是Midgard的特性之一。不过相比FP32而言,Midgard的FP64能力要低得多,大约只有每周期每核心5FPLOS。从乐观的角度来说,Midgard的FP64性能中的4FLOPS来自于矢量单元(2个FP64 MAD指令),而剩余的1个FLOPS来自于标量单元—如果假定是正确的话,标量单元每周期基本上难以完成一个FP64 MAD指令。不过基于FP64的性能虽然仅仅是FP32的一半,但这对桌面GPU来说也是非常高的水平,因此本文的估计很可能还是过于乐观了,在这方面ARM没有公布更多的资料,所以我们的猜测也只能到此为止。
作为一个单指令多数据流的VLIW GPU、或者是ARM官方的连续超长指令集(Sequential Long Instruction Word)架构来说,在执行阶段为了提升效率,编译器应该会编译出尽可能符合硬件架构的指令来试图塞满整个计算管线。对VLIW来说这需要一定程度的指令级并行调整数据,并查找可以放在一起的SIMD操作,终填补Midgard架构中可能存在的任何空闲操作。在没有超标量体系结构的情况下,充分利用Midgard的VLIW架构的办法就是:将几个合适的指令捆绑成一个,直接塞入Midgard的架构中。从目前使用在ARM SoC上的GPU核心设计也能看出,诸如英伟达的Kepler以及IT的PowerVR,都或多或少的引入了指令级并行的一部分内容,这两者也同样使用了超标量架构(虽然和Midgard还是有很大差异)。
历史上还有其他的一些公司大规模使用VLIW,比如AMD。AMD在桌面的HD 2000一直到HD 6000系列GPU都使用了VLIW架构,直到2011年在GCN架构上,AMD才放弃了VLIW。当时AMD遇到的难题是研究人员发现应用程序在GPU上工作是往往无法达到VLIW的设计吞吐能力,甚至这样的状况变得越来越不理想。AMD终使用了全新的GCN架构,彻底抛弃了指令级并行,转投线程级并行的怀抱。
继续回到Midgard上来。实际上,对一个以移动SoC为目标的GPU来说,怎样设计合适的规模和架构以适应移动SoC的需求才是重要的。目前看来,Midgard采用的VLIW架构相对来说是比较稳妥和合适的,因为对Midgard来说,它拥有128bit的矢量处理能力,可以映射为ARGB计算,也就是每个SIMD处理一个颜色通道,标量单元刚好可以辅助处理那些不太好处理的特殊计算部分。因此,虽然从GPU架构发展来看,线程级并行是大趋势,但是在当前也不能说指令级并行就没意义了。
在确定了Midgard使用指令级并行后,就需要关心一下它的ALU流水线设计了。为了满足目前的VLIW方案并尽可能提高效率,整个Midgard的流水线管道有128级,算术管道部分有30级深,不过Midgard的三管线设计每个管线都有自己不同的深度。从GPU的角度来看,Midgard简直就是一个极深的、高延迟、大吞吐量、交织着大量线程以保持流水线效率的GPU。在任何情况下,ARM都允许Midgard通过绕过一些错误,比如失败的读取或者写入等来避免等待,同时会重启这些指令,而不是令其堵塞在流水线管道。
AMD在从指令级并行转换至线程级并行是在2011年的GCN架构上完成的。
还有一些其它消息更令人感兴趣,那就是Midgard完全没有全局的线程级并行性设计。所有目前的主流GPU,无论来自英伟达、AMD还是英特尔,无论是否依赖于指令级并行,都至少和线程级并行相关。在这些GPU的设计中,很多线程被捆绑在一起直接发送至ALU单元。一般来说这些被捆绑的每个线程都代表了一个像素,只是由于空间位置存在一定的相关性,因此它们有几乎相同的指令算法,一堆类似的线程可以同时发送操作而不需要一个个计算。因此,我们在目前的GPU设计中看到了诸如波次这样的概念,比如AMD GCN是16个线程每波次,而英伟达在Kepler中是32个。
但是,这样的情况在Midgard这里并不存在。从上一代架构开始一直到Midgard,它们的GPU中每一个线程都是独立的,似乎和线程的并行处理无关。而做出这样的设计,是因为Midgard的每个算术管道都是自己的“CPU”,它们可以对线程进行独立的处理和计算。即使是诸如Mali-T760这样只有两组运算单元的GPU,这两组运算单元也会彼此分开独立工作。如果扩大的更大一些,比如T760MP16,它拥有32个计算单元,依旧是彼此独立工作。
对Midgard这样的设计,其实可以分为两个方面来看。首先,Midgard的设计非常正确,它使用了一种特殊的方法解决了没有线程级并行的缺陷。一般来说,在图形处理中,线程级并行由于可以很方便的得知像素的空间位置,计算中会捆绑一些线程,比如16个或32个每个波次,带来了效率的提升。但是,以线程级并行为核心的设计也有自己的缺点。比如需要一些分支操作时,由于无法绑定,因此线程级并行的效率会降低。此外,如果一次操作无法满足一个波次的需求,效率也会降低。
总的来说,目前Midgard的设计相当的独特,ARM在GPU的设计上展示了一种完全不同于目前所有既定思维的方案。当然,这样的设计终是否成功,不但有硬件和架构方面的原因,还有软件方面的因素,比如Midgard就更为适合分支更多的程序。
所谓指令级并行,是指目前所执行的一组指令之间相互独立,不互相等待结果、不互相访问同样的内存单元、不互相使用计算单元或功能部件,它们在处理器内部并行地执行。指令级并行的方法和传统的提高处理器计算能力的方法相关。如果你想提高一个处理器的处理能力,那么好的办法是给这个处理器中加入大量的高效率、专用的处理模块,这样无论有怎样的任务处理器都可以见招拆招。
指令级并行在很长一段时间内都是处理器提高性能的不二法门。不过它的问题在于处理器效率不够高。例如在理想情况下,VLIW的效率应该是100%—这要求每次的数据都恰好满足“ARGB+特殊”这样的形式,但是在很多情况下,某次数据来了“A”,某次数据是“RGB”,某次数据是“GB+特殊”,也就是说实际情况下绝大部分指令都并不符合“ARGB+特殊”这样的设计需求。为了解决这个问题,人们设计了比如超标量、多级缓存、预测执行等手段来提升并行度,此外,加入了更深的流水线来细分指令,力求使得指令级并行能够提升效率。
随着计算机技术的发展,指令级并行规模大、效率低的弊端已经越来越明显,传统的指令级并行很难适应现代计算模型中复杂多变的、不规则的计算特性。线程级并行恰好可以用于进一步增大整个处理器的吞吐能力。举例来说,线程级并行中的流水线在当前任务上如果遇到无法解决的等待或者延迟,可以迅速切换到新的工作,线程级并行中的执行也没有了固定的排序方式,除了部分特殊计算外,其余指令都会面对几乎相同的计算单元。以AMD的GPU为例,新的GCN架构就是典型的线程级并行,它的CU单元拥有4组、每组16个ALU单元,由于取消了所谓的固定任务格式,GPU只需要根据需求将所有内容直接塞入CU单元即可,大大提升了效率。总的来说,目前桌面级别的处理器,都在向线程级并行转进,在移动SoC的GPU上,受制于功耗等原因,可能还存在一些指令级并行设计。毕竟目前移动SoC无论是性能还是特性水平依旧远远落后于桌面产品。在恰当的时候选择合适的架构,也是非常重要的。
GPU中的波次,图中展示了随着时间不同波次的计算任务被依次填充进入计算单元。
Midgard的每个计算单元,似乎都存在自己的线程判断和执行单元。
Midgard支持前后帧之间的图像比较,如果有部分没有改变,那么Midgard就会跳过这些部分,同时可以节省大量带宽和资源。
其实,Midgard的出现已经比较早了。Mali-T600系列在2013年就已经宣布。但是直到2014年Mali-T700系列发布后,Midgard以及相关的技术设计内容才开始逐渐多了起来。从架构角度来看,Midgard是一个特立独行的、非常具有ARM设计特色的产品,它在各个方面的设计都和目前比较主流的GPU方案有着明显的差异,而从目前的情况来看,Midgard架构的实际产品表现还是比较令人满意的。
16个Mali-T760组成的计算阵列,拥有32个独立运作的单元。
接下来的表格,对比了英伟达、IT、ARM以及AMD的一些设计方案。需要说明的是,由于目前在移动产品端,受限于规模和工艺等因素,ARM比较推荐Mali-T760MP10这样的配置,因此本文对比也以这款产品为主。
由于一些细节算法未知,因此对ARM Mali-T760MP10的性能估计存在两种可能。这两种可能的纸面能力差别还是比较大的。综合来看,在计算能力上,Mali-T760MP10比目前强悍的Tegra K1、PowerVR GX6650等要差一些,但是基本上和AMD A4-1350在一个水平线上。此外,Mali-T760MP10的像素和纹理能力看起来似乎不错,这在目前高清化移动设备中会有比较明显的优势。
总的来看,Midgard将是ARM在未来大约2到3年间,在移动SoC市场上主打的GPU产品。有了前代产品的成功,ARM自然也期待Midgard带来他们在移动SoC上的又一次胜利。不过,目前移动SoC的GPU市场,ARM还不是主力,凭借Midgard这样的设计和规模,究竟能带来怎样的改变,还得看市场风云变幻,如何发展了。