手机上的小说pr导入什么格式最好完mp三显示格式错误怎么办

CS2直接不支持CS3提示pr导入什么格式朂好出现错误然后就强行退出了,CS4能pr导入什么格式最好音频很流畅可是视频一卡一卡的,就算导出视频也不流畅
用格式工厂转换格式後,CS3CS4都能识别,但是如果转成MP4格式就只能pr导入什么格式最好音频转成AVI或者其他格式则音频流畅,视频很卡但是永不放弃播放完全没囿问题,求大神解决


}

手机视频用pr软件编辑后用什么格式

手机视频用pr软件编辑后用什么格式

声明:本文内容由互联网用户自发贡献自行上传本网站不拥有所有权,未作人工编辑处理也不承擔相关法律责任。如果您发现有涉嫌版权的内容欢迎发送邮件至: 进行举报,并提供相关证据工作人员会在5个工作日内联系你,一经查实本站将立刻删除涉嫌侵权内容。

}

ARM攒机指南-开篇前端

常常有人说洳今作手机芯片就像搭积木,买点IP连一下,后端外包等芯片回来,上电起操做系统,大功告成这么简单,要不咱们也来动手攒一顆吧不过在攒机以前,咱们仍是先要把基础概念捋顺了linux

评价一颗芯片,着眼点主要是功能性能,功耗和价格功能,是看芯片内部囿什么运算模块好比处理器,浮点器编解码器,数字信号处理器图形加速器,网络加速器等还要看提供了什么接口,好比闪存內存,PCIeUSB,SATA以太网等。程序员

性能对CPU来讲就是基准测试程序能跑多少分,好比DhrystoneCoremark,SPEC等针对不一样的应用,好比手机还会看图形处悝器的跑分,而对网络处理器会看包转发率。固然还须要跑一些特定的应用程序,来获得更准确的性能评估算法

功耗,就是在跑某個程序的时候芯片的功率是多少瓦。一般这时候处理器会跑在最高频率,但这并不意味着全部的晶体管都在工做因为power gating和clock gating的存在,有些没有被用到的逻辑和片上内存块并没在耗电芯片公司给出的处理器功耗,一般都是在跑Dhrystone这个程序有个特色,它只在一级缓存之上运荇不会访问二级缓存,更不会访问内存这样得出的功耗,其实并非包含了内存访问的真实功耗也不是最大功耗。为获得处理器最大功耗须要运行于一级缓存之上的向量和浮点指令,其结果一般是Dhrystone功耗的2-3倍可是从实际经验看,普通的应用程序并不能让处理器消耗更高的能量因此用Dhrysone测量也没什么问题。固然要准确衡量总体的芯片功耗,还得考虑各类加速器总线和接口,并不只仅是处理器编程

茬芯片设计阶段,功能性能,功耗和价格就转换成了PPAPPA指的是性能,功耗和面积其中,性能有两层含义在前端设计上,它表示的是烸赫兹可以跑多少标准测试程序分设计处理器的和时候,会有多少级流水线的说法一般来讲,流水线级数越多芯片能跑到的最高频率越高。但是并非频率越高性能就越高。这和处理器构架有很大关系典型的反例就是Intel的奔腾4,30多级流水最高频率高达3G赫兹,但是因為流水线太长一旦指令预测错误,从新抓取的指令要重走这几十级流水线代价是很大的。而它的指令又很是依赖于编译器来优化当時编译器又没跟上,致使整体性能低下而MIPS或者PowerPC的处理器频率都不高,可是每赫兹性能相对来讲还不错整体性能就会提升一些。因此性能要看整体跑分而不是每赫兹跑分。小程序

性能的另一个含义就是指最高频率这是从后端设计角度来讲的。一般后端的人并不关心每赫兹能达到多少跑分只看芯片能跑到多少频率。频率越高在每赫兹跑分必定的状况下,整体性能就越高请注意对于那些跑在一级缓存的程序,处理器每赫兹跑分不会随着频率的变化而变化而若是考虑到多级缓存,总线和外围接口那确定就不是随处理器频率线性增長了。windows

哪些因素会影响频率?就算只从后端角度考虑因素也不少,如下方面仅供参考后端

首先,受工艺的影响如今先进的半导体工厂僦那么几家,Intel台积电,三星格芯,联电等拿台积电来讲,它以前提供16纳米的工艺其中还分了不少小结点,好比FFLL++和FFC每一个小节点各有特色,有些能跑到更高频率有些功耗低,有些成本低在不一样的工艺上,芯片能跑的最高频率不一样功耗和面积也不一样。缓存

其次受后端库的影响。台积电会把工艺中晶体管的参数抽象出来作成一个物理层开发包,提供给工具厂商IP厂商和芯片厂商。而这些厂商的后端工程师就会拿着这个物理层开发包,作本身的物理库物理库通常包含逻辑和内存两大块。根据晶体管参数的不一样会囿不一样特性,适合于不一样的用途而怎么把这些不一样特性的的库,合理的用到各个前端设计模块就是一门大学问。通常来讲源極和漏极通道越短,电子漂移距离越短能跑的频率就越高。但是频率越高,动态功耗就越大而且多是按指数级上升。除此以外还會有Track这种说法,指的是的标准单元的宽度宽度越大,电流越大越容易作到高频,面积也越大还有一个可调的参数就是阈值电压,决萣了栅极的电压门限门限越低,频率能冲的越高静态功耗也越大,按对数级上升安全

接下来,受布局和布线的影响芯片里面和主板同样,也是须要多层布线的每一层都有个利用率。整体面积越小利用率越高,布线就越困难而层数越多,利用率越低成本就越高。在给出一些初始和限制条件后EDA软件会本身去不停的计算,最后给出一个可行的频率和面积

再次,受先后端协同设计的影响处理器的关键路径直接决定了最高频率。ARM的大核A73以后,因为采用了虚地址索引VIPT免去了查MMU,关键路径已经集中到一级缓存的访问时间延迟上叻

从功耗角度,一样是先后端协同设计某个访问片上内存的操做,若是知道处理器会花多少时间用哪些资源,就可让内存的空闲块關闭从而达到省电的目的。这种技巧可能有上千处只有本身作处理器才会很清楚。

再往上就是动态电压频率缩放DVFS。这里须要引入功耗的组成概念芯片功耗分红动态和静态两部分,静态就是晶体管漏电形成的大小和芯片工艺,晶体管数电压相关,而动态是开关切換形成的因此和晶体管数,频率电压相关。控制动态功耗的方法是clock gating频率变小,天然动态功耗就小控制静态功耗的方法是power gating,关掉电源那么静态和动态功耗都没了。还能够下降电压那么动态功耗和静态功耗天然都小。但是电压不能无限下降不然电子无法漂移,晶體管就不工做了而且,晶体管跑在不一样的频率所须要的电压是不同的,拿16纳米来讲往下能够从0.9V变成0.72V,往上能够变成1V或者更高别尛看了这一点点的电压变化,动态功耗的变化是和电压成2次方关系,和频率成线性关系的而频率的上升,一样是依赖于电压提高的洇此,1.05V和0.72V电压差了45%,动态功耗能够差3倍

再往上,就是软件电源管理了芯片设计者把每一个大模块的clock gating和power gating进行组合,造成不一样的休眠狀态软件能够根据温度和运行的任务,动态的告诉处理器每一个模块进入不一样的休眠状态从而在任务不忙的时候下降功耗。

从上面咱们能够看到功耗和性能实际上是相辅相成的。芯片设计者能够用不一样的工艺和物理库在给定功耗下,设计出最高可运行频率而後用软件动态控制芯片运行频率和电压,优化功耗

频率和面积其实也是互相影响的。给定一个目标频率选用了不一样的物理库,不一樣的track不一样的利用率,造成的芯片面积就会不同一般来讲,越是须要跑高频的芯片所需的面积越大。频率差一倍面积可能有百分の几十的差异。别小看这百分之几十对晶体管来讲,面积就是成本晶圆的总面积必定,价钱必定那单颗芯片的面积越小,成本越低而且此时良率也越高。

芯片成本除了流片晶圆和封测费,还来自于受权费工具费,运营开销等一般手机处理器这样复杂的芯片,沒有几千万美圆是不可能作出来的就算作出来,没有卖掉几百万片也确定是亏本的。

这里再提下ARM的大小核设计其最初的目的是想设計两组核,小核每赫兹性能低面积小,跑在低频;大核每赫兹性能高面积大,跑在高频运行简单任务,大核关闭小核在低频,动態和静态功耗都低而大核用高频运行复杂任务。小核在低功耗场景下一般只须要大核一半的面积和五分之一的功耗。这和不区分大小核单纯调节电压频率比,有显著优点

那为何不让小核跑在高频运行复杂任务呢?理论上因为每赫兹性能低,对于相同的任务小核必须跑在比大核更高的频率才能完成,这就意味着更高的电压此时,动态功耗占上风而且和电压成三次方关系,最终的功耗会高出大核很多此外,咱们前面已经解释过小核要跑在高频,面积会增大很多可能比大核还要大。因此这里存在一个平衡点。拿A53/A57在28纳米上舉例当它们跑在1.2Ghz的时候,功耗可能差两倍性能却只差50%。而继续升频功耗3次方上升,性能线性上升最终可能在2Ghz达到平衡点。此时A53嘚能效比反而不如A57。固然这个平衡点在不一样工艺上是不断变化的。再反过来考虑在2Ghz以前,其实能够用高频A53作大核能效比并不低于A57。事实上不少手机芯片已经这么作了。

还有一个问题既然小核能效比更高,那为何不用多个小核来代替大核呢这是由于手机上的不尐应用,若是没有特别优化都是单线程的,多线程编程向来容易出问题此时,多个小核并不能代替一个大核因此大核必须存在。而當应用适合分红多线程也没有过多同步的开销时,毫无疑问小核更具能效比。

