2013年1月31日星期四

2013"应用处理器"微架构 - 长话短说"微架构"




第1页:什么是应用处理器?
对不起,你被标题欺骗了,实际上对许多读者来说要读懂本文并不是那么轻松:p
随着半导体工艺的日趋先进,智能手机(Smartphone 或者 Superphone)、平板电脑(Tablet 或者 Pad)已经成为许多网友最常使用、最多关注、更新最快的电子消费产品,高度便携性是这类产品的最关键成功原因。
所谓便携性自然是指产品必须足够轻便而且需要有足够的续航能力,因此这就要求产品的原件必须足够省电,只有这样才能减少散热和电池体积这两个最占体积和重量的问题。
要达到这个目标,肯定要做功能和性能上的妥协,至少相对个头更大的笔记本电脑、台式机而言,像降低吞吐率或者增加时延,从实测性能而言,目前智能手机或者平板电脑的 CPU、图形处理器性能基本上相当于 6 到 10 年前台式电脑的水准。
举个简单的例子,在俄罗斯网站 ixbt 的讨论区上,有这样的一条帖子,一位名为 ssvb 的网友采用 origenboard.org 的一片 Samsung Exynos 4210 开发板(配有 Exynos 4210 处理器具备两个 ARM Cortex-A9 处理器内核)跑出来的 High Performance Linpack (HPL)性能是 1.307 GFLOPS,同贴中还有 Intel Atom N450(Pineview 架构,45nm,单核) 1.66GHz 的测试结果——0.944 GFLOPS 以及 Cortex-A15 1.7GHz 双核 HPL 为 4.3 GFLOPS
NVIDIA 官网上的一份 SC011 文件也表明 Tegra 2(ARM Cortex-A9 双核 1GHz,理论双精度浮点性能 2GFLOPS)的 HPL 性能为 1.15GFLOPS( 57% 效率,200MFLOPS/瓦) 。
这都是一个什么概念?我曾经在 06 年的时候用 Pentium D 820 2.8GHz 跑出来的 HPL 性能为 10.12 GFLOPS,Athlon64X2 2.6GHz 为 9.158 GFLOPS。
那么现在台式机的 HPL 性能状况如何?
在去年我用 Core i7 2600K 3.4GHz 配合未支持 AVX 指令的 GotoBLAS(数学库)上得到的 HPL 性能为 51.18 GFLOPS 左右,后来又用支持 AVX 的 OpenBLAS(原 GotoBLAS 开发者停止更新后的其中一个后续开源社区版)得出的 HPL 性能为 99.38 GFLOPS,到 2013 年支持 AVX2 指令集的 Haswell 架构出来后,这个测试结果应该还能接近再翻番,达到 200 GFLOPS 级别。
也许你会说手机、平板要双精度干啥呢?请不要忘记在 30 年前的 x86 处理器根本没有集成任何硬件浮点单元,现在的情况又如何?曾经做出号称最强 x87 协处理器的 Cyrix 后来一头扎进整数为王的产品策略后现在影都没了。
“干啥”这个问题往往是硬件具备并达到一定性能条件后就会有答案的,台式机上的性能测试软件和方案会随着手机、平板性能日益强大而变得在这类设备上运行也理所应当,除了上面说的 HPL 外,各类 PC 上流行的测试工具例如 SPEC CPU20xx、3DMark 等也会是如此。
传统的 CPU 性能测试的确不能完全适用于手机、平板的 SoC 芯片(人们把可以在移动操作系统上跑应用软件的 SOC 称作应用处理器,简称 AP),但是请注意我说这句话是因为 SoC 并不仅仅有 CPU,还有 GPU、音视频编解码器、存储控制器、非易失性存储单元、数模/模数转换器以及各种输入输出周边等,这使得我们要单纯评价一款 SoC 是否最佳的时候可能会感到颇为伤神。
话虽如此,不过总的来说,SoC 中和性能最密切相关的依然是 CPU、GPU,因为智能设备里几乎所有程序的运行都必须依仗两者来执行,与用户的使用感受有直接关系(请注意,我们这里说的只是指 SoC 芯片中,而非手机或者平板电脑整体)。因此,纵然手机、平板处理器型号各异并且内中千头万绪,我们还是应该从大家最关心的 CPU、GPU 着手来了解。
现在情况简单多了,按照 ISA(指令集架构)划分,因为目前的手机、平板 CPU 无非是 ARM、Intel/AMD 两大阵营,潜在的还有 MIPS,不过目前 MIPS 似乎在这个领域还成不了气候,更像是一个备胎。 
如果你对计算机科学还不是很了解的话,对 ISA 这个词可能也不会很了解,虽然它经常出现在一些时髦的技术文章中。
电脑显然并不能直接明白 C、Java、Basic 这样的高级语言(虽然有人尝试过开发高级语言处理器,但是无不失败告终),搭建在高级语言和 CPU 本机代码之间的就是 ISA。
ISA 的全称是 instruction set architecture,中文就是指令集架构,有时候直接称呼为架构(architecture),是指程序员实际“可见”的指令集,包含了程序员编写一个能正确运行的二进制机器语言程序的所有信息,涉及到指令、 I/O 设备等。例如 Intel 的 IA-32、Intel 64(曾经名为 IA32e、EM64T 等);ARM 的 ARMv7、ARMv8 等等。
这里的 IA32、Intel 64 或者 ARMv7、ARMv8 其实是指各自指令集架构的不同版本,有时候我们嫌啰嗦,所以把前两者统称 x86,后两者统称 ARM。
将 ISA 变成真正可以使用的实物需要经过“实现”,它包括两个层面:组成和硬件。
组成是从计算机设计的高阶层面而言,例如:存储系统、存储互连接、CPU(包括算术、逻辑分支、数据传输的实现)设计,有时候“组成”又被称作微架构(microarchitecture),英特尔 Nehalem、NVIDIA Kepler、ARM Cotrex-A57 都可以属于各自某系列芯片的微架构,其中 Kepler 的 ISA 是 CUDA PTX 和 Cortex-A57 的 ISA 属于 ARMv8。
硬件通常是指电脑的规格,包括具体的逻辑设计、封装技术,同一系列的产品可能有相同的 ISA、近乎一样的微架构,但是存在某些具体规格的差别,例如 NVIDIA Tegra 3,有 AP30、AP33、T30、T33、T30S、T33S、T30SL 等具体的型号,它们都属于 Tegra 3 微架构,但是频率规格、内存规格等地方都有差别。
而 GPU 方面则复杂一些,有 PowerVR、高通、NVIDIA、ARM、Intel 等等,其中使用最广泛的就是 PowerVR,这得益于 PowerVR 10年前就决定全面切换到移动设备上,铺桥搭路的功夫很扎实,而 NVIDIA 和 Intel 的商业模型都是只用于自家产品(当然 NVIDIA 也曾经在游戏机领域做过 RSX 这样的 IP core 授权)的,所以目前未能在其他 SoC 上看到。
下面的表格给出了这两年来比较热门的手机或者平板电脑 ARM 处理器,它们基本上都被应用于各公司的旗舰级产品中。
2011/2013 SoC 对比表
SoC制程CPUGPU内存总线发布时间
Apple A545nm/32nm2 x ARM Cortex A9 w/ MPE @ 1GHzPowerVR SGX 543MP22 x 32-bit LPDDR22011-10-4
Apple A5X45nm2 x ARM Cortex A9 w/ MPE @ 1GHzPowerVR SGX 543MP44 x 32-bit LPDDR22012-3-16
Apple A632nm2 x Apple Swift @ 1.3GHzPowerVR SGX 543MP32 x 32-bit LPDDR22012-9-12
Apple A6X32nm2 x Apple Swift @ 1.4GHzPowerVR SGX 554MP44 x 32-bit LPDDR22012-10-23
NVIDIA Tegra 240nm2 x ARM Cortex A9 @ 1GHzULV GeForce T21 x 32-bit LPDDR22010-1-8
NVIDIA Tegra 3/Kal-El40nm4 x ARM Cortex A9 w/ MPE @ ~1.3GHzULV GeForce T31 x 32-bit LPDDR22011-11-8
NVIDIA Tegra 4/Wayne28nm4 x ARM Cortex A15MPCore w/MPEULV GeForce T42 x 32-bit LPDDR22012-1
Samsung Exynos 421045nm2 x ARM Cortex A9 w/ MPE @ 1.2GHzARM Mali-400 MP42 x 32-bit LPDDR22011-2-10
Samsung Exynos 421232nm2 x ARM Cortex A9 w/ MPE @ 1.5GHzARM Mali-400 MP42 x 32-bit LPDDR22011-10-1
Samsung Exynos 525032nm2 x ARM Cortex A15MPcore w/ MPE @ 1.7GHzARM Mali-6042 x 32-bit LPDDR22011-11-30
Qualcomm MSM8060/8260/866045nm2 x Scorpion @ 1.5GHzAdreno 2201 x 32-bit LPDDR2*2011-2-10
Qualcomm MSM896028nm2 x Krait @ 1.5GHzAdreno 2252 x 32-bit LPDDR22011-2-14
Qualcomm MSM8960T28nm2 x Krait @ 1.7GHzAdreno 3202 x 32-bit LPDDR22012-2-27
Qualcomm APQ806428nm4 x Krait @ 1.7GHzAdreno 3202 x 32-bit LPDDR22011-2-14
它们都属于 ARMv7 架构,架构寄存器数量为 16 个,其中 Tegra 2/3、Exynos、A5/A5X 的 CPU 核心是 Cortex A9 或者 Coretx A15,都是来自于 ARM 的 IP core 授权,而 A6/A6X 的 Swift 和高通的 Scorpion/Krait 则分别是苹果和高通获得 ARM 架构授权后而各自自行开发的。
众所周知,IP core 的全称是 Intellectual Proerty core,意即知识产权内核,是目前各种嵌入式应用、个人智能消费类设备中最为常见技术类型,数十亿计的产品都采用了来自 ARM、MIPS 的 IP core。IP core 被设计成可以和芯片中其他逻辑单元(例如视频编解码器、I/O 界面、内存界面)协同运作形成一枚可以支持特定应用的处理器。
IP core 分为两类:硬核(hard core......不要会错意了)和软核(soft core)。硬核是针对特定半导体厂商而优化的,对外人来说是一个提供了外部界面、不修改的“黑盒子”,获得授权的厂商通常只能对核外的逻辑参数进行修改,例如 L2 cache 大小,但是 IP core 本身不可修改。而软核的设计代码则是可以针对不同半导体厂商做编译和修改,当然这要求设计厂商具备强大的研发实力和经验,因为现在的 IP core 相当复杂。
简而言之而言,硬核的性能更高、占用管芯面积更小,而软核则可以让不同厂商作进一步的修改。




