Intel Larrabee GPU 体系结构初览
从具体的名称而言,Larrabee 可算是一个在三年前就已经冒出来的名字,首次被证实的文件是一份 Intel “不小心”散布到网络上的幻灯片——"Tera Tera Tera"。在这份幻灯片中,我们首次看到了 Larrabee 的设计方向、大致架构,特别是其中提到的基于 x86 ISA 部分在当时更是引起了大家的轰动。
Larrabee 本质上的确是一枚基于 x86 的处理器,不过它的片上内核规模达到了前所未有的数目:32 个甚至更多,不过另一方面它又属于所谓的同 ISA 异质架构概念,这就给 Intel 带来了一系列的挑战,特别是如何确保较高的执行并行度、如何面对其首番出场所要面对的最大挑战——游戏图形渲染与通用计算的平衡。
和 NVIDIA、AMD 以及其他传统 GPU 厂商未到最后一刻绝不对外公布新 GPU 体系架构甚至根本不曾透露(例如 NV30)的做法不同的是,Intel 对 Larrabee 的体系架构除了一些执行细节外基本上是和盘托出,而这还是距它正式发布的应该有一年左右的时间点。
当然,不仅 Larrabee 如此,事实上 Intel 历史上发布的各种处理器大都能提供非常详细的数据表、手册、开发指南以及配套的开发工具,在技术资源方面力度上是毋庸置疑的。
如此大方的安排有助于我们大致了解 Larrabee 的架构,特别是对许多喜欢一睹为快的读者来说更是难得的机会可以了解未来 GPU 或者 many-core 处理器的发展方向。
不过在介绍 Larrabee 之前,我觉得有必要先说说其推出的背景,这对于了解 Intel 为什么要推出 Larrabee 以及如何实现 Larrabee 是至关重要的。
正如大家所知道的,从 DirectX 10 开始,Vertex Shader 和 Pixel Shader 的 ISA(指令集架构)已经是统一,VS 和 PS 都能在同一个单元上完成,加上 Stream Out 的引入以及各类开发工具的推出,把 GPU 应用于通用计算领域已经是渐入佳境的话题。
与以往学术机构里作学术研究的各种 stream processor 不同的是,GPU 有非常庞大、可以媲美桌面 CPU 的市场规模,这使得开发人员能够很容易就获得便宜的产品为大量的潜在用户做相应的 GPU 通用运算开发,为软件增加卖点并获取更高的附加值,没有多少人在怀疑这个市场已经在蠢蠢欲动。
让我们在看桌面 CPU 这面的情况,和整个 90 年代以增加门电路数量密度、时钟频率以及指令级并行相比,到了 2003 年整个业界都认识到了电力、发热的物理屏障已经让时钟频率的增长难以维继,而在指令级并行方面,实现复杂的分支预测、推测执行所占用的芯片成本与所能达到的性能提升相比也都开始变得不怎么划算了,摆在人们面前的性能提升道路似乎就剩下增加门电路这条路还是可以继续冲的。
在未来的 10 年里,我们相信半导体产业依然维持着每两年晶体管数量增加一倍的发展趋势,在这样的背景下,人们自然而然地想到了推出多核产品,这不仅仅是指目前大家看到的双核、四核,随着半导体工艺的推进,更多内核的 CPU 也将在未来的日子里问世,半导体厂商从来都不会让自己庞大的产能闲置着。
Intel 新近推出的桌面处理器为 Nehalem 架构,这个架构是在一枚 4 cores 的 45nm 桌面处理器,芯片面积大约是 246mm^2,支持SSE 4.2,在 3.2GHz 频率下的峰值浮点性能为 51.2 GFLOPS(双精度)或者 102.4 GFLOPS(单精度)。
基于 55nm(其实是 65nm half-node)的 AMD RADEON HD 4870 芯片面积为 260mm^2,750MHz 时峰值浮点性能为 240 GFLOPS(双精度)或者 1200 GFLOPS(单精度)。
不仅如此,现在 GPU 的带宽也是 CPU 所无法媲美的,例如 RADEON HD 4870 的内存带宽就是 115.2GB/s,而 Nehalem 搭配 DDR3-1066 的内存带宽也就是 26GB/s 左右,在内存容量方面,GPU 也正在迎头赶上,例如 NVIDIA Tesla 1060 就拥有 4GB 的卡载内存。
不过 GPU 内存子系统虽然有非常高的带宽,但是它的时延是非常高的,这主要是因为 GPU 主要针对的计算一直以来都比较少出现数据复用(data re-use)的情况,或者说局部性较差,因此基本上只是靠一小块的 FIFO(先进先出)作为缓存。
对于一些可能复用的地方,例如纹理过滤操作,就会采用比较简单的 read-only cache,不过庞大的多线程才是 GPU 克服内存时延的最大关键所在。
随着 GPU 踏足通用计算,data re-use 的场合越来越多,即使是现在游戏图形运算中时常遇到的 post processing,data re-use 也是司空见惯的事情,为此 GPU 厂商也都往 GPU 里加入可读写的软件管理 cache。
最早引入该概念的产品是 NVIDIA 的 G80,它有 16 个内核(称之为 Streaming Multiprocessor,或者简称 SM),每个内核内都有一块 16KB 大小、时延为 1 个时钟周期、具备 16 个 bank 的 SRAM,开发人员透过 CUDA 或者未来的 Compute Shader、OpenCL实现对这块 SRAM 的控制,而内核执行的线程结果可以在这里暂存实现高效的 data re-use。
到这里大家应该都很清楚从技术的角度而言,CPU 和 GPU 的发展都正面临着一个拐点,前者因为各种原因不得不延缓“ILP/频率”这个免费午餐而转向多核技术,而后者因为制造技术的发展所新加入的晶体管构成的功能模块不仅仅限于可以在图形渲染上使用,包括不少可以并行化的运算也都能拿到 GPU 上高效的执行。
这也就连带产生了市场争夺的问题。在很长的一段时间里,超级计算机、服务器这类被称作现金奶牛的市场都是由传统的 CPU 厂商提供运算部件,现在 GPU 厂商也要插一脚进来,他们在性能上的竞争力实在不容小瞥,而且已经有了一些现成的案例。
这不仅仅是高性能运算领域的问题,在以产量著称的桌面领域,GPU 涉足的通用计算也越来越让 CPU 厂商感到不少的隐忧,例如物理加速、视频处理、三维成品级渲染这类以往需要大量运算资源来完成的任务,GPU 厂商也都开始提供解决方案。
目前的 PC 市场普遍被认为进入了成熟阶段,这意味着市场容量在短时间内爆发性增长的可能性不大,所以 GPU 侵蚀 CPU 传统优势领域的下场将可能是 CPU 的份额受到挤压。
对于一般的 design house(设计公司)类型 CPU 厂商来说,这似乎不是什么大的问题,因为他们在营运上的成本主要是研发,而对于垂直型 CPU 厂商(IDM)来说,CPU 份额的下降意味着自己的最强优势——产能将变成非常沉重的负资产。
要避免这个问题的发生,最好的办法就是自己也推出类似的产品,Larrabee 就是 Intel 的答案。#p#page_title#e#
每个厂商都会竭力让自己站在最有利的位置上,IBM 有 Power Everywhere 的发展策略,Intel 作为 x86 ISA 的始创者自然也有自己的 x86 Everywhere 的算盘。
在历史上 Intel 曾经推出过若干款图形芯片,例如 80 年代末期的 i860,90 年代末的 i740,其中前者对部分读者可能不怎么熟悉,但是当年它的推出其实是引起了不少的轰动,在介绍 Larrabee 的时候我觉得还是有必要提一下这个东西。
在 1989 年的 Comdex 大展上,时任 Intel CEO 的 Andy Grove 罕有地没有发表任何演讲,根据后来发表的一些书籍指出,其原因之一在于 Intel 内部正对 RISC 和 CISC 未来的地位展开激烈的讨论,而 Andy Grove 正受到这个争论的困扰。
在当时有各种形形色色的 RISC 预言,例如“在 2005 年你会购买一台 MIPS 芯片的 PC,而你的邻居则会购买一台有 SPARC 芯片的PC”,“486 是 CISC 的黄金时代,但是它还可能是最后的一枚 CISC 处理器”,“586 是最后一枚真正的 CISC 处理器”。
不过 Intel 此时手上除了已经被确定为 386 替代品的 486 外,还有一个 RISC 处理器,这就是 i860。
1986 年,当 Intel 内部已经笃定 486 为 386 换代产品的时候,一位在 Intel 内为 RISC 呐喊了 4 年的工程师 Les Kohn 知道这是无法改变的现实后,决定改变方向,向 Intel 高层提供一个“为 486 设计”的基于 RISC 的协处理器方案——i860。
在 386 时代,Intel 也提供了与 386 配套但是单独出售的 387 协处理器,能够为 CAD、3D 工作站提供 386 10 倍以上的浮点性能,在这个产品上 Intel 获取了丰厚的利润。协处理器能赚钱,赚很多的钱,所以 i860 作为 486 协处理器的赚钱期望让 Intel 终于通过了 Les Kohn 的建议。
然而 Les Kohn 和他的团队的实际设计目标却是推出一个与 x86 家族截然不同的产品,i860 属于不折不扣的 RISC 处理器,但是与 387 和 386 的差别相比还不算太大,Les Kohn 的目标是希望 Intel 最终能比较愉悦地接受 RISC 的概念。
Intel 的 387 协处理器针对的是 3D、CAD、工作站用户,这类应用的用户对性能的追求高于对兼容性的追求,在当时看来 i860 的确是一个不错的 Intel 涉足 RISC 的突破口。
最终设计出来的 i860 是一枚 64-bit RISC 处理器,拥有单周期双指令发射能力以及集成了一个 3D 图形单元,与其它 RISC 处理器相比,比较特殊的是这枚 i860 在内存管理上复制了 386/486 的换页机制,这有助于 i860 能比较容易地运行为 386/486 编写的 C 代码,从纸面规格上来看的话,i860 远不仅仅是一枚协处理器而是一枚比一般 RISC 处理器更加强大的产品。
i860 和 486 一样都是一百万枚晶体管,但是在理论浮点性能和图形性能上 i860 都远优于 486,这看上去 RISC 的确存在一定优势。
但是i860 最终没能取得市场上的成功,这牵涉到多方面的原因,而最致命的原因却是从一开始就已经的被决定了:Les Kohn 要设计的实际上并非是一个能够赚钱的产品。
和 x86 相比它缺乏软件支持,而几乎当时所有的工作站厂商都选择了开发、设计自己的芯片,此外它的实际浮点性能也与设计目标相距不少距离,ALU/FPU 的切换需要花费大量的时间,使得它无法成为真正意义上的CPU,更多的是作为它当初被举荐时候的"想法"——工作站图形加速器使用。
i860 乃至以后的 Pentium Pro、Itanium、Netburst的发展证明,Intel 一直都没有把所有的鸡蛋放在同一个篮子里,与这些架构并存的一直都有被证明是成功的“旧架构”并存,486、Pentium、Pentium M 等,这得益于 Intel 强大的技术储备和研发资金来支撑,而其他处理器公司大都由于资金限制选择了孤注一掷的产品研发模式。
在 Intel 推出 Larrabee 之前,曾经生产过一枚代号 Polaris 的 80 核处理器,这个芯片是被作为未来 Intel many-core 计划的原型来设计的,片上内核的数量、内核间的连接方式、高带宽的 3D Stack 内存实现是这枚芯片的主要试验目标。
80 个内核、成本高昂的 2D Mesh(网面式)内部连接网络、3D Stacked 内存等一系列在 Intel 历史上从来没有真正尝试过的技术都在这枚 Polaris 实现了,然而这些试验的成果可能由于时间的关系以及成熟度、可行性等原因,并没有没反映到 Larrabee 上。
按照 Ars Technica1 的报道,Larrabee 采用的内核是基于 x86 的 P54C(80502)。而历史上的 P54C 架构上属于 P5 的 debug 版,早于支持 MMX 的 P55C(80503)。根据这篇报道,当年 Intel 完成 Pentium 的设计后,交给了美国五角大楼,五角大楼将其用于耐辐射的军事用途。
而五角大楼有自己的半导体工厂来生产这些军用的 P54C,由于苛刻的应用环境,五角大楼还对 P54C 的 RTL(Register Transfer Level,逻辑综合)代码进行了彻底的除错,当若干年后这个军品版 P54C 完成了历史使命后,五角大楼将清理好的代码交给了 Intel,这就是 Larrabee 内核的来源。
更确切的事实来自于 Intel 于 Siggraph 08 发表的 "Larrabee: A Many-Core x86 Architecture for Visual Computing" 一文中所指出的:
对 Intel 来说,x86 的软件价值实在是其最大的资财,在历史上它替 Intel 战胜了几乎所有的桌面电脑、工作站、小型机处理器厂商,甚至包括 Intel 自己采用其他 ISA 的产品。Larrabee’s scalar pipeline is derived from the dual-issue Pentium processor, which uses a short, inexpensive execution pipeline.
这次来自 GPU 的挑战在 Intel 看来不过是当年 RISC vs. CISC 争战的延续或者翻版而已,采用基于 x86 的 many-core 也许可以应对这样的挑战,而这也是对自己最有利的方案。#p#page_title#e#
虽说 Larrabee 与 P54C 有一定的关系,但是从实际的体系架构来说,我们认为两者实际上是存在巨大的差异,对 Intel 来说 x86 的引入只是为了能发挥其既有的传统软件优势,为未来 many-core 的大规模导入进行预演,而在当下 Larrabee 首先必须作为 GPU 推向市场,这样才能有利于普及产品,这是非常重要的一步。
Larrabee 可以有多种配置形式,上图为 16 核版本的架构图
Larrabee 是由许多个 in-order(顺序执行)的内核以及纹理单元、内部环路、内存控制器、总线控制器等单元组成,具体的组合形式取决于针对的应用场合,例如作为 GPU 的时候就会整合进 PCIE 作为总线界面,如果是应用于主板上作为协处理器使用的话,还会整合进 QPI 界面。
在 Intel 的 SIGGRAPH 08 论文中提供了一份 65nm Core 2 Duo 处理器与同样制程但是支持 Multithread(4 Thread) 并具备 16-way SIMD 向量单元的 Pentium 内核更新版的对比,用来说明采用 in-order 执行的流水线在吞吐先决的场合在同样的面积、耗电指标下所具备的性能优势。
CPU | Core 2 Duo | 类似 LRB 的 Pentium 更新版 |
流水线设计 | 乱序执行[OoOE] | 顺序执行[In-Order] |
内核数量 | 2 | 10 |
各内核单周期指令发射能力 | 4 | 2 |
各内核 VPU 运算能力 | 4 | 16 |
iL2 cache 容量 | 4MB | 4MB |
各内核单指令流吞吐能力 | 4 | 2 |
共计向量吞吐率 | 8 | 160 |
代号 Conroe 的 65nm Core 2 Duo 芯片面积大约是 143 平方毫米,不过在耗电方面, Conroe 有多种频率规格,而频率与功耗是存在一定的正比关系,在无法确知 Intel 所谓的同样功耗情况下其实是指什么频率规格。
真正的10 个 Larrabee 内核实际上是没有那么大的 L2 cache 而且是有 FMADD 指令支持的。Larrabee 也不仅仅只有“内核”,还有内存控制器、外部总线控制器、纹理单元、内部环路等组件,这些组件毫无疑问也是需要占用大量芯片面积。
做一个对比好了,如果单纯计算所谓的内核,NVIDIA 65nm GT200 30 个“内核”占的面积大约是 148.8 平方毫米,是整个芯片面积(583.2 平方毫米)的 25%。
我们其实比较难直接对比上表中两者的浮点性能,表格中能反映的只是 Core 2 Duo 和 10 个类似 Larrabee 架构的内核但是并不实际存在的东西的浮点指标对比,不过从向量吞吐率指标来看,两者在同频率下的差别的确较大。
之所以如此,是因为 OoOE 的内核主要是为了追求指令级并行(ILP),有非常复杂的指令控制单元,而 in-order 在这部分上的处理比较简单,随着多线程技术的引入, in-order 可以把更多的资源放在扩展数据级并行(DLP)和线程级并行(TLP)上,提供比 OoOE 流水线内核更强大的向量吞吐率。
OoOE 流水线与 in-order 流水线各有特色,前者能维持较高的 ILP,但是流水线的复杂度较高,而后者的流水线复杂度低不少,能够在同样的面积、功耗下透过向量技术、多内核、多线程以及适当的固定功能硬件电路等措施加持达到非常高的浮点运算吞吐率。
这使得 in-order 流水线在几乎所有浮点运算吞吐先决应用场合中成为首选,例如所有的 GPU 以及 XBOX 360 的 Xenon、Playstation 3 的 Cell、SUN 的 UltraSPARC-T1/T2 等等。
Larrabee 糅合了许多目前类似产品的特征,同时结合 Intel 自己的优势,加入了诸如 x86、SMT、QPI、大容量 cache 等技术,再赋予 Intel 强大的软件开发支持,力图成为一个 many core 时代的标志性产物,我们下面给大家进一步介绍其架构细节。
上图就是 Larrabee 其中一个 CPU 内核、内部互连网络、该内核所属的 L2 cache 局部子集。
Larrabee 内核的指令解码器能转译标准的 Pentium 处理器 x86 指令、x86-64 指令以及专门定制的 VPU 指令(LRBni)。
为了简化设计,标量单元和向量单元都有自己独立的寄存器,彼此的数据传输/交换是需要先写入到内存,然后再读回到 L1 cache 里才能完成。
Larrabee 的 L1 cache 可以让标量单元和向量单元实现对内存的低延迟高速缓存化存取,结合向量单元(VPU)的 Load 操作就能让 L1 cache 像是一个扩展的寄存器堆,让许多算法的性能得到显著的提升,尤其是使用 Larrabee 提供的 cache 控制指令。
Larrabee 的内核具备 SMT 多线程技术,为了让这 4 个硬件线程得以充分发挥性能,Larrabee 内核的 L1 指令 cache 和 L1 数据 cache 从 Pentium(单线程)的 8KB+8KB 扩展为 32KB+32KB 了,这恰好是匹对线程数。
Larrabee 拥有一个基于目录式一致性设计的二级高速缓存(L2 cache),每个 Larrabee 内的 CPU 内核都在这个 L2 cache 内有自己对应的区域,这个区域的大小为 256KB。
所谓的“一致性”简单来说,就是指在一个存储器系统中读取任何一个数据项返回的结果必须确保总是最近写入的数值。
在单处理器环境中这个问题很简单,但是在多处理器的情况下,由于各个处理器很多时候都有各自独立的 cache (Larrabee 就是这样),那么情况就会复杂许多,而不同的一致性协议设计对性能都有直接的影响。
一致性协议最常见的就是监听式和目录式,监听式需要较高的的总线带宽,一般只用在小规模的多处理器系统中,而像 Larrabee 这样多达 32 内核的设计,如果使用监听式协议的话,内部总线的成本将非常高。
故此 Larrabee 的 L2 cache 采取了目录式的设计,当然这也和 Intel 已经掌握了丰富的 cache 一致性设计经验有关,而像 NVIDIA 这样的 GPU 厂商在可读/写 cache 上的设计经验与 Intel 相比就可能有较大的差距。
Larrabee 的每个内核都有连接到自身 L2 cache 子集的直达通道,因此各个内核能够一起并行地对自身 L2 cache 子集进行访问操作。内核所写的数据会被存储于自身的 L2 cache 子集内并在必要的时候可以被其他内核对应的 L2 cache 子集所冲刷掉。Larrabee 的内部环状总线网络能确保共享数据的一致性。#p#page_title#e#
Larrabee 的标量运算单元实际上就是衍生自 Pentium 处理器的双发射超标量流水线,同样存在类似 Pentium 那样的 U、V 两条流水线,其中的主流水线和 SIMD 16 路向量单元共享部分资源。
标量单元能支持 Pentium 处理器的所有 x86 指令,可以运行对应的操作系统内核和应用程序,主要的区别是加入了 x64 指令、新的标量指令例如 bit count/bit scan 、cache 控制指令和 4 个硬件线程的执行能力。
Larrabee 新引入的 cache 控制指令和指令模式能够实现显式的 cache 控制,例如可以实现往 L1、L2 cache 预取数据的指令和降低 cache line 优先权的指令模式。
流式数据通常很快就会把 cache 内的数据挤兑掉,Larrabee 能够在每条流式数据的 cache line 被访问后进行标记以便提前清空。这些 cache 控制指令同样允许 L2 cache 可以像一个擦写板内存(scratchpad memory)那样使用的同时实现完全的一致性,对于提高性能有莫大的裨益。
对于 Larrabee 单个内核内而言,透过多个线程来对 shared memory 进行同步存取的代价并不高。位于单个内核的线程共享相同的本地 L1 cache,因此在 L1 cache 内就能满足完成一个单独的原子旗语读取。相较而言,多个内核之间的同步存取成本就要高多了,因为这需要透过处理器之间的锁定来实现,当然这是一个多处理器设计中众所周知的难题。
多指令发射 CPU 的性能损失通常是由于难以找到能一起匹配执行的指令。按照 Intel 自己的测试,Larrabee 的双发射解码器拥有较高的多发射率,主、副指令流水线的匹对原则在这里起关键性的作用,它允许编译器在比一个运行时式的乱序指令采集器更宽的范围内进行离线分析。
所有的指令都能发射给 Larrabee 标量单元的主流水线执行,这让编译器的指令合并难题降低到最低。而次流水线能够执行 x86 的大多数标量指令(包括 load/store、简单的 ALU 操作、cache 处理)以及向量 store 指令。
编译器毕竟不是万能的,对于编译器无法实现并发的代码调度造成的阻塞问题,Larrabee 的 4 硬件线程执行能力可以在一定程度上予以掩盖。
当数据不能预先预取至 L1 cache 而需要从 L2 cache 装载至 L1 cache 造成的时延问题,硬件多线程执行同样能予以掩盖。当在相同内核上使用相同的数据组时,运行多个线程同样能提高 cache 的效率
Larrabee 向量单元(VPU)的最高向量处理宽度为 16,可以执行整数、单精度/双精度浮点指令,Intel 专门找来了多位业界的资深开发人员一起协作开发专门针对 Larrabee VPU 的指令集——LNI。
VPU 加上它的寄存器所占的面积约只相当于单个内核面积的 1/3,但是它所提供了 Larrabee 的绝大部分性能。
Larrabee 的 VPU 是一个 16-路宽度的 SIMD(单指令多数据)向量处理器,按照 Intel 的说法这是在高运算密度和运算单元利用率上的一个折衷选择。
依照 Intel 的早期分析,如果采用 16-路单元一次处理 16 个像素单个组元,即采用分离的指令分别处理像素中的红、绿、蓝等组元而不是一次合并处理像素的多个色彩组元,在这样的方式下典型像素着色器程序(pixel shader)的演算效能可以达到 88%。
Larrabee 的 VPU 指令支持 3 个源操作数,第一个源操作数以及目标数是同一个而且通常必须位于向量寄存器中(某些指令中,头两个源操作数的第一个必须是 mask revister),但是指令中的最后一个源操作数可以来自于“内存”,如果数据已经预取至 cache,那么此时的 L1 cache 可以看作是一个扩展的寄存器堆(register file)。
对于 madd 以及 multi-sub 指令,第一个源操作数既是源数也是目标数,因此它们都没有非破坏性的形态,只有专门设计用于内插的 vmadd233 指令是例外。
VPU 可以读取自 cache 的数据类型包括了 8-bit unorm、8-bit uint、16-bit sint 以及 16-bit 浮点数据,它们都能在不损失性能的情况下被转换为 32-bit 浮点数或者整数,由此可以显著增加可存储于 cache 内的数据类型并降低专用数据转换指令的需要。
Larrabee 向量寄存器中的数据可以多种方式在排列上进行对调(即 Swizzle 或者 Re-Order),以达到可以对正 VPU 处理单元通道的需要。位于 cache 内的数据可以直接“复制(Replicate)”到 VPU 的单元通道,这个功能可以在图形运算和非图形运算的时候使用,能显著提高 cache 的利用效率。
Larrabee 的 VPU 能支持多种类型的浮点、整数数据指令,指令集提供了标准的算术操作(例如 fused multiply-add)、标准的逻辑操作(例如从像素中提取出非字节对齐的栏位),这些都是属于从寄存器或者内存读取并把结果写入到向量寄存器的 load-op(装载操作)的指令。
配合 load/store 指令,VPU 就能支持在大多数 GPU 中一些较少见或者更复杂的数据格式与浮点值之间进行转换的操作,对这类操作采用分离指令或者说软件执行的方式可以显著地节省芯片面积和电力消耗,而代价只是些微的性能损失。
VPU 的指令还支持 gather 和 scatter 式的操作,允许往非连续的地址进行 load 或者 store 操作。VPU 的 16 个数据元可以自 16 个不同的向量寄存器地址进行 load 或者 store 操作而不是只能在单个的向量寄存器地址上进行。
这两个功能的实现可以让 VPU 的 16 个运算单元并行地执行 16 个 shader instance,而每个看起来像是在串列的方式来执行,甚至在使用运算出来的索引来执行数组存取的时候也能如此。
Gather 和 scatter 的性能受限于 cache,因为每个周期 VPU 只能 load 或者 store 一条 cache line,如果地址分布在若干 cache line 里,那就需要若干次的 load/store,使得 gather 和 scatter 的性能大打折扣,例如地址分布在 16 条不同的 cache line 内就必须需要 16 个周期才能完成一次 gather 或者 scatter 。
按照 Intel 的说法,由于许多工作负荷都具有高度的连贯性存取样式,因此 gather 和 scatter 的存取周期要远低于 16 个周期。
透过一个 mask(遮罩)寄存器(VPU 的每个运算通道都对应一个位元的遮罩寄存器),Larrabee VPU 指令执行能够被予以论断(predicate)。这个 mask 控制向量寄存器或者内存位置哪些部分被写或者不被更改。
举例,一个标量的 if-then-else 控制结构能够透过一条指令来设置 mask 寄存器以基于比对的方式映射(map)至 VPU,而后 VPU 以 mask 寄存器控制的相反极性既执行 if 从句部分也执行 elsa 从句部分,而不管运算完成后是否写入结果。
;if (v5<v6) {v1 += v3;} |
以动画形式展现上面的简单分支程序如何在 Larrabee 上被执行
只有 mask register k7 为 1 的通道的数值才会被完整保存
k7 为 0 的通道的数据均被写入 1
当 mask 寄存器内都是 0 或者 1 的话,条件从句能被完全地中止掉。这样能够减少少数从句出现分支预测失败而遭遇的性能惩罚,同时也让编译器的指令调度器有更高的自由度。
VPU 同样使用这些 mask 寄存器来给 load/store 指令打包,从而在连续的内存地址中访问允许的数据元。这样程序员就能在满足复杂分支条件的情况下整合稀疏的执行 strand(缕程),使其成为一个能更有效实现向量计算的格式。
按照目前公开的 Larrabee 指令集架构资料,VPU 的 mask 寄存器数量是 8 个,寄存器位宽是 16-bit。#p#page_title#e#
Larrabee 采用了双向的环形总线网络,允许芯片内的代理(Agent)例如 CPU 内核、L2 cache 以及其他逻辑模块彼此沟通。如果 CPU 内核的数量超过 16 个的时候,就会采用多个短连接环型总线来挂接,这个结构被称作 X-Ring。
每条环形数据总线的各向位宽是 512-bit,所有数据的行程安排都是在注入信息至环形总线之前就已经确定。例如,每个 agent 能在双数周期的时候从一个方向接纳一个信息包,在奇数周期的时候从另一个方向接收另一个信息包。
这样的安排能简化环形网络的路由逻辑,当数据出现在网络上时,这些数据无需被保存在路由器单元中,从而可以实现在非常小的代价下提供竞争最小化的高带宽。
Larrabee 环形网络最初的设计是把 L2 cache 和 内核都作为 agent 挂在总线上,以方便实现一致性,但是这样带来的问题是对 Larrabee 来说,环形总线面临的传输压力极大,结果这个设计很快就被抛弃了。现在 L2 cache 配属给每个 Larrabee 内核,成为 内核的一部分,应用先进的一致性协议以及 cache 控制指令,确保总线的压力尽可能地低。
Larrabee 的 L2 cache 被设计为每个内核可以高带宽地存取没有被其他内核写入结果的内存地址,因此每个内核的数据都是保存在自己对应的 L2 cache 子集部分内。各个内核可以并行地存取自己所属的 L2 cache 子集,而无须与其他内核进行通信。不过,当在 L2 cache 中分配一条新的 cache line 时,环路网络会被用于检查数据共享,以维持数据的一致性。
这个处理器内部网络本身也是作为一个 L2 cache 存取内存的路径。一个典型的高端产品会包括多个标准设计(例如 GDDR3、GDDR5)的内存界面,这些内存界面分散挂接于处理器内部网络上的若干处以降低拥挤度。
在片上网络环绕的延迟会增加内存存取的时间,但是相对于存取外部内存的延迟,额外的环路延迟通常显得非常低。
Larrabee 的 CPU 内核可以透过这个片上的环形网络总线对固定功能单元进行访问,而后者也可以访问 L2 cache 和内存,和内存控制器一样,这些固定功能单元分散地挂接在环形网络的若干处以降低存取竞争。
现在的 GPU 包含了若干功能固化逻辑单元用于不同的图形运算任务,例如纹理过滤、显示输出处理、后着色器阿尔法混合、光栅化(rasterization)以及内插等。
光栅化在这里仅是指确定一个图元(primitive)覆盖的 fragmet(片元)位置以及依照图元的覆盖样本位置参数值进行内插的动作。
功能固化单元通常需要若干 FIFO(先入先出)缓存实现负载平衡,这会导致难以在避免浪费芯片面积和性能瓶颈的情况下正确地确定这些逻辑电路及其 FIFO 缓存的大小。
Intel 对 Larrabee 的设计理念是只要软件执行方式的性能足够,相应的功能固化单元就采用软件执行方式取代。例如,Larrabee 上就没有包含光栅化、内插或者后着色器阿尔法混合等功能固化单元,使得 Larrabee 可以增进新的功能和最佳化措施,被取代的任务可以在渲染流水线不同位置执行,取决于具体的应用程序在什么情况下能达到最高效率。
采用软件方式执行后 Larrabee 可以依据它们对性能的需求进行运算资源分配,而不是设计一些为了攀爬峰值性能的硬件电路。
Larrabee 保留了纹理过滤单元,原因是 Larrabee 的内核还不能高效的执行纹理过滤操作。根据 Intel 的分析,在 Larrabee 的内核上以软件方式执行纹理过滤操作,性能只有 Intel 自己设计的纹理单元的 1/12~1/40,性能幅度取决于是否启用了纹理解压缩。
对此,Intel 将原因归结为 4 点:
-
纹理过滤依然普遍采用 8-bit 色彩组元,这类组元在专用电路上处理比 32-bit 宽的 VPU 运算通道更有效。
-
要高效选择未对齐 2x2 四方图块进行过滤处理需要一个特定流水线类型的 gather(聚集)电路。
-
读取纹理数据至 VPU 用于过滤处理造成的寄存器堆带宽压力近乎不可行。
-
在专用硬件上执行即时纹理解压缩的效率要远远高于 CPU 内核。
Larrabee 的纹理过滤单元在内部特征上和典型的 GPU 纹理单元相当类似,每个 CPU 内核拥有 32KB 纹理 cache ,纹理单元可以支持所有的常见操作,例如 DirectX 10 已压缩纹理格式、mipmapping、各向异性过滤等。
Larrabee 的内核透过 L2 cache 向纹理单元发送指令并透过 L2 cache 接收纹理单元的运算结果。纹理单元和内核使用同样的 x86 虚拟内存页面。纹理单元执行虚拟至物理页面转换并向 Larrabee 内核报告所有的页面缺失,当页面在内存的时候,内核发回纹理过滤指令给纹理单元。
只要软件执行方式的速度足够快,Larrabee 也可以直接使用其 CPU 内核执行纹理操作。#p#page_title#e#
Larrabee 本质上是由若干 CPU 内核构成的 many-core (众核或者说群核)处理器,理论上可以采用几乎所有风格的渲染方式,但是前提是必须能实现高度的并行化,Intel 在 Larrabee 的论文中阐述了基于 sort-middle 方式的软件图形渲染器,采用 binning(分仓)来实现负载平衡来实现高效的图形并行处理运算。
什么是 sort-middle? |
所谓的 sort-middle 是相对 sort-first、sort-last 而言,sort 在这里指的是从模型空间转换为屏幕空间。
Sort-first 是在图形渲染流水线的开始阶段就将图元(primitive)分配到各个渲染节点,一般用于多屏输出或者像 AFR、SFR 这样的多 GPU 渲染方案;sort-last 是在光栅化后重新分布像素;而 sort-middle 则是在几何变换(geometry transform)与光栅化之间重新分布图元。
sort-last 和 sort-middle 比较符合图形流水线的自然形态,适合硬件实现,SGI 的 Reality Engine、Infinite Engine 属于 sort-middle;大多数的 GPU 以及 NVIDIA NVSG-Scale 的多 GPU 渲染方案都属于 sort-last 中的 sort-last fragment。
除了这三种主要的 sorting 方式外,还有其他的 sorting,例如将三种 sorting 混合的方式。
关于 sort-first 和 sort-last,大家可以参阅 NVIDIA NVISION08 上的一篇幻灯片:NVISION08-Does_Your_Software_Scale.pdf
基于 sort-middle 模式的渲染器大致可以分为 Tile-based(拼图式或者说图块式)和 Interleaved-based(隔行式)两种,SGI 的 Reality Engine 属于 Interleaved-based,而 ImgTech 的 PowerVR 以及 ARM 的 Mali 都属于 Tile-based。
RTset 的定义 |
在 Intel 的文档中,Larrabee 采用的是 Tile-Based 的渲染方式,我们以假设渲染一组单独的 render target(渲染对象)(例如一个像素缓存和一个深度缓存)为例简单介绍 Larrabee 的渲染原理。
在 Larrabee 中这些 render target 以及对他们进行更动的渲染指令一起被称作 RTset。
Primitive Set 的定义 |
RTset 的渲染指令通常由图形 API 所定义一系列遵照当前设备状态对一个三角形 batch (批组)渲染时的渲染状态变化。Larrabee 渲染器并不采用当前本性状态的观念,而是采用在单一完整定义的结构中捕获渲染状态(这里所谓的单一完全定义结构简单来说就是指一个 Tile)。
而后 Larrabee 将三角形的 batch 分组并依照使用状态对每个 batch 打上 tag(标签)。这些是三角形的 batch 及使用状态被称作 primitive set (图元集)或者 PrimSet,大致相当于 Direct3D 里 DrawPrimitive,不过两者并不完全对等。
RTset 的渲染与 tile、bin 的定义 |
上图就是 Intel 提供的对单个 RTset 的 PrimSet 进行渲染的大致流程。渲染的画面被切成若干像素组成的 tile(图块),每个 tile 都有一个 bin(图元仓)来放置 PrimSet 中与该 tile 交叠的三角形。对应整个 RTset 的 bin 被称为 bin set。有时候 tile 和 bin 在术语上是相通的,不过在这里 tile 是指实际的像素数据,而 bin 是指映射至 tile 的 primitive set(图元集)。
每个 tile 都有一个 bin,bin 内放的是与之对应的 tile 内交叠的三角形
简而言之,每个 tile 都有一个 bin,每个 RTset 都有一个单独的 bin set。
除了三角形外,bin 内还保存有已经着色的顶点、完成光栅化的 fragment(片元),所有的 bin 都保存在片外的内存(例如显卡内存甚至系统主内存)上。
Tile 的尺寸与性能影响 |
每个 tile 的大小是依据 RTset 的目标表面来设置:tile 的尺寸要能完全放置到 Larrabee 内核的 L2 cache 里。因此,相对使用较少、较低色彩通道的 RTset, 一个有许多色彩通道或者使用高精度数据格式的 RTset 所采用的 tile 尺寸就更小了。
为了简化代码,tile 的尺寸通常是正方型或者平方数,典型的大小为 32x32 至 128x128。
如果采用 32-bit 深度和 4D*8-bit 色彩的话,一个 128x128 的 tile 只会占用 256KB L2 cache 的一半空间,如果是 32-bit 深度,4D*32-bit,就可能需要把 tile 尺寸降低到 64x64,因为 128x128 32Z+128C 占的空间已经撑爆掉 L2 cache。
只要 tile 能完全放置在 L2 cache 内,即使是不同尺寸的 tile 渲染速度都不会有显著的波动。
尺寸较小的 tile 面临的的问题主要是场景中的某些三角形会在多个 tile 上交叠,因此每个被交叠 tile 都需要对这些三角形进行处理,术语上这被称作 bin spread (图元仓跨界)。Tile 越小出现 bin spread 的机会就越高,不过按照 Intel 的说法,在现在的渲染应用中出现 bin spread 的机会小于 5%,这意味着需要重复处理的跨界三角形数量相对单个覆盖整个 render target 的 bin 来说少于 5%。