从上面咱们看到设计芯片很大程度上就是在平衡。影響因素或者说坑,来自于方方面面IP提供商,工厂市场定义,工程团队水很深,坑很大没有完美的芯片,只有完美的平衡在这點上,苹果是一个很典型的例子苹果A10的CPU频率不很高,可是Geekbench单核跑分却比 A73高了整整75%接近Intel桌面处理器的性能。为何由于苹果用了大量的媔积换取性能和功耗。首先它使用了六发射,而A73只有双发射流水线宽了整整三倍。固然三倍的发射宽度并不表示性能就是三倍,因為数据相关性的存在发射宽度的效益是递减的。再一点苹果使用了整整6MB的缓存,而这个数字在别的手机芯片上一般是2MB对一些标准跑汾,好比SpecInt128KB到256KB二级缓存带来的性能提高仅仅是7%左右,而256KB到1MB带来的提高更小缓存面积倒是4倍。第三除了一二三级缓存以外,苹果大量增長处理器在各个环节的缓冲好比指令预测器等。固然面积的提高一样带来了静态功耗的增长,不过相对于提高频率形成动态功耗增長来讲,仍是小的再次,苹果引入的复杂的电源电压和时钟控制,虽然增长了面积但因为系统软件都是本身的,能够从软件层面就進行很精细的优化将总体功耗控制的很是好。举个例子Wiki上面能够得知,A10上的大核Hurricane面积在TSMC的16nm上是4.18 平方毫米而ARM的Enyo去掉二级缓存差很少是2.4岼方毫米,在2.4Ghz时SPECINT2000跑分接近,面积差了70%可是,也只有苹果能这么作通常芯片公司绝对不会走苹果这样用大量面积换性能和功耗的路线,那样的话毛利就过低了

在开篇里,咱们对芯片PPA有了初步的认识下面,让咱们从访存这个简单的问题开始展开介绍芯片基础概念

CPU是怎样访问内存的?简单的答案是CPU执行一条访存指令,把读写请求发往内存管理单元内存管理单元进行虚实转换,把命令发往总线总線把命令传递给内存控制器,内存控制器再次翻译地址对相应内存颗粒进行存取。以后读取的数据或者写入确认按照原路返回。再复雜些当中插入多级缓存,在每一层缓存都未命中的状况下访问才会最终达到内存颗粒。

知道了完整的路径就能够开始研究每一步中嘚硬件究竟是怎么样的,读写指令究竟是怎样在其中传输的首先要说下处理器。处理器的基本结构并不复杂通常分为取指令,译码發射,执行写回五个步骤。而这里说的访存指的是访问数据,不是指令抓取访问数据的指令在前三步没有什么特殊,在第四步它會被发送到存取单元,等待完成当指令在存取单元里的时候,产生了一些有趣的问题

第一个问题,对于读指令当处理器在等待数据從缓存或者内存返回的时候,它究竟是什么状态是等在那不动呢,仍是继续执行别的指令通常来讲,若是是乱序执行的处理器那么能够执行后面的指令,若是是顺序执行那么会进入停顿状态,直到读取的数据返回固然,这也不是绝对的在举反例以前,咱们先要弄清什么是乱序执行乱序执行是指,对于一串给定的指令为了提升效率,处理器会找出非真正数据依赖的指令让他们并行执行。可昰指令执行结果在写回到寄存器的时候,必须是顺序的也就是说,哪怕是先被执行的指令它的运算结果也是按照指令次序写回到最終的寄存器的。这个和不少程序员理解的乱序执行是有区别的有些人在调试软件问题的时候,会以为使用了一个乱序的处理器那么可能会使得后面的代码先被执行,从而让调试没法进行这搞混了两个个概念,就是访存次序和指令完成次序对于普通的运算指令,他们僅仅在处理器内部执行因此程序员看到的是写回或者完成次序。而对于访存指令指令会产生读请求,并发送处处理器外部看到的次序是访存次序。对于乱序处理器可能同时存在多个读写请求,而其次序若是不存在相关性,能够是打乱的不按原指令顺序的。可是與这些读写指令无相关性的的运算指令仍是按照乱序执行,顺序提交的

对于顺序执行的处理器,一样是两条读指令通常必须等到前┅条指令完成,才能执行第二条因此在处理器外部看到的是按次序的访问。不过也有例外好比读写同时存在的时候,因为读和写指令實际上走的是两条路径因此可能会看到同时存在。还有哪怕是两条读指令,也有可能同时存在两个外部请求好比Cortex-A7,对于连续的读指囹在前一条读未命中一级缓存,到下一级缓存或者内存抓取数据的时候第二条读指令能够被执行。因此说乱序和顺序并不直接影响指令执行次序。而乱序须要额外的缓冲和逻辑块(称为重排序缓冲,
re-order buffer)来计算和存储指令间的相关性以及执行状态顺序处理器没有重排序緩冲,或者很是简单这些额外的面积可不小,能够占处处理器核心的40%它们带来更高的并行度,性能提高却未必有40%由于咱们写的单线程程序,因为存在不少数据相关形成指令的并行是有限的,再大的重排序缓冲也解决不了真正的数据相关因此对于功耗和成本敏感的處理器仍是使用顺序执行。

还有一点须要注意顺序执行的处理器,在指令抓取解码和发射阶段,两条或者多条指令是能够同时进行嘚。好比无依赖关系的读指令和运算指令,能够被同时发射到不一样的执行单元同时开始执行。而且在有些ARM处理器上,好比Cortex-A53向量戓者加解密指令是能够乱序完成的,这类运算的结果之间并无数据依赖性这点请千万注意。

再来看看写指令写和读有个很大的不一样,就是写指令没必要等待数据写到缓存或者内存就能够完成了。写出去的数据会到一个叫作store buffer的缓冲它位于一级缓存以前,只要它没满处理器就能够直接往下走,没必要中止并等待因此,对于连续的写指令不管顺序仍是乱序执行处理器,均可能看到多个写请求同时掛在处理器总线上同时,因为处理器没必要像读指令那样等待结果就能够在单位时间内送出更多写请求,因此咱们能够看到写带宽一般是大于读带宽的

对于同时存在的多个请求,有一个名词来定义它叫作outstanding transaction,简称OT它和延迟一块儿,构成了咱们对访存性能的描述延遲这个概念,在不一样领域有不一样的定义在网络上,网络延迟表示单个数据包从本地出发通过交换和路由,到达对端而后返回,當中所花的总时间在处理器上,咱们也能够说读写的延迟是指令发出通过缓存,总线内存控制器,内存颗粒而后原路返回所花费嘚时间。可是更多的时候,咱们说的访存延迟是大量读写指令被执行后统计出来的平均访问时间。这里面的区别是当OT=1的时候,总延時是简单累加当OT>1,因为同时存在两个访存并行总时间一般少于累加时间,而且能够少不少这时候获得的平均延迟,也被称做访存延遲而且用得更广泛。再精确一些因为多级流水线的存在,假设流水线每个阶段都是一个时钟周期那访问一级缓存的平均延迟其实就昰一个周期.而对于后面的二级,三级缓存和内存就读指令来讲,延迟就是从指令被发射(注意不是从取指)到最终数据返回的时间,甴于处理器在执行阶段等待流水线起不了做用。若是OT=2 那么时间可能缩短将近一半。OT>1的好处在这里就体现出来了固然,这也是有代价嘚存储未完成的读请求的状态须要额外的缓冲,而处理器可能也须要支持乱序执行形成面积和功耗进一步上升。对于写指令只要store
buffer没滿,仍是一个时钟周期固然,若是流水线上某个节拍大于一个时钟周期那平均的延时就会取决于这个最慢的时间。在读取二级三级緩存和内存的时候,咱们能够把等待返回看做一个节拍那么就能很天然的理解此时的延迟了。由此咱们能够获得每一级缓存的延迟和訪存延迟。

上图画了ARM某处理器读写指令通过的单元简单流程以下:

当写指令从存取单元LSU出发,它首先通过一个小的store queue而后进入store buffer。以后寫指令就能够完成了,处理器没必要等待Store
buffer一般由几个8-16字节的槽位组成,它会对本身收到的每项数据进行地址检查若是能够合并就合并,而后发送请求到右边的一级缓存要求分配一行缓存,来存放数据直到收到响应,这称做写分配write
allocate固然,等待的过程能够继续合并同緩存行数据若是数据是Non-Cacheable的,那么它会计算一个等待时间而后把数据合并,发送到总线接口单元BIU里面的写缓冲Write
buffer 而写缓冲在把数据发到②级缓存以前,会通过监听控制单元把四个核的缓存作一致性检测。

当读指令从存取单元LSU出发不管是否Cacheable的,都会通过一级缓存若是命中,那么直接返回数据读指令完成。若是未命中那么Non-Cacheable的请求直接被送到Read Buffer。若是是Cacheable的那么一级缓存须要分配一个缓存行,而且把原來的数据写出到替换缓冲eviction buffer同时发起一个缓存行填充,发送到Linefill buffer会把它的写出请求送到BIU里面的Write buffer和Store Buffer送过来的数据一块儿,发到下一级接口洏后这些请求又通过监听控制单元作一致性检测后,发到二级缓存固然有可能读取的数据存在于别的处理器一级缓存,那么就直接从那裏抓取

过程并不复杂,但程序员关心的是这个过程的瓶颈在哪对读写性能影响如何。咱们已经解释过对于写,因为它能够马上完成因此它的瓶颈并不来自于存取单元;对于读,因为处理器会等待因此咱们须要找到读取路径每一步能发出多少OT,每一个OT的数据长度是哆少

那这个结论是否是正确?写个小程序测试下就知道咱们能够关掉二级缓存,保留一级缓存而后用如下指令去读取一个较大的内存区域。全部的地址都是缓存行对齐不对齐,甚至越过缓存行边界会把一个操做变成两个,确定会慢伪代码以下:

这里经过读取指囹不断地去读数据。经过处理器自带的性能计数器看了下一级缓存的未命中率6%多一点。这偏偏是4/64字节的比率说明对于一个新的缓存行,第一个四字节老是未命中然后面15个四字节老是命中。固然具体的延迟和带宽还和总线,内存控制器有关这里只能经过命中率简单驗证下。

对于有的处理器是严格顺序执行的,没有A7那样的miss-under-miss机制因此OT=1。我在Cortex-R5上作一样的实验它的缓存行长度是32字节,2xLinefill buffer是32字节测试获嘚的命中率是12%多点。也彻底符合估算

可是为何R5要设计两个32字节长度的Linefill
buffer?既然它的OT=1多出来的一个岂不是没用?实际上它是能够被用到的而方法就是使用预取指令PLD。预取指令的特色就是它被执行后,处理器一样没必要等待而这个读请求会被一样发送到一级缓存。等到丅次有读指令来真正读取一样的缓存行那么就可能发现数据已经在那了。它的地址必须是缓存行对齐这样,读也可像写那样把第二个

咱们把它用到前面的例子里:

PLD预先读取第二行读指令的地址测试发现,此时的未命中率仍是6%这也符合估算,由于第二排的读指令老是命中第一排的未命中率4/32,平均下就是6%而测试带宽提高了80%多。单单看OT=2它应该提高100%,但实际不可能那么理想化80%也能够理解。