第2页:长话短说“微架构”——流水线
ISA 的“实现”需要借助各种微架构,现在的处理器微架构基本上涉及以下部分:
流水线化
多核、多线程
SIMD 向量
存储系统分层结构

流水线

早期一些采用非常简单的指令集(注意,我们说的不是 RISC)的电脑是采用单周期设计的,取指、解码、执行、写回都是放在同一个拍(周期)内顺序完成,此时的 CPI(每指令周期数)基本上是 1,但是这样设计的效率很低:当取指的时候,其余工位都只能瞎瞪眼等开饭,这样的设计也被称作非流水线化执行。
流水线示意图
上:非流水线化(顺序化)执行
下:流水线化执行
流水线化则是实现各个工位不间断执行各自的任务,例如同样的四工位设计,指令拾取无需等待下一工位完成就进行下一条指令的拾取,其余工位亦然。
世界上第一台采用流水线化指令执行的电脑为 1961 年的 IBM Stretch 或者说 IBM 7030,具备四级流水线工位,它同时也是 IBM 第一台晶体管化电脑。
这样原本四工位非流水线的一个周期是 800 个皮秒的话,在流水线设计的处理器上,虽然同样的指令完成时间依然是 800 皮秒,但是第二条指令则可能只需要在第一条指令完成时间加 200 皮秒即第 1000 皮秒就能完成,而非流水线设计则需要第 1600 皮秒才能完成。
流水线 pipelined
常见的五周期(FDEMW)流水线形式,对同步处理器来说 Latch 之间为一拍(周期)
对 Pentium 4 这类异步处理器来说,个别工位(simple ALU)频率为双倍即 1/2 拍
RISC 指令集具备指令编码格式统一、等长的特点,在流水线设计设计上有得天独厚的优势,这样可以使得流水线工位设计相对于指令编码格式不统一、非等长的 CISC(例如 x86 的指令长度为 1 个字节到 17 个字节不等)来说显得更容易。
x86 可能需要将一些工位拆开(这意味着流水线工位更多或者流水线长度更深),例如英特尔的第一款流水线化处理器——486 的指令解码就是拆成两个工位。
流水线设计可以让指令完成时间更短(理论上受限于流水线执行时间最长的工位),因此将一些工位再拆开的话,虽然依然是每个周期完成一条指令,但是“周期”更短意味着指令吞吐时间进一步缩短,每秒能跑出来的指令数更多,这就是超级流水线的初衷。
微架构
(Microarchitecture)
流水线工位数
(Pipeline stages)
Sony Cell PPU23
IBM PowerPC 717
IBM Xenon19
AMD Athlon10
AMD Athlon XP11
AMD Athlon6412
AMD Phenom12
AMD Opteron15
ARM7TDMI(-S)  3
ARM7EJ-S  5
ARM810  5
ARM9TDMI  5
ARM1020E  6
XScale PXA210/PXA250  7
ARM1136J(F)-S  8
ARM1156T2(F)-S  9
ARM Cortex-A5  8
ARM Cortex-A813
AVR32 AP7  7
AVR32 UC3  3
DLX  5
Intel P5 (Pentium)  5
Intel P6 (Pentium Pro) 14
Intel P6 (Pentium III) 10
Intel NetBurst (Willamette)20
Intel NetBurst (Northwood)20
Intel NetBurst (Prescott)31
Intel NetBurst (Cedar Mill)31
Intel Core14
Intel Atom16
LatticeMico32  6
R4000  8
StrongARM SA-110  5
SuperH SH2  5
SuperH SH2A  5
SuperH SH4  5
SuperH SH4A  7
UltraSPARC  9
UltraSPARC T1  6
UltraSPARC T2  8
WinChip  4
LC2200 32 bit  5
例如 Cortex-A15、Sandy Bridge 都分别具备 15 级、14 级流水线,而 Intel NetBurst(Pentium 4)、AMD Bulldozer 都是 20 级流水线,它们的工位数都远超出基本的四(或者五)工位流水线设计。更长的流水线虽然能提高频率,但是代价是耗电更高而且可能会有各种性能惩罚。