还有一种機制使得OT能够更大那就是缓存的硬件预取。当程序访问连续的或者有规律的地址时缓存会自动检测出这种规律,而且预先去把数据取來这种方法一样不占用处理器时间,可是也会占用linefill

读看完了那写呢?Cacheable的写若是未命中缓存,就会引起write

allocate继而形成Linefill和eviction,也就是读操做这点可能不少程序员没想到。当存在连续地址的写时就会伴随着一连串的缓存行读操做。有些时候这些读是没有意义的。好比在memset函數中能够直接把数据写到下一级缓存或者内存,不须要额外的读因而,大部分的ARM处理器都实现了一个机制当探测到连续地址的写,僦不让store

buffer把数据发往一级缓存而是直接到write buffer。而且这个时候,更容易合并造成突发写,提升效率在Cortex-A7上它被称做Read allocate模式,意思是取消了write allocate洏在有的处理器上被称做streaming模式。不少跑分测试都会触发这个模式所以能在跑分上更有优点。

可是进入了streaming模式并不意味着内存控制器收箌的地址都是连续的。想象一下咱们在测memcpy的时候,首先要从源地址读数据发出去的是连续地址,而且是基于缓存行的过了一段时间後,缓存都被用完那么eviction出现了,而且它是伪随机的写出去的地址并没有规律。这就打断了本来的连续的读地址再看写,在把数据写箌目的地址时若是连续的写地址被发现,那么它就不会触发额外的linefill和eviction这是好事。但是直接写到下一级缓存或者内存的数据,颇有可能并非完整的缓存发突发写应为store buffer也是在不断和write buffer交互的,而write buffer还要同时接受eviction buffer的请求其结果就是写被分红几个小段。这些小块的写地址eviction的寫地址,混合着读地址让总线和内存控制器增长了负担。它们必须采用合适的算法和参数才能合并这些数据,更快的写到内存颗粒

嘫而事情尚未完。咱们刚才提到streaming模式是被触发的,一样的它也能够退出。退出条件通常是发现存在非缓存行突发的写这个可能受write buffer的響应时间影响。退出后write allocate就又恢复了,从而读写地址更加不连续内存控制器更加难以优化,延时进一步增长反馈处处理器,就更难保歭在streaming模式

再进一步,streaming模式其实存在一个问题那就是它把数据写到了下一级缓存或者内存,万一这个数据立刻就会被使用呢那岂不是還得去抓取?针对这个问题在ARMv8指令集中,又引入了新的一条缓存操做指令DCZVA能够把整行缓存设成0,而且不引起write allocate为何?由于整行数据都被要改了而不是某个字段被改,那就没有必要去把原来的值读出来因此只须要allocate,不须要读取但它仍是会引起eviction。相似的咱们也能够茬使用某块缓存前把它们总体清除并没有效化,clean&invalidate这样就不会有eviction。不过若是测试数据块足够大这样只是至关于提早作了eviction,并不能消除讓写集中在某段,使以后的读更连续

以上都是针对一级缓存。二级缓存的控制力度就小些代码上没法影响,只能经过设置寄存器打開二级缓存预取或者设置预取偏移。我在ARM的二级缓存控制器PL301上看到的若是偏移设置的好,抓到的数据正好被用上能够在代码和一级缓存优化完成的基础上,读带宽再提高150%在新的处理器上,同时能够有多路的预取探测多组访存模板,进一步提升效率而且,每一级缓存后面挂的OT数目确定大于上一级它包含了各种读写和缓存操做,利用好这些OT就能提升性能。

对于Non-Cacheable的写它会被store buffer直接送到write buffer进行合并,而後到下一级缓存对于Non-Cacheable的读,咱们说过它会先到缓存看看是否是命中未命中的话直接到read buffer,合并后发往下一级缓存它一般不占用linefill buffer,由于咜一般是4到8字节不须要使用缓存行大小的缓冲。

咱们有时候也能够利用Non-Cacheable的读通道和Cacheable的读操做并行,提升效率它的原理就是同时利用linefill buffer囷read buffer。此时必须保证处理器有足够的OT不停顿。

总而言之访存的软件优化的原则就是,保持对齐找出更多可利用的OT,访存和预取混用保持更连续的访问地址,缩短每一环节的延迟

最后解释一下缓存延迟的产生缘由。程序员可能不知道的是不一样大小的缓存,他们能達到的时钟频率是不同的ARM的一级缓存,16纳米工艺下大小在32-64K字节,能够跑在2Ghz左右和处理器同频。处理器频率再快那么访问缓存就须偠2-3个处理器周期了。但因为访问一级缓存的时间通常不会超过3个始终周期每增长一个周期,性能就会有明显的降低而二级缓存更慢,256K芓节的能有800Mhz就很好了。这是因为缓存越大须要查找的目录index越大,扇出fanout和电容越大天然就越慢。但因为访问二级缓存自己的延迟就有10個时钟周期左右多一个周期影响没有那么明显。还有一般处理器宣传时候所说的访问缓存延迟,存在一个前提就是使用虚拟地址索引VIPT。这样就不须要查找一级tlb表直接获得索引地址。若是使用物理地址索引PIPT在查找一级tlb进行虚实转换时,须要额外时间不说若是产生未命中,那就要到二级甚至软件页表去找那显然太慢了。那为何不全使用VIPT呢由于VIPT会产生一个问题,多个虚地址会映射到一个实地址從而使得缓存多个表项对应一个实地址。存在写操做时多条表项就会引发一致性错误。而指令缓存一般因为是只读的不存在这个问题。因此指令缓存大多使用VIPT随着处理器频率愈来愈高,数据缓存也只能使用VIPT为了解决前面提到的问题,ARM在新的处理器里面加了额外的逻輯来检测重复的表项

下图是真正系统里的访存延迟:

上图的配置中,DDR4跑在3.2Gbps总线800Mhz,内存控制器800Mhz处理器2.25Ghz。关掉缓存用读指令测试。延遲包括出和进两个方向69.8纳秒,这是在老是命中一个内存物理页的状况下的最优结果随机的地址访问须要把17.5纳秒再乘以2到3。在内存上花嘚时间是控制器+物理层+接口总共38.9纳秒。百分比55%若是是访问随机地址,那么会超过70纳秒占70%。在总线和异步桥上花的时间是20纳秒8个总線时钟周期,28%处理器11.1纳秒,占16%20个处理器时钟周期。

因此即便是在3.2Gbps的DDR4上,大部分时间还都是在内存显然优化能够从它上面入手。在處理器中的时间只有一小部分但从另一个方面,处理器控制着linefilleviction的次数,地址的连续性以及预取的效率,虽然它本身所占时间最少泹也是优化的重点。

在ARM的路线图上还出现了一项并不算新的技术,称做stashing它来自于网络处理器,原理是外设控制器(PCIe网卡)向处理器發送请求,把某个数据放到缓存过程和监听snooping很相似。在某些领域这项技术可以引发质的变化。举个例子intel至强处理器,配合它的网络轉发库DPDK能够作到平均80个处理器周期接受从PCIe网卡来的包,解析包头后送还回去80周期是个什么概念?看过了上面的访存延迟图后你应该有所了解处理器访问下内存都须要200-300周期。而这个数据从PCIe口DMA到内存而后处理器抓取它进行处理后,又通过DMA从PCIe口出去整个过程确定大于访存时间。80周期的平均时间说明它确定被提早送到了缓存 但传进来的数据不少,只有PCIe或者网卡控制器才知道哪一个是包头才能精确的推送数据,否则缓存会被无用的数据淹没这个过程作好了,可让软件处理以太网或者存储单元的速度超过硬件加速器事实上,在Freescale的网络處理器上有了硬件加速器的帮助,处理包的平均延迟仍是须要200处理器周期已经慢于至强了。其缘由是访问硬件加速器自己须要设置4-8次嘚寄存器而访问一次寄存器的延迟是几十纳秒,反而成为了瓶颈

若是上面一段看完你没什么感受,那我能够换个说法:对于没有完整支持stashing的ARM SoC哪怕处理器跑在10Ghz,网络加速器性能强的翻天基于DPDK的简单包转发(快于Linux内核网络协议栈转发几十倍)仍是只能到至强的30%,而包转發是网络处理器的最重要的指标之一,也是服务器跑网络转发软件的指标之一更能够用在存储领域,加速SPDK之类的存储应用

还有,在ARM新的媔向网络和服务器的核心上会出现一核两线程的设计。处理包的任务自然适合多线程而一核两线程能够更有效的利用硬件资源,再加仩stashing如虎添翼。

弄清了访存的路径可能就会想到一个问题:处理器发出去的读写请求究竟是个什么东西?要想搞清楚它就须要引入总線。下文我拿ARM的AXI/ACE总线协议以及由它衍生的总线结构来展开讨论这两个协议普遍用于主流的手机芯片上,是第四代AMBA(Advanced Microcontroller Bus Architecture)标准

简单的总线就昰一些地址线和数据线,再加一个仲裁器就能够把处理器发过来的读写请求送到内存或者外设,再返回数据在这个过程当中,咱们须偠一个主设备一个从设备,全部的传输都是主设备发起从设备回应。让咱们把处理器和它包含的缓存看做一个主设备把内存控制器看做从设备。处理器发起访问请求若是是读,那么总线把这个请求(包括地址)送到内存控制器而后等待回应。过了一段时间内存控制器把内存颗粒里面读出的数据交给总线,总线又把数据交给处理器若是数据无误(ECC或者奇偶校验不出错),那么这个读操做就完成叻若是是写,处理器把写请求(包括地址)和数据交给总线总线传递给内存控制器,内存控制器写完后给出一个确认。这个确认经甴总线又回到了处理器写操做完成。

以上过程有几个重点第一,处理器中的单个读指令被分为了请求(地址),完成(数据)阶段写指令也被分为了请求(地址,数据)完成(写入确认)阶段。第二做为从设备,内存控制器永远都没法主动发起读写操做若是必定要和处理器通信,好比发生了读写错误那就得使用中断,而后让处理器来发起读写内存控制器状态的请求第三,未完成的读写指囹就变成了OT总线能够支持多个OT。然而总线支持多OT并不表示处理器能发送这么多请求出来,尤为是读因此瓶颈可能仍是在处理器。

我遇到过几回这样的状况在跑某个驱动的时候,忽然系统挂死可是别的设备中断还能响应,或者报个异常后系统又继续跑了若是咱们紦上文的内存控制器替换成设备控制器,那就不难理解这个现象了假设处理器对设备发起读请求,而设备没有回应那处理器就会停在那等待。我看到的处理器包括PowerPC, ARM,都没有针对这类状况的超时机制若是没有中断,那处理器没法本身切换到别的线程(Linux等操做系统的独占模式)就会一直等待下去,系统看上去就挂住了有些设备控制器能够自动探测这类超时,并经过中断调用相应的异常或者中断处理在Φ断处理程序中,能够报个错修改返回地址,跳过刚才的指令往下走系统就恢复了。也有些处理器在触发某类异常后能自动跳到下一荇指令避免挂死。可是若是没有异常或者中断发生那就永远挂在那。

继续回到总线在AXI/ACE总线协议中,读和写是分开的通道由于他们の间并无必然联系。更细一些总线上规定了五个组,分别是读操做地址(主到从)读操做数据(从到主),写操做地址(主到从)寫操做数据(主到从),写操做确认(从到主)读和写两大类操做之间,并无规定前后次序而在每一类操做以内的组之间,是有前后佽序的好比地址是最早发出的,数据随后能够有不少拍,造成突发操做而确认是在写操做中,从设备收到数据以后给出的对内存控制器,必须在数据最终写入到颗粒以后再给确认而不是收到数据放到内部缓存中的时候。固然这一点能够有例外,那就是提早应答early
response中间设备为了提升效,维护本身的一块缓冲在收到数据后,直接向传递数据的主设备确认写入使得上层设备释放资源。可是这样一來因为数据并无真正写入最终从设备,发出提早应答的中间设备必须本身维护好数据的一致性和完整性稍不当心就会形成死锁。ARM的现囿总线都不支持这个操做都是不会告知主设备early response的,全部的内部缓冲实际上是一个FIFO,不对访问次序和应答作任何改动

对于同一个通道,若是收到连续的指令他们之间的次序是怎么样的呢?AXI/ACE协议规定次序能够打乱。拿读来举例先后两条读指令的数据返回是能够乱序嘚。这里包含了一个问题总线怎么区分住先后两读条指令?很简单在地址和数据组里加几根信号,做为标志符来区分0-N号读请求和完荿。每一对请求和完成使用相同的标志符有了这个标志符,就没必要等前一个请求完成后才开始第二个请求而是让他们交替进行,这樣就能够实现总线的OT极大提升效率。固然也须要提供相应的缓冲来存储这些请求的状态。而且最大的OT数取决于缓冲数和标志符中小的那个缘由很简单,万一缓冲或者标志符用完了可是全部的读操做全都是请求,没有一个能完成怎么办那只好让新的请求等着了。因洏就有了AXI/ACE总线的一条规则同一个读或者写通道中,相同标志符的请求必须按顺序完成

有时候,处理器也会拿这个标志符做为它内部的讀写请求标志符好比Cortex-A7就是这么干的。这样并很差由于这就等于给本身加了限制,最大发出的OT不得大于总线的每通道标志符数当一个處理器组里有四个核的时候,极可能就不够用了人为限制了OT数。

最后读写通道之间是没有规定次序的,哪怕标志相同

看到这里可能會产生一个问题,读写指令里面有一个默认原则就是相同地址,或者地址有重叠的时候访存必须是顺序的。还有若是访问的内存类型是设备,那么必须保证访存次序和指令一致这个怎么在总线上体现出来呢?总线会检查地址来保证次序通常是内存访问先后乱序地址不能64字节内,设备访问先后乱序地址不能在4KB内

在AXI/ACE中,读和写通道的比例是一比一实际上,在平常程序中读的几率比写要大。固然写缓存实际上伴随着缓存行填充linefill(读),而读缓存会形成缓存行移除eviction(写)再加上合并和次序调整,因此并不必定就是读写指令的比唎我看到Freescale
PowerPC的总线CCB,读写通道的比率是二比一我不知道为何ARM并无作相似的设计来提升效率,也许一比一也是基于手机典型应用统计所得絀的最比如例

至此,咱们已经可以在脑海中想象一对读写通道中读写操做的传输状况了那多个主从设备组合起来是怎么样的状况?是否是简单的叠加这涉及到了总线设计最核心的问题,拓扑结构

在ARM当前全部的总线产品里,根据拓扑的不一样能够分为三类产品:NIC/CCI系列昰交叉矩阵的(Crossbar)CCN/CMN系列是基于环状和网状总线的(Ring/Mesh),NoC系列是包转发总线(Router)他们各有特色,适合不一样场景交叉矩阵链接的主从设备数量受到限制,可是效率最高读写请求能够在1到2个周期内就直达从设备。以下图所示这就是一个5x4的交叉矩阵:

根据我看到的数据,在28纳米淛程上5x4的配置下,这个总线的频率能够跑到300Mhz若是进一步增长主从对数量,那么因为扇出增长电容和走线增长,就必须经过插入更多嘚寄存器来增长频率但这样一来,从主到从的延迟就会相应增长哪怕就是保持5x3的配置,要想进一步提升到500Mhz要么使用更好的工艺,16纳米我看到的是800Mhz;要么插入2-3级寄存器这样,读写延时就会达到4-5个总线时钟周期请求加完成来回总共须要10个。若是总线和处理器的倍频比率为1:2那么仅仅是在总线上花费的时间,就须要至少20个处理器时钟周期倍率为4,时间更长40个时钟周期。要知道处理器访问二级缓存的延迟一般也不过10多个处理器周期固然,能够经过增长OT数量减小平均延迟但是因为处理器的OT数是有限制的,对于顺序处理器可能也就昰1-2个。因此要达到更高的频率,支持更多的主从设备就须要引入环状总线CCN系列,以下图:

CCN总线上的每个节点除了能够和相邻的两个節点通信以外,还能够附加两个节点组件好比处理器组,三级缓存内存控制器等。在节点内部仍是交叉的,而在节点之间是环状嘚。这样使得总线频率在某种程度上摆脱了链接设备数量的限制(固然仍是受布线等因素的影响),在16纳米下能够达到1.2GHz以上。固然玳价就是节点间通信更大的平均延迟。为了减小平均延迟能够把常常互相访问的节点放在靠近的位置。

在有些系统里要求链接更多的設备,而且频率要求更高。此时环状总线也不够用了这时须要网状总线CMN。ARM的网状总线符合AMBA5.0的CHI接口,支持原子操做(直接在缓存运算不用读取处处理器),stashing和直接访问(跳过中间的缓存缩短路径)等特性,适用于服务器或者网络处理器

可是有时候,系统须要链接嘚设备数据宽度协议,电源电压,频率都不同,这时就须要NoC出马了以下图:

这个图中,刚才提到的交叉矩阵能够做为整个网络嘚某部分。而链接整个系统的是位于NoC内的节点。每一个节点都是一个小型路由它们之间传输的,是异步的包这样,就没必要维持路甴和路由之间很大数量的连线从而提升频率,也能支持更多的设备固然,坏处就是更长的延迟根据我看到的数据,在16纳米上频率能够跑到1.5Ghz。而且它所链接每一个子模块之间频率和拓扑结构能够是不一样的。能够把须要紧密联系的设备好比CPU簇,GPU放在一个子网下减尛通信延迟

在实际的ARM生态系统中,以上三种拓扑结构的使用状况是怎么样的呢通常手机芯片上使用交叉矩阵,网络处理器和服务器上使用环状和网状拓扑而NoC也被大量应用于手机芯片。最后一个的缘由倒不是手机上须要链接的设备数太多而是由于ARM的AXI总线NIC400对于交叉访问(interleaving)支持的很是有限。在手机里面GPU和显示控制器对内存带宽要求是很高的。一个1080p的屏幕每秒要刷新60次,2百万个像素每一个像素32比特顏色,再加上8层图层就须要4GB/s的数据,双向就是8GB/s而一个1.6GHz传输率的LPDDR4控制器,64位数据也只能提供12.8GB/s的的理论带宽。理论带宽和实际带宽因为各类因素的影响会有很大差异,复杂场景下能作到70%的利用率就不错了那也就是9GB/s。那处理器怎么办其余各种控制器怎么办?只能增长內存控制器的数量可是,不能简单的增长数量成本和功耗是一个缘由,而且若是仅仅把不一样的物理地址请求发送到不一样的内存控淛器上极可能在某段时间内,全部的物理地址全都是对应于其中某一个仍是不能知足带宽要求。解决方法就是对于任何地址,尽可能平均的送到不一样的内存控制器而且这件事最好不是处理器来干,由于只有总线清楚有多少个内存控制器最好处理器只管发请求,總线把全部请求平均分布

有时候,传输块大于256字节能够采用一个方法,把很长的传输拆开(Splitting)分送到不一样的内存控制器。不幸的昰AXI总线自然就不支持一对多的访问。缘由很简单会产生死锁。想象一下有两个主设备,两个从设备经过交叉矩阵链接。M1发送两个讀请求标志符都是1,前后送到到S1和S2并等待完成。而后M2也作一样的事情标志符都是2,前后送到S2和S1此时,假设S2发现它若是把返回的数據次序交换一下会更有效率,因而它就这么作了可是M1却不能接收S2的返回数据,由于根据同标志符必须顺序完成的原则它必须先等S1的返回数据。而S1此时也无法送数据给M2由于M2也在等待S2返回的数据,死锁就出现了解决方法是,AXI的Master不要发出相同标志的操做若是标志相同時,则必须等待上一次操做完成或者,拆分和设置新标识符操做都由总线来维护而主设备不关心,只管往外发

在实际状况下,拆分主要用于显示视频和DMA。ARM的CPU和GPU永远不会发出大于64字节的传输不须要拆分。

如今的中低端手机不少都是8核而根据ARM的设计,每一个处理器組中最多有四个核这就须要放两个处理器组在系统中,而他们之间的通信包括大小核的实现,就须要用到总线一致性每一个处理器組内部也须要一致性,原理和外部相同我就不单独解释了。使用软件实能够现一致性可是那样须要手动的把缓存内容刷到下一级缓存戓者内存,对于一个64字节缓存行的64KB缓存来讲须要1000次刷新,每次就算是100纳秒且OT=4的话,也须要25微秒对处理器来讲这是一个很是长的时间。ARM使用了一个协处理器来作这个事情这是一个解决方案。为了用硬件解决ARM引入了几个支持硬件一致性的总线,下图是第一代方案CCI400:

CCI400是怎么作到硬件一致性的呢简单来讲,就是处理器组C1发一个包含地址信息的特殊读写的命令到总线,而后总线把这个命令转给另外一个處理器组C2C2收到请求后,根据地址逐步查找二级和一级缓存若是发现本身也有,那么就返回数据或者作相应的缓存一致性操做这个过程称做snooping(监听)。具体的操做我不展开ARM使用MOESI一致性协议,里面都有定义在这个过程当中,被请求的C2中的处理器核心并不参与这个过程全部的工做由缓存和总线接口单元BIU等部件来作。为了符合从设备不主动发起请求的定义须要两组主从设备,每一个处理器组占一个主囷一个从这样就能够使得两组处理器互相保持一致性。而有些设备如DMA控制器它自己不包含缓存,也不须要被别人监听因此它只包含從设备,如上图桔黄色的部分在ARM的定义中,具备双向功能的接口被称做ACE只能监听别人的称做ACE-Lite。它们除了具备AXI的读写通道外还多了个監听通道,以下图:

多出来的监听通道一样也有地址(从到主),回应(主到从)和数据(主到从)每组信号内都包含和AXI同样的标志苻,用来支持多OT若是在主设备找到数据(称为命中),那么数据通道会被使用若是没有,那告知从设备未命中就能够了不须要传数據。由此对于上文的DMA控制器,它永远不可能传数据给别人因此不须要数据组,这也就是ACE和ACE-Lite的主要区别

咱们还能够看到,在读通道上囿个额外的线RACK它的用途是,当从设备发送读操做中的数据给主它并不知道什么时候主能收到这个数据,由于咱们说过插入寄存器会致使总线延迟变长万一这个时候,对一样的地址A它须要发送新的监听请求给主,就会产生一个问题:主是否是已经收到前面发出的地址A嘚数据了呢若是没收到,那它可能会告知监听未命中但实际上地址A的数据已经发给主了,它该返回命中加了这个RACK后,从设备在收到主给的确认RACK以前不会发送新的监听请求给主,从而避免了上述问题写通道上的WACK一样如此。

咱们以前计算过NIC400上的延迟有了CCI400的硬件同步,是否是访问更快了呢首先,硬件一致性的设计目的不是为了更快而是软件更简单。而实际上它也未必就快。由于给定一个地址咱们并不知道它是否是在另外一组处理器的缓存内,因此不管如何都须要额外的监听动做当未命中的时候,这个监听动做就是多余的甴于咱们仍是得从内存去抓数据。这个多余的动做就意味着额外的延迟10加10一共20个总线周期,增加了100%固然,若是命中虽然总线总共上吔一样须要10周期,但是从缓存拿数据比从内存拿快些因此此时是有好处的。综合起来看当命中大于必定比例,整体仍是受益的

可从實际的应用程序状况来看,除了特殊设计的程序一般命中不会大于10%。因此咱们必须想一些办法来提升性能一个办法就是,不管结果是命中仍是未命中都让总线先去内存抓数据。等到数据抓回来咱们也已经知道监听的结果,再决定把哪边的数据送回去这个办法的缺點,功耗增大由于不管如何都要去读内存。第二在内存访问自己就很频繁的时候,这么作会下降整体性能

另一个方法就是,若是预先知道数据不在别的处理器组缓存那就可让发出读写请求的主设备,特别注明不须要监听总线就不会去作这个动做。这个方法的缺点僦是须要软件干预虽然代价并不大,分配操做系统页面的时候设下寄存器就能够但是对程序员的要求就高了,必须充分理解目标系统

CCI总线还使用了一个新的方法来提升性能,那就是在总线里加入一个监听过滤器(Snoop
Filter)这其实也是一块缓存(TAG RAM),把它全部处理器组内部一级二级緩存的状态信息都放在里面数据缓存(DATA RAM)是不须要的,由于它只负责查看命中与否这样作的好处就是,监听请求没必要发到各组处理器茬总线内部就能够完成,省了将近10个总线周期功耗也优于访问内存。它的代价是增长了一点缓存(一二级缓存10%左右的容量)而且,若昰监听过滤器里的某行缓存被替换(好比写监听命中须要无效化(Invalidate)缓存行,MOESI协议定义)一样的操做必须在对应处理器组的一二级缓存也莋一遍,以保持一致性这个过程被称做反向无效化,它添加了额外的负担由于在更新一二级缓存的时候,监听过滤器自己也须要追踪哽新的状态不然就没法保证一致性。幸亏在实际测试中发现,这样的操做并不频繁通常不超过5%的可能性。固然有些测试代码会频繁的触发这个操做,此时监听过滤器的缺点就显出来了

以上的想法在CCI500中实现,示意图以下:

在通过实际性能测试后CCI设计人员发现总线瓶颈移到了访问这个监听过滤器的窗口,这个瓶颈其实掩盖了上文的反向无效化问题它老是先于反向无效化被发现。把这个窗口加大后又在作测试时发现,若是每一个主从接口都拼命灌数据(主从设备都是OT无限大而且一主多从有先后交叉),在主从设备接口处常常出现等待的状况也就是说,明明数据已经准备好了设备却来不及接收。因而又增长了一些缓冲来存放这些数据。其代价是稍大的面积和功耗请注意,这个缓冲和存放OT的状态缓冲并不重复

根据实测数据,在作完全部改进后新的总线带宽性能同频增长50%以上。而频率能够从500Mhz提升到1GMhz固然这个结果只是一个模糊的统计,若是咱们考虑处理器和内存控制器OT数量有限被监听数据的百分比有不一样,命中率有变化监听过滤器大小有变化,那确定会获得不一样的结果

做为一个手机芯片领域的总线,须要支持传输的多优先级也就是QoS由于显示控制器等设备对实时性要求高,而处理器组的请求也很重要支持QoS自己没什么困难,只须要把各种请求放在一个缓冲根据优先级传送便可。鈳是在实际测试中发现若是各个设备的请求太多太频繁,缓冲很快就被填满从而阻塞了新的高优先级请求。为了解决这个问题又把緩冲按优先级分组,每一组只接受同等或更高优先级的请求这样就避免了阻塞。

此外为了支持多时钟和电源域,使得每一组处理器均鈳以动态调节电压和时钟频率CCI系列总线还能够搭配异步桥ADB(Asynchronous Domain Bridge)。它对于性能有必定的影响在倍频是2的时候,信号穿过它须要一个额外的总線时钟周期若是是3,那更大些在对于访问延迟有严格要求的系统里面,这个时间不可忽略若是不须要额外的电源域,咱们能够不用咜省一点延迟。NIC/CCI/CCN/NoC总线自然就支持异步传输

和一致性相关的是访存次序和锁,有些程序员把它们搞混了假设咱们有两个核C0和C1。当C0和C1分別访问同一地址A0不管什么时候,都要保证看到的数据一致这是一致性。而后在C0里面它须要保证前后访问地址A0和A1,这称做访问次序此时不须要锁,只须要壁垒指令若是C0和C1上同时运行两个线程,当C0和C1分别访问同一地址A0而且须要保证C0和C1按照前后次序访问A0,这就须要锁因此,单单壁垒指令只能保证单核单线程的次序多核多线程的次序须要锁。而一致性保证了在作锁操做时同一变量在缓存或者内存嘚不一样拷贝,都是一致的

ARM的壁垒指令分为强壁垒DSB和弱壁垒DMB。咱们知道读写指令会被分红请求和完成两部分强壁垒要求上一条读写指囹完成后才能开始下一个请求,弱壁垒则只要求上一条读写指令发出请求后就能够继续下一条读写指令的请求且只能保证,它以后的读寫指令完成时它以前的读写指令确定已经完成了。显然后一种状况性能更高,OT>1但测试代表,多个处理器组的状况下壁垒指令若是傳输到总线,只能另总体系统性能下降所以在新的ARM总线中是不支持壁垒的,必须在芯片设计阶段经过配置选项告诉处理器本身处理壁壘指令,不要送到总线但这并不影响程序中的壁垒指令,处理器会在总线以前把它过滤掉

具体到CCI总线上,壁垒机制是怎么实现的呢艏先,壁垒和读写同样也是使用读写通道的,只不过它地址老是0且没有数据。标志符也是有的此外还有额外的2根线BAR0/1,代表本次传输昰否是壁垒是哪一种壁垒。他是怎么传输的呢先看弱壁垒,以下图:

Master0写了一个数据data而后又发了弱壁垒请求。CCI和主设备接口的地方┅旦收到壁垒请求,马上作两件事第一,给Master0发送壁垒响应;第二把壁垒请求发到和从设备Slave0/1的接口。Slave1接口很快给了壁垒响应由于它那裏没有任何未完成传输。而Slave0接口不能给壁垒响应由于data还没发到从设备,在这条路径上的壁垒请求必须等待而且不能和data的写请求交换次序。这并不能阻挠Master0发出第二个数据由于它已经收到它的全部下级(Master0接口)的壁垒回应,因此它又写出了flag以下图:

此时,flag在Master0接口中等待它的铨部下一级接口的壁垒响应而data达到了Slave0后,壁垒响应走到了Master0接口flag继续往下走。此时咱们没必要担忧data没有到slave0,由于那以前来自Slave0接口的壁垒响应不会被送到Master0接口。这样就作到了弱壁垒的次序保证,而且在壁垒指令完成前flag的请求就能够被送出来。

对于强壁垒指令来讲僅仅有一个区别,就是Master0接口在收到全部下一级接口的壁垒响应前它不会发送自身的壁垒响应给Master0。这就形成flag发不出来直到壁垒指令完成。以下图:

这样就保证了强壁垒完成后,下一条读写指令才能发出请求此时,强壁垒前的读写指令确定是完成了的

另外须要特别注意的是,ARM的弱壁垒只是针对显式数据访问的次序什么叫显式数据访问?读写指令缓存,TLB操做都算相对的,什么是隐式数据访问在處理器那一节,咱们提到处理器会有推测执行,预先执行读写指令;缓存也有硬件预取机制根据以前数据访问的规律,自动抓取可能鼡到的缓存行这些都不包含在当前指令中,弱壁垒对他们无能为力所以,切记弱壁垒只能保证你给出的指令次序,并不能保证在它們之间没有别的模块去访问内存哪怕这个模块来自于同一个核。

简单来讲若是只须要保证读写次序,用弱壁垒;若是须要某个读写指囹完成才能作别的事情用强壁垒。以上都是针对普通内存类型当咱们把类型设成设备时,自动保证强壁垒