第3页:长话短说“微架构”——超标量
既然流水线设计可以实现不间断取指、解码、执行、写回,那为何不干脆同时做几条流水线一起取指、解码、执行、写回呢?这就引出了超标量设计。
超标量
上图就是一个三路超标量四工位流水线的指令/周期执行示意图,可以看到 CPI 从 1 变成 0.33,即每周期执行 3.33 条指令,这样的改进幅度是令人着迷的,因此在初期的时候超标量甚至被人们赞美为标量程序的向量式处理。
不过在现实中不可能都这样,因为现在的处理器执行不同指令时候的“执行”段工位并不完全一样,例如整数可能短一些,浮点或者向量和 Load/Store 指令需要长一些,加上一些别的因素,实际大部分程序的实际 CPI 都是 1.x 甚至更高啊。
例如:
a = b * c
d = a + 1
这里的第二条指令需要使用到第一条指令的计算结果,因此必须等待第一条指令完成后才能跑第二条指令,更重要的是,在不少处理器上乘法指令并非一个周期而是需要多个周期才能完成。在遇到这样的情况时,就不能实现多指令发射而且会出现流水线停顿。



第4页:长话短说“微架构”——分支(转移)预测
当然,还有更复杂的情况:
if (a > 5) 
    b = c; 
else
    b = d; 