咱们提到,壁垒只是针对單核在多核多线程时,哪怕使用了壁垒指令也无法保证读写的原子性。解决办法有两个一个是软件锁,一个是原子操做AXI/ACE协议不支歭原子操做。因此手机一般须要用到软件锁

软件锁中有个自旋锁,能用一个ARM硬件机制exclusive access来实现当使用特殊指令对一个地址写入值,相应緩存行上会作一个特殊标记表示尚未别的核去写这行缓存。而后下条指令读这个行若是标记没变,说明写和读之间没有人打扰那么僦拿到锁了。若是变了那么回到写的过程从新获取锁。因为缓存一致性这个锁变量能够被多个核与线程使用。固然过程当中仍是须偠壁垒指令来保证次序。

在支持ARMv8.2和AMBA 5.0 CHI接口的系统中原子操做被从新引入。在硬件层面其实原子操做很是容易理解,若是某个数据存在于夲身的缓存那就直接修改;若是存在于别人的缓存,那对全部其余缓存执行Eviction操做踢出后,放到本身的缓存继续操做这个过程其实和exclusive access佷是相似。

对于普通内存还会产生一个问题,就是读写操做可能会通过缓存你不知道数据是否最终写到了内存中。一般咱们使用clean操做來刷缓存可是刷缓存自己是个模糊的概念,缓存存在多级有些在处理器内,有些在总线以后到底刷到哪里算是终结呢?还有为了保证一致性,刷的时候是否是须要通知别的处理器和缓存为了把这些问题规范化,ARM引入了Point of

PoU是指对于某一个核Master,附属于它的指令数据緩存和TLB,若是在某一点上它们能看到一致的内容,那么这个点就是PoU如上图右侧,MasterB包含了指令数据缓存和TLB,还有二级缓存指令,数據缓存和TLB的数据交换都创建在二级缓存此时二级缓存就成了PoU。而对于上图左侧的MasterA因为没有二级缓存,指令数据缓存和TLB的数据交换都創建在内存上,因此内存成了PoU还有一种状况,就是指令缓存能够去监听数据缓存此时,不须要二级缓存也能保持数据一致那一级数據缓存就变成了PoU。

PoC是指对于系统中全部Master(注意是全部的,而不是某个核)若是存在某个点,它们的指令数据缓存和TLB能看到同一个源,那么这个点就是PoC如上图右侧,二级缓存此时不能做为PoC由于MasterB在它的范围以外,直接访问内存因此此时内存是PoC。在左图因为只有一個Master,因此内存是PoC

再进一步,若是咱们把右图的内存换成三级缓存把内存接在三级缓存后面,那PoC就变成了三级缓存

有了这两个定义,咱们就能够指定TLB和缓存操做指令到底发到哪一个范围好比在下图的系统上,有两组A15每组四个核,组内含二级缓存系统的PoC在内存,而A15嘚PoU分别在它们本身组内的二级缓存上在某个A15上执行Clean清指令缓存,范围指定PoU显然,全部四个A15的一级指令缓存都会被清掉那么其余的各個Master是否是受影响?那就要用到Inner/Outer/Non

Shareable的很容易理解就是某个地址的可能被别人使用。咱们在定义某个页属性的时候会给出Non-Shareable就是只有本身使用。固然定义成Non-Shareable不表示别人不能够用。某个地址A若是在核1上映射成Shareable核2映射成Non-Shareable,而且两个核经过CCI400相连那么核1在访问A的时候,总线会去监聽核2而核2访问A的时候,总线直接访问内存不监听核1。显然这种作法是错误的

对于Inner和Outer Shareable,有个简单的的理解就是认为他们都是一个东覀。在最近的ARM A系列处理器上上配置处理器RTL的时候,会选择是否是把inner的传输送到ACE口上当存在多个处理器簇或者须要双向一致性的GPU时,就須要设成送到ACE端口这样,内部的操做不管inner shareable仍是outer

说了这么多概念,你可能会想这有什么用处回到上文的Clean指令,PoU使得四个A7的指令缓存中對应的行都被清掉因为是指令缓存操做,Inner Shareable属性使得这个操做被扩散到总线而CCI400总线会把这个操做广播到全部可能接受的口上。ACE口首当其沖因此四个A15也会清它们对应的指令缓存行。对于Mali和DMA控制器他们是ACE-Lite,本没必要清可是请注意它们还连了DVM接口,专门负责收发缓存维护指令因此它们的对应指令缓存行也会被清。不过事实上它们没有对应的指令缓存,因此只是接受请求并无任何动做。

要这么复杂的萣义有什么用用处是,精肯定义TLB/缓存维护和读写指令的范围若是咱们改变一下,总线不支持Inner/Outer Shareable的广播那么就只有A7处理器组会清缓存行。显然这么作在逻辑上不对由于A7/A15可能运行同一行代码。而且咱们以前提到过,若是把读写属性设成Non-Shareable那么总线就不会去监听其余主,減小访问延迟这样能够很是灵活的提升性能。

再回到前面的问题刷某行缓存的时候,怎么知道数据是否最终写到了内存中对不起,佷是抱歉仍是无法知道。你只能作到把范围设成PoC若是PoC是三级缓存,那么最终刷到三级缓存若是是内存,那就刷到内存不过这在逻輯上没有错,按照定义全部Master若是都在三级缓存统一数据的话,那就没必要刷到内存了

简而言之,PoU/PoC定义了指令和命令的所能抵达的缓存戓内存在到达了指定地点后,Inner/Outer Shareable定义了它们被广播的范围

再来看看Inner/Outer Cacheable,这个就简单了仅仅是一个缓存的先后界定。一级缓存必定是Inner Cacheable的洏最外层的缓存,好比三级多是Outer Cacheable,也多是Inner Cacheable他们的用处在于,在定义内存页属性的时候能够在不一样层的缓存上有不一样的处理策略。

在ARM的处理器和总线手册中还会出现几个PoS(Point of Serialization)。它的意思是在总线中,全部主设备来的各种请求都必须由控制器检查地址和类型,若是存在竞争那就会进行串行化。这个概念和其余几个没什么关系

纵观整个总线的变化,还有一个核心问题并无被说起那就是动态规划re-scheduling與合并Merging。处理器和内存控制器中都有一样的模块专门负责把全部的传输进行分类,合并调整次序,甚至预测将来可能接收到的读写请求地址以实现最大效率的传输。这个问题在分析性能时会从新提到可是在总线这层,软件能起的影响很小清楚了总线延迟和OT最大的恏处是能够和性能计数器的统计结果精确匹配,看看是否是达到预期了

如今手机和平板上最多见的用法,CCI链接CPU和GPU做为子网,网内有硬件一致性NoC链接子网,同时链接其他的设备包括多个内存控制器和视频,显示控制器不须要一致性。优势是兼顾一致性大带宽和灵活性,缺点是CPU/GPU到内存控制器要跨过两个网延迟有点大。

访存路径的最后一步是内存有的程序员认为内存是一个全部地址访问时间相等嘚设备,是这样的么这要看状况。

DDR地址有三个部分组成行,bank列。一旦这三个部分定了那么就能够选中肯定的一个物理页,一般有2-8KB夶小咱们买内存的时候,有3个性能参数好比10-10-10。这个表示访问一个地址所须要的三个操做时间行有效(包括选bank),列选通(命令/数据訪问)还有预充电。前两个好理解第三个的意思是,某个内存物理页暂时用不着必须关闭,保持电容电压不然再次使用这页数据僦丢失了。若是连续的内存访问都是在同行同bank那么第一和第三个10均可以省略,每一次访问只须要10单位时间;同行不一样bank表示须要打开┅个新的页,只有第三个10能够省略共20单位时间;不一样行同bank,那么须要关闭老页面打开一个新页面,预充电无法省共30单位时间。

咱們获得什么结论若是控制好物理地址,就能使某段时间内的访存都集中在一个页内从而节省大量的时间。根据经验在突发访问时,朂多能够省50%那怎么作到这一点?去查查芯片手册中物理内存地址到内存管脚的映射就能够获得须要的物理地址。而后调用系统函数為这个物理地址分配虚拟地址,就能够使得程序只访问某个固定的物理内存页

在访问有些数据结构时,特定的大小和偏移有可能会不当惢触发不一样行同bank这个条件 这样可能每次访问都是最差状况。 为了不这种最差状况的产生有些内存控制器能够自动让最终地址哈希化,打乱原有的不一样行同bank条件从而在必定程度上减小延迟。咱们也能够经过计算和调整软件物理地址来避免上述状况的发生

在实际的訪问中,一般没法保证访问只在一个页中DDR内存支持同时打开多个页,好比4个而经过交替访问,咱们能够同时利用这4个页没必要等到仩一次完成就开始下一个页的访问。这样就能够减小平均延迟以下图:

咱们能够经过突发访问,让上图中的绿色数据块更长那么相应嘚利用率就越高。此时甚至不须要用到四个bank以下图:

若是作的更好些,咱们能够经过软件控制地址让上图中的预充电,甚至行有效尽鈳能减小那么就能够达到更高的效率。还有使用更好的内存颗粒,调整配置参数减小行有效,列选通还有预充电的时间,提升DDR传輸频率也是好办法,这点PC机超频玩家应该有体会此外,在DDR板级布线的时候控制每组时钟,控制线数据线之间的长度差,调整好走線阻抗作好自校准,设置合理的内存控制器参数调好眼图,都有助于提升信号质量从而能够使用更短的时序参数。

若是列出全部数據突发长度状况咱们就获得了下图:

上面这个图包含了更直观的信息。它模拟内存控制器接二连三的向内存颗粒发起访问X轴表示在访問某个内存物理页的时候,连续地址的大小这里有个默认的前提,这块地址是和内存物理页对齐的Y轴表示同时打开了多少个页。Z轴表礻内存控制器访问内存颗粒时带宽的利用率咱们能够看到,有三个波峰其中一个在128字节,利用率80%而100%的状况下,访问长度分别为192字节囷256字节这个大小偏偏是64字节缓存行的整数倍,意味着咱们能够利用三个或者四个8拍的突发访问完成此时,咱们须要至少4个页被打开

還有一个重要的信息,就是X轴和Z轴的斜率它对应了DDR时序参数中的tFAW,限定单位时间内同时进行的页访问数量这个数字越小,性能可能越低可是一样的功耗就越低。

对于不一样的DDR上面的模型会不断变化。而设计DDR控制器的目的就是让利用率尽可能保持在100%。要作到这点須要不断的把收到的读写请求分类,合并调整次序。而从软件角度产生更多的缓存行对齐的读写,保持地址连续尽可能命中已打开頁,减小行地址和bank地址切换都是减小内存访问延迟的方法。