将其按照汇编语言编写出来:
cmp a, 5    ; a > 5 ?
    ble L1
    mov c, b    ; b = c
    br L2
L1: mov d, b     ; b = d
L2: ...
这里的第二条指令是一个条件分支指令(ble 是小于或等于转移指令,ble L1 表示如果寄存器 a 小于等于 5 就转移到 L1 这行执行 mov d,b 这条指令)。
这条指令抵达“执行单元”的时候,位于流水线前段的取指单元和解码单元肯定已经拾取和解码了若干条指令,但是哪一条指令才应该接下来被执行呢?应该是第三、四条还是第五条呢?
在第二行的条件分支指令完成之前,处理器只能等待。处理器平均六条指令就会遇到一条分支指令,因此流水线设计带来的大部分性能提升优势此时会被丧失掉。
为此处理器必须进行“猜测”,按照猜测结果进行取指并推测哪些指令能开始执行,不过这些指令的执行结果并不会被递交(写回)直到分支指令的执行结果完成。
如果猜错的话,这部分指令的结果就会被扔掉,这也意味着这些指令对应的时间或者周期数会被浪费掉。当然如果猜中的话,处理器就能全速运行了。
那么如何去做“猜测”呢?
一个办法是所谓的静态分支预测,例如在指令编码格式里留出一个位元作为预测信息,编译器编译的时候,对这个位元进行标记,告诉处理器该跑那条分支,不过这对于已经采用了不具备这类条件执行指令的旧式 ISA 二进制程序来说这样显然是不可能的。
另一个办法就是“运行过程中”进行猜测即动态分支预测,通常是采用类似被称作“片上分支预测表”的单元来记录最近分支的地址以及用一个位元指示出哪一条分支是最近是否被采用的。
不过现在大多数处理器实际上是用两个位元来作标记的,因此单次的分支“不跳转”并不会马上导致一般的“跳转”预测出现反转(这对于循环边界来说是很重要的)。不过两位元分支预测并有考虑到分支相关性,所以人们后来有采用两级分支预测来解决这个问题,使得预测精度大大提高。
动态分支表需要占用相当可观的芯片面积,但是另一方面来说分支预测对流水线化处理器是相当重要的,所以是物有所值的。
不过就算是最好的分支预测技术也可能会猜错,对于超级流水线或者说深流水线来说就会有很多指令的结果会被扔掉,这样的情况被称作 mispredict penalty(误预测性能惩罚)。
像 Pentium III 这类具备非常先进分支预测技术的处理器,在遇到分支预测失败的时候,也会出现 10~15 个周期的性能损失,因此即使正确命中了 90% 的分支,也会因为分支误预测导致 30% 的性能损失,所以 Pentium III 其实很多时候会出现 30% 的时间在走冤枉路。
人们在 ISA 中引入条件执行指令(predicated instruction),希望籍此尽量减少分支,例如上面的例子,引入名为 cmovle 的判定指令后,可以写成这样:
cmp a, 5       ; a > 5 ?
mov c, b       ; b = c
cmovle d, b    ; if le, then b = d
cmovle 的作用是“当小于或者等于的时候就进行赋值”,只有在条件为“真”的时候才会递交执行,因此被称作条件执行指令。
采用了判定指令后,原来的 5 条指令变成 3 条,避免了两条分支指令,cmp 和 mov 可以并行执行实现 50% 的性能提升,消除了分支预测错误导致的大量误预测惩罚。
ARM 从一开始具备完整的判定指令集,而 MIPS 和 x86 后了也都添加了条件赋值指令,IA64(EPIC)中几乎每条指令都具备条件执行功能。




第5页:长话短说“微架构”——动态调度
为了充分利用由于分支以及长时延指令导致的流水线“气泡(停摆)”而浪费的资源,人们引入了乱序执行(OoOE)技术。当出现需要等待某条指令的时候,程序中的指令会被“重排序(Re-Ordered)”,使得其他指令可以被执行。
对于像 x86 这样的 ISA 来说,32 位模式下的寄存器只有 8 个(ARMv7 是 16 个),如果程序里的变量较多,就会导致多个变量使用同一个寄存器的情况发生,这里有可能出现先读后写的伪相关现象。
微架构里解决寄存器先读后写(WAR)伪相关的办法就是寄存器重命名。在微架构的寄存器堆里塞进比 ISA 寄存器更多的物理寄存器,透过索引式寄存器堆或者保留站方式,将 ISA 寄存器映射到物理寄存器,从而实现乱序执行。
ARM Cortex-A8、Intel Pentium、Intel Atom(Bonnell 内核)、IBM Cell PPU 都属于顺序执行,它们选择顺序执行的原因主要是为了省电,因为 OoOE 需要大量的晶体管来实现。随着制程的改进,OoOE 的开销会逐渐淡化变得在某些场合里可行,因此像 ARM 从 Cortex-A9、Intel 从 Pentium Pro/Atom(Silvermont 内核)都开始采用 OoOE。