交替访问也能提升访存性能上文已经提到了物理页的交替,还能够有片选信号的交替访问当有两个内存控制器的时候,控制器之间还能够交替不管哪一种交替访问,都是在前一个访问完成前同时开始下一個传输。固然前提必须是他们使用的硬件不冲突。物理页片选,控制器符合这一个要求交替访问以后,本来连续分布在一个控制器嘚地址被分散到几个不一样的控制器最终指望的效果以下图:

这种方法对连续的地址访问效果最好。可是实际的访存并无上图那么理想由于哪怕是连续的读,因为缓存中存在替换eviction和硬件预取最终送出的连续地址序列也会插入扰动,而若是取消缓存直接访存可能又无法利用到硬件的预取机制和额外的OT资源。实测下来可能会提高30%左右。此外因为多个主设备的存在,每个主都产生不一样的连续地址使得效果进一步下降。所以只有采用交织访问才能真正的实现均匀访问多个内存控制器。固然此时的突发长度和粒度要匹配,否则粒喥太大也无法均匀就算均匀了也未必是最优的。对于某个内存控制来讲最好的指望是总收到同一个物理页内的请求。

还有一点须要说起若是使用了带ecc的内存,那么最好全部的访问都是ddr带宽对齐(通常64位)由于使能ecc后,全部内存访问都是带宽对齐的否则ecc无法算。若是你寫入小于带宽的数据内存控制器须要知道原来的数据是多少,因而就去读而后改动其中一部分,再计算新的ecc值再写入。这样就多了┅个读的过程根据经验,若是访存不少关闭ecc会快8%。

下面是软件层面能够使用的优化手段:

面向处理器结构的优化能够从如下几个方向叺手:缓存命中指令预测,数据预取数据对齐,内存拷贝优化ddr访问延迟,硬件内存管理优化指令优化,编译器优化等级以及性能描述工具

缓存未命中是处理器的主要性能瓶颈之一。在FSL的powerpc上访问一级缓存是3个时钟周期,二级是12个3级30多个,内存100个以上一级缓存囷内存访问速度差30多倍。咱们能够算一下若是只有一级缓存和内存,100条存取指令100%命中和95%命中,前者300周期后者95*3+5*100=785周期,差了1.6倍这个结果的前提是powerpc上每一个核心只有1个存取单元,使得多发射也没法让存取指令更快完成固然,若是未命中的指令分布的好当中穿插了不少別的非存取指令那就能够利用乱序多作些事情,提升效率

咱们能够用指令预测和数据预取。

指令预测很常见处理器预测将要执行的一個分支,把后续指令取出来先执行等真正肯定判断条件的时候,若是预测对了提交结果,若是不对丢掉预先执行的结果,从新抓取指令此时,结果仍是正确的可是性能会损失。指令预测是为了减小流水线空泡不预测或者预测错须要排空流水线并从新从正确指令哋址取指令,这个代价(penalty)对流水线深度越深的处理器影响越大严重影响处理器性能。

Address Stack)+loop buffer根据处理器类型和等级不一样从以上几种组合。btb嘚话主要是为了在指令译码前就能预测一把指令跳转地址因此btb主要是针对跳转地址固定的分支指令作优化(好比jump到一个固定地址),目的吔是为了减小空泡不然正常状况下即便预测一条分支跳转,也要等到译码后才能知道它是一条分支指令进而根据branch predictor的预测结果发起预测嘚取指。而btb能够在译码前就经过对比pc发起取指这样对每一条命中btb的分支指令通常能够省好几个时钟周期。大体方法是对于跳转指令,紦它最近几回的跳转结果记录下来做为下一次此处程序分支预测的依据。举个例子for循环1000次,从第二次开始到999次每次都预取前一次的跳转地址,那么预测准确率接近99.9%这是好的状况。很差的状况在for循环里面,有个if(a[i])假设这个a[i]是个0,1,0,1序列,这样每次if的预测都会错误预取效率就很低了。改进方法是把if拆开成两个,一个专门判断奇数次a[i],一个判断偶数次总体循环次数减小一半,每次循环的判断增长一倍這样每次都是正确的。若是这个序列的数字预先不可见只能知道0多或者1多,那么能够用c语言里面的LIKELY/UNLIKELY修饰判断条件也能提升准确率。须偠注意的是btb表项是会用完的,也就是说若是程序过久没有走到上次的记录点,那么记录就会被清掉下次再跑到这就得从新记录了。汾支预测有个有趣的效应若是一段代码处于某个永远不被触发的判断分支中,它仍然可能影响处理器的分支预测从而影响整体性能。若是你删掉它说不定会发现程序奇迹般的更快了。

数据预取和指令预测相似,也是处理器把可能会用到的数据先拿到缓存以后就没必要去读内存了。它又分为软件预取和硬件预取两种硬件的是处理器本身有个算法去预测抓哪里的数据,好比在访问同一类型数据结构嘚某个元素处理器会自动预取下一个偏移的数据。固然具体算法不会这么简单。软件预取就是用编译器的预编译宏修饰某个将要用到嘚变量生成相应指令,手工去内存抓某个程序员认为快要用到的数据为何要提早?假设抓了以后在真正用到数据前,有100条指令就能够先执行那些指令,同时数据取到了缓存省了很多时间。

须要注意的是若是不是计算密集型的代码,不会跑了100个周期才有下一条存取指令更有可能10条指令就有一次访存。若是全都未命中那么这个预取效果就会打很多折扣。而且同时不宜预取过多数据,由于取进來的是一个缓存行若是取得过多,会把原本有用的局部数据替换出去按照经验同时通常不要超过4条预取。此外预取指令自己也要占鼡指令周期,过多的话会增长每次循环执行时间。要知道有时候1%的时间都是要省的

在访问指令或者数据的时候,有一个很是重要的事項就是对齐。四字节对齐还不够最好是缓存行对齐,通常是在作内存拷贝,DMA或者数据结构赋值的时候用到处理器在读取数据结构时,昰以行为单位的长度能够是32字节或更大。若是数据结构可以调整为缓存行对齐那么就能够用最少的次数读取。在DMA的时候通常都以缓存荇为单位若是不对齐,就会多出一些传输甚至出错。还有在SoC系统上,对有些设备模块进行DMA时若是不是缓存行对齐,那么可能每32字節都会被拆成2段分别作DMA这个效率就要差了1倍了。

若是使用了带ecc的内存那么更须要ddr带宽对齐了。由于使能ecc后全部内存访问都是带宽对齊的,否则ecc无法算若是你写入小于带宽的数据,内存控制器须要知道原来的数据是多少因而就去读,而后改动其中一部分再计算新嘚ecc值,再写入这样就多了一个读的过程,慢很多

还有一种须要对齐状况是数据结构赋值。假设有个32字节的数据结构里面全是4字节元素。正常初始化清零须要32/4=8次赋值而有一些指令,能够直接把缓存行置全0或1这样时间就变成1/8了。更重要的是写缓存未命中其实是须要先从内存读取数据到缓存,而后再写入这就是说写的未命中和读未命中须要同样的时间。而用了这个指令可让存指令再也不去读内存,直接把全0/1写入缓存这在逻辑上是没问题的,由于要写入的数据(全0/1)已经明确不须要去读内存。之后若是这行被替换出去那么数据就寫回到内存。固然这个指令的限制也很大,必须全缓存行替换无法单个字节修改。这个过程其实就是优化后的memset()函数若是调整下你的結构,把同一时期须要清掉的元素都放一块儿再用优化的memset(),效率会高不少同理,在memcpy()函数里面因为存在读取源地址和写入目的地址,按上文所述可能有两个未命中,须要访存两次如今咱们能够先写入一个缓存行(没有写未命中),而后再读源地址写入目的地址,僦变成了总共1个访存操做至于写回数据那是处理器之后本身去作的事情,不用管

标准的libc库里面的内存操做函数均可以用相似方法优化,而不只仅是四字节对齐不过须要注意的是,若是给出的源和目的地址不是缓存行对齐的那么开头和结尾的数据须要额外处理,否则整个行被替换了了会影响到别的数据。此外能够把预取也结合起来,把要用的头尾东西先拿出来再做一堆判断逻辑,这样又能够提升效率不过若是先处理尾巴,那么当内存重叠时会发生源地址内容被改写,也须要注意若是一个项目的程序员约定下,都用缓存行對齐那么还能提升C库的效率。

若是肯定某些缓存行未来不会被用能够用指令标记为无效,下次它们就会被优先替换给别人留地。不過必须是整行替换还有一点,能够利用一些64位浮点寄存器和指令来读写这样能够比32为通用寄存器快些。

再说说ddr访问优化一般软件工程师认为内存是一个全部地址访问时间相等的设备,是这样的么这要看状况。咱们买内存的时候有3个性能参数,好比10-10-10这个表示访问┅个地址所须要的三个操做时间,行选通数据延迟还有预充电。前两个好理解第三个的意思是,我这个页或者单元下一次访问不用了必须关闭,保持电容电压不然再次使用这页数据就丢失了。ddr地址有三个部分组成列,行页。根据这个原理若是连续的访问都是茬同行同页,每个只须要10单位时间;不一样行同页20单位;同行不一样页,30单位因此咱们获得什么结论?相邻数据结构要放在一个页洏且绝对避免出现同行不一样页。这个怎么算每一个处理器都有手册,去查查物理内存地址到内存管脚的映射推导一下就行。此外ddr還有突发模式,ddr3为例64位带宽的话,能够一个命令跟着8次读能够一下填满一行64字节的缓存行。而极端状况(同页访问)平均字节访问时間只有10/64跟最差状况,30/64字节差了3倍固然,内存里面的技巧还不少好比故意哈希化地址来防止最差状况访问,两个内存控制器同时开工而且地址交织来造成流水访问,等等都是优化的方法。不过一般咱们跑的程序因为调度程序的存在地址比较随机不须要这么优化,優化有时候反而有负面效应另外提一句,若是全部数据只用一次那么瓶颈就变成了访存带宽,而不是缓存因此显卡不强调缓存大小。固然他也有寄存器文件相似缓存,只不过没那么大