第6页:长话短说“微架构”——线程级并行化
假设我们有这样的一段 C 代码:
int x,y ;
int z ;
x = 100 ;
y = x + 1 ;
z = 5 ;
由于 z 的初始化和赋值都是相对对立的,这里也许可以拆成两条 thread(线程):
thread #1:
int x,y ;
x = 100 ;
y = x + 1 ;
和 thread #2:
int z ;
z = 5 ;
如果处理器的微架构具备两种架构状态让操作系统认为有两个处理器的话,上面的两条 thread 就能同时执行了,这就是多线程。
多线程有三种类型,即 SMT、FGMT 和 CGMT,其中最早实现 SMT 的处理器是 Intel 的 Pentium 4,而 FGMT 大都在 in-order(相对于 OoOE)处理器上采用例如 Cell PPU 和所有的 GPU 上。
随着半导体工艺提升以及功率墙壁垒横亘在前面导致超级流水线提升频率和各种指令并行度措施不再灵光后(这些限制其实在 20 多年前就被处理器厂商和科研界预见到,例如 1993 年 DEC 西部研究院 David W.Wall)的论文《LIMITS OF INSTRUCTION-LEVEL PARALLELISM》,1993 年英特尔在路线图中明确提出在 P8(当时还是 P5 或者说 Pentium)时代引入多核处理器)厂商开始在片上实现多个内核,这也就出现了多核处理器。
多核处理器能让支持多线程的程序、操作系统跑得更快,但是目前大部分的应用通常更偏好于单线程性能出色的处理器,因此你会看到单线程性能较强的双核处理器比单线程性能较弱的多核处理器更快的情况发生。
到目前为止我们介绍了指令并行、线程并行的微架构实现,不过除了这两种并行技术外,还有另一种非常常见的并行技术:数据级并行化,通常以 SIMD 向量方式实现。



第7页:长话短说“微架构”——数据级并行(SIMD)
SIMD 就是单指令多数据的缩写,理解起来并不困难,例如执行一条 SIMD 加法指令就能在一个周期里完成 64 条数据流发来的 64 个数字的加法运算。
SIMD 的初衷是为了摊薄大量执行单元上的控制单元成本,顺带减少程序的尺寸,因为SIMD 只需要复制一份代码就能开跑,而多核处理器(或者说 MIMD)需要每个内核都复制一份代码和在 cache 上共享多个程序拷贝。
SIMD 最好是用来跑结构相同的一堆数据,因此它是数据级并行的重要实现方式之一,而这类应用主要是多媒体为主,所以很多 ISA 都提供了专门的 SIMD 扩展来执行多媒体应用,ARM 有 NEON、Intel 有 MMX/SSE/AVX 等。




第8页:长话短说“微架构”——存储系统分层结构
无论是冯·诺依曼还是哈佛结构的处理器,最理想的情况下当然是有无限大的存储空间和 0 时延的存储系统了,不过这显然是无法做到的,因此人们就提出了分层式的存储系统结构,从寄存器开始每往下一层容量就更大,但是速度也更慢:
Memory Hierarchy
例如对于 ARM Cortex-A9(四核 Tegra 3 的批发报价一般为 15~21 美元)来说:
物理寄存器堆大小是 56*32-bit = 224 字节
L1 cache 是 32-KiB(时延 4 周期)
L2 Cache 是 1-MiB,不同大小区段的时延是:
  • 64 KiB - 128KiB = L1C + L2C = 4 + 19 = 23 周期
  • 256 KiB - 512 KiB = L1_C + L2_C + TLB_L1 = 4 + 19 + 7 = 30 周期
  • 1 MiB = L1_C + L2_C + TLB_L1 + TLB_L2 = 4 + 19 + 7 +7 = 37 周期
不同型号的产品,搭配的内存容量不尽相同,以 华为 Ascend P1 XL 为例,搭配的内存大小为 1GiB,时延大概是 L2 + 110ns,带宽一般都有 1000MiB/s 以上。
基本上所有的手机都是采用 NAND 型闪存或者闪存卡作为 DASD(直接存取存储设备)来存放程序和数据,大小一般在 4 GiB 以上,如果搭配 Class 4 的 8 GiB microSD 卡的话读写带宽一般只有 1.x MiB/ss~3.x MiB/s(传输数据块大小为 4KiB 时)和 0.005 MiB/s~1.x MiB/s,价格一般为 20 元人民币左右 。
这里说的时延是从数据载入指令发出到数据抵达处理单元所需的时间,这通常并不难理解。
那么这里的 TLB 时延(TLB_L1/TLB_L2)又是怎么回事呢?这是因为虚拟内存的存在。
虚拟内存(virtual memory)的作用一般有两个:确保多个程序之间可以有效、安全地实现内存共享;让程序以为有大一块连续的内存空间(例如虚拟内存空间地址有 64-bit,但是我们的物理内存实际上只有 16GiB 或者说系统中的物理地址空间只有 34-bit,又或者是虚拟内存空间是 32-bit,而物理定址空间是 40-bit)。
对于用户程序在虚拟内存空间里操作的处理器,是需要把虚拟内存空间地址转换为物理内存空间地址,这就需要进行地址转换了。负责这个功能的单元一般被称作内存管理单元(MMU),有时候它又被称作分页内存管理单元,当然 MMU 的功能不仅仅是地址转换(否则就不会被盖这么大的名头了)。
内存的基本管理单位被称作 page(页面,或者说页块),不同处理器支持的页面大小不一样,一般都是 4KiB(在 ARMv7a 里还有 64 KiB、1MiB、16 MiB 等),性能导向型的处理器页面正变得越来越大,而嵌入式处理器似乎有 1KiB 大小的。
记录物理内存和虚拟内存关系里的数据列表被称作分页表,这些分页表也都是放在主内存(物理内存)中的,但是如果每次读写内存都要访问两次主内存的话效率太低了,所以人们引入了名为 TLB(Translate Look-aside Buffer,转换后缓存)的 cache 来改善这个问题。
不同的处理器 TLB 大小都不一样,以我们这里举例的 Cortex-A9 为例,本身就存在多种 TLB 配置形式,它的 L1 D-TLB 是 32 个条目(或者说分页地址映射),而 L1 I-TLB 可以配置为 32 或者 64 条目。
总之,早期的单周期式架构效率很差,因此人们引入了流水线设计,可以充分使用各级工位,各工位执行时间越短自然 CPU 的频率可以更快;然后人们又引入了超标量设计,让 CPU 上可以同时跑几条指令,随之而来的相依性等问题让架构师们想出了分支预测、乱序执行、寄存器重命名等等技术来保证处理器的指令执行效率。
除了提高指令并行度来改善处理器性能外,还有数据并行、线程化并行等方法,但是后两者都需要程序员和编译器协助,并非免费。
影响处理器性能还有内存的带宽和时延问题,因为取指和数据读写都必须透过内存访问来完成,层阶式设计是目前成本最为合理的方式。

没有评论:

发表评论