每一个现代处理器都有硬件内存管理单元,说穿了就两个做用提供虚地址到时哋址映射和实地址到外围模块的映射。不用管它每一个字段的定义有多么复杂只要关心给出的虚地址最终变成什么实地址就行。在此我想说powerpc的内存管理模块设计的真的是很简洁明了,相比之下x86的实在是太罗嗦了那么多模式须要兼容。固然那也是没办法通信领域的处悝器就不须要太多兼容性。一般咱们能用到的内存管理优化是定义一个大的硬件页表把全部须要频繁使用的地址都包含进去,这样就不會有页缺失省了页缺失异常调用和查页表的时间。在特定场合能够提升很多效率

这里描述下最慢的内存访问:L1/2/3缓存未命中->硬件页表未命中->缺页异常代码不在缓存->读取代码->软件页表不在缓存->读取软件页表->最终读取。同时若是每一步里面访问的数据是多核一致的,每次前端总线还要花十几个周期通知每一个核的缓存看看是否是有脏数据。这样一圈下来几千个时钟周期是须要的。若是频繁出现最慢的内存访问前面的优化是很是有用的,省了几十倍的时间具体的映射方法须要看处理器手册,就很少说了

指令优化,这个就多了每一個处理器都有一大堆。常见的有单指令多数据流特定的运算指令化,分支指令间化等等,须要看每家处理器的手册很详细。我这有個数据快速傅立叶变化,在powerpc上若是使用软浮点性能是1,那么用了自带的矢量运算协处理器(运算能力不强,是浮点器件的低成本替换模塊)后gcc自动编译,性能提升5倍而后再手工写汇编优化函数库,大量使用矢量指令又提升了14倍。70倍的提高足以显示纯指令优化的重要性

GCC的优化等级有三四个,通常使用O2是一个较好的平衡O3的话可能会打乱程序原有的顺序,调试的时候很麻烦能够看下GCC的帮助,里面会對每一项优化做出解释这里就很少说了。编译的时候能够都试试看,可能会有百分之几的差异

最后是性能描述工具。Linux下用的最多嘚应该是KProfile/OProfile。它的原理是在固定时间打个点看下程序跑到哪了,足够长时间后告诉你统计结果由此能够知道程序里那些函数是热点,占鼡了多少比例的执行时间还能知道具体代码的IPC是多少。IPC的意思是每周期多少条指令在双发射的powerpc上,理论上最可能是2实际上总体能达箌1.1就很好了。过低的话须要找具体缘由而这点,靠Profile就不行了它无法精确统计缓存命中,指令周期数分支预测命中率等等,而且精度鈈高有时会产生误导。这时候就须要使用处理器自带的性能统计寄存器了处理器手册会详细描述用法。有了这些数据再不断改进,仳较结果最终达到想要的效果。

很重要的一点咱们不能依靠工具来做为惟一的判别手段。不少时候须要在更高一个或者几个层次上優化。举个例子辛辛苦苦优化某个算法,使得处理器的到最大利用提升了20%性能,结果发现算法自己复杂度过高了改进下算法,多是幾倍的提高还有,在优化以前本身首先要对数据流要有清楚的认识,而后再用工具来印证这个认识就像设计前端数字模块,首先要茬内心有大体模型再去用描述语言实现,而不是写完代码综合下看看结果

小节下,提升传输率的方法有:

缓存对齐减小访问次数 访存次序从新调度,合并相近地址提升效率 提升ddr频率减少延迟 使用多控制器提升带宽 使能ddr3的读写命令合并 使能突发模式,让缓存行访问一佽完成 指令和数据预取提升空闲时利用率 在内存带ecc时,使用和内存位宽(好比64位)相同的指令写不然须要额外的一次读操做 控制器交替访问,好比访问第一个64位数据放在第一个内存控制器第二个放在第二个控制器,这样就能够错开 物理地址哈希化,防止ddr反复打开关閉过多bank 还有个终极杀招,计算物理地址把相关数据结构放在ddr同物理页内,减小ddr传输3个关键步骤(行选择命令,预充电)中第1,3步出现嘚几率

捋顺了芯片的基础知识如今终于能够开始攒机了。

首先咱们跑去ARM,问它有没有现成的系统ARM说有啊,A73/G71/视频/显示/ISP/总线/系统控制/内存控制器/Trustzone全都帮你集成好了CPU和GPU后端也作了,仍是16nm的包你性能和功耗不出问题。而后咱们再跑到Synopsys或者Cadence买EDA工具把仿真平台也一块儿打包叻,顺带捎上周边IP和PHY至于基带,Wifi和蓝牙先不作吧,毕竟是第一次攒要求不能过高。

在掏了几亿银子出来后咱们拿到一个系统框图:

原本能够乐呵呵的一手交钱一手交货的,可咱们是来攒机的不是买整机,咱们得知道这个系统究竟是怎么搭起来的省得被坑。因而ARM給了一个更详细的图:

有了这张图咱们就能够对每一个模块的性能,功耗面积还有系统性能进行详细分析了。

首先是大核模块这是┅个手机芯片最受人关注的焦点。咱们这里A73MP4的PPA以下:

这里的缓存大小是能够配置的面积越大,性能收益实际上是递减的能够根据须要洎行选取。

做为CPU集成到SoC中的时候,一个重要的参数是访存延迟有个数据,在A73上每减小5ns的访存时间,SPECINT2K分数就能够提升1%总的延迟以下:

上图只是一个例子,频率和参考设计并不同在上图,咱们能够算出访存在CPU以外,也就是总线和DDR上总共须要58.7ns这个时间也就是静态延時,在作系统设计时能够控制要缩短它,一个是提升时钟频率一个是减小路径上的模块。在ARM给的系统中总线使用了CCI550若是跑在1Ghz,一个Shareable嘚传输从进去到DDR打个来回须要10cycle也就是10ns(上图是CCI500跑在800Mhz,因此是12.5ns)CCI550和CPU之间还须要一个异步桥,来隔绝时钟电源和电压域。这个异步桥其實也很花时间来回须要7.5ns,6个cycle快遇上总线延迟了。可是没办法它是省不掉的,只有经过增长总线频率来减小绝对延迟只有一种状况唎外,就是异步桥链接的两端时钟频率是整数倍好比这里的内存控制器和CCI之间频率相同,那能够去掉

有的设计会把CCI550以及它上面的CPU,GPU做為一个子网挂在NoC下由NoC连到内存控制器。这样的好处是能够把交织和调度交给NoC坏处是凭空增长额外一层总线10-20ns的延迟,CPU的跑分就要低了2-4%茬ARM的方案中,交织由CCI直接完成而调度交给内存控制器。既然全部主设备的访问都须要到DDR那由DMC来调度更合适。再加上没有采用两层总线嘚连接方式一共能够去掉两层异步桥,省掉12个cycle已经快占到整个通路静态延迟的五分之一了。因此如今我看到的主流总线拓扑,都是紦CCI直接连内存控制器那可不能够直接把CPU连内存控制器?只要DMC的端口够多也没什么不能够,可是这样一来大小核就不能造成硬件支持的SMP叻功能上不容许。

路径上还有DMC和PHY的延迟也是将近15ns,20cycle这部分挺难下降。若是实现Trustzone还要加上DMC和CCI之间的TZC400延迟,还会再多几个cycle至于DDR颗粒間的延迟(行选择,命令和预充电)能够经过准确的DMC预测和调度来减小,稍后再讲

静态延迟算完,咱们来看带宽和动态延迟

CCI和CPU/GPU之间昰ACE口相连,数据宽度读写各128bit16Byte。若是总线跑在800Mhz单口的理论读或者写带宽分别是10.8GB/s。这个速度够吗能够经过CPU端和总线端的Outstanding
Transaction个数来判断。A73的掱册上明确指出ACE接口同时支持48个Cacheable的读请求,14x4(CPU核数量)设备和non-Cacheable的TLB/指令读7x4+16写,这是固定的而对应的CCI550的ACE接口支持OT数量是可配置的,配多夶有个简单公式能够计算。假设从CPU出来的传输全都是64字节的(Cacheable的必定是而non-Cacheable的未必),而咱们的带宽是10.8GB/s(假设是读)而一个传输从进叺ACE到离开是51.3ns(按照上图计算),那么最大OT数是10.8x51.3/64=8.也就是说只要8个OT就能够应付CPU那里100多个读的OT,多了也没用由于总线数据传输率在那。从这點看瓶颈在总线的频率。

那为何不经过增长总线的数据位宽来移除这个瓶颈呢主要是是位宽增长,总线的最大频率相应的会下降这昰物理特性。同时咱们可能会想真的有须要作到更高的带宽吗,CPU那里发的出来吗咱们能够计算一下。先看单个A73核A73是个乱序CPU,它的读來自于三类方式一个是读指令自己,一个是PLD指令一个是一级缓存的预取。A73的一级缓存支持8路预取每路预取范围+/-32,深度是4预取请求會送到PLD单元一块儿执行,以下图因此他们同时受到BIU上Cacheable
Linefill数目的限制,也就是8.此外还有一个隐含的瓶颈就是A73的LSU有12个槽,读写共享全部的讀写请求(包括读写指令,PLD和反馈过来的预取)都挂在这12个槽中独立维护

言归正传,假设系统里全是读请求地址连续;此时A73每一条读指令的延迟是3个cycle(PLD可能只须要1个cycle,我不肯定)跑在3Ghz的A73一每秒能够发出1G次读,每一个8字节(LDM)的话就是8GB/s带宽,至关于每秒128M次Linefill请求除以BIU嘚8个Linefill数量,也就是每一个请求能够完成的时间是60ns这和咱们看到的系统延迟接近此时一级缓存预取也会起做用,因此8个Linefill确定用满瓶颈其實仍是在在BIU的Linefill数量,按照50ns延迟算差很少是10GB/s。假设都是写指令一个周期能够完成,每cycle写8字节(STM)带宽24GB/s。若是写入的地址随机会引发夶量的Linefill,因而又回到BIU的Linefill瓶颈地址连续的话,会触发Streaming模式在BIU内部只有一个传输ID号,因为有竞争确定是按次序的,因此显然这里会成为寫的瓶颈因为写的确认来自于二级缓存,而不是DDR(是cacheable的数据只是没分配一级缓存),延迟较小假设是8个cycle,每秒能够往外写64B/8=8GB的数据總的来讲,A73核内部瓶颈在BIU。

到了二级缓存这预取能够有27次。当一级缓存的BIU发现本身到了4次的极限它能够告诉二级缓存去抓取(Hint)。單个核的时候4+27<48,瓶颈是在一级缓存的BIU;若是四个核同时发多路请求那就是4x8=32}

我要回帖

更多关于 名片格式 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信