对Memory Fabric的观察
近期比较热门的Gen-Z是一种语义存储(memory-semantic)体系架构,它本身的主要技术优势:
一是能够将DRAM和非易失性存储器及未来的持久性存储技术结合起来;
二是它还使用一种高带宽、低延迟和高效的协议来简化软硬件设计,降低了解决方案的成本和复杂性。
Gen-Z它已经发展到了一定程度,需要更好地定义来适应更大规模的规范与标准,例如在数据中心越来越受欢迎的成熟NVM Express和新兴Compute Express Link(CXL)协议。
前段时间,我们在项目中考虑Memory Fabric某场景时,尝试了内存管理单元MMU的修改,几经周折,我们也成功在Normal空间禁止了cacheable属性。但是,一提到MMU配置我们就谈虎色变,想起曾经的MMU相关死机案例,那都是寻寻觅觅仍然找不到原因的悲伤故事。
于是,我们就跑题了,把Memory Fabric和禁止cacheable属性都放一边,先梳理一下ARM处理器MMU配置相关的问题,也聊一下与MMU配置相关性比较强的CPU特性--推测执行(Speculative execution)。由于MMU和Speculative execution都是生僻词,系统工程师和底层软件工程师可能了解多一些,应用软件工程师就很少接触了,本文也主要谈一下MMU和推测执行的关系和约束,不对技术细节展开描述。
MMU,内存管理单元,顾名思义就是用于管理内存的部件,这是CPU内部模块名,需要操作系统来进行空间配置和管理,所以,有时提到的MMU并不完全指硬件部分,也包括软件部分。其作用就是完成VA虚拟地址到PA物理地址的转换,页面大小管理,同时配置地址空间的访问属性,包括Normal(乱序访问)和Device(定序访问)进行区分,cache写回,cache写透,关闭cache等等,配置地址空间的访问权限,如只读,只写,可读可写,XN(不可执行)等等。图示如下:
推测执行,或者叫投机执行,或者叫预测执行,也理解为乱序执行,只是传统意义的乱序执行更多是指令在执行阶段的并行执行,而推测执行更多的是指令在提取和分发阶段的投机行为。考虑分支预测,如果分支判断的条件都还没有计算出来,那么CPU提取哪个分支的指令呢?从流水线上看,推测执行就是允许CPU的Fetch部件根据历史和其它条件预取择”正确”分支的指令,并译码分发和执行其中“无害”的指令。
一、简介Introduction
伴随着处理器引入具备分支预测和推测执行功能的复杂流水线,正确地对MMU编程变得尤为重要,否则将出现非本意的内存访问,严重时将导致处理器挂起或者系统异常。本指南规定了安全编程MMU以避免此类问题的最低要求,假定读者已经理解了MMU运行的基本原理,如果不了解,需要先看相关编程手册补充MMU知识。
二、推测执行Speculative execution
Cortex-A 系列处理器推测执行指令可以提升性能,通常基于分支预测的结果,如果预测正确,将收到较好的性能收益,如果预测失败,所有推测执行的结果将抛弃,流水线将被清空。推测执行可能导致程序访问非本意的内存区域,无论是用于数据读、指令预取还是地址转换表的遍历。MMU必须正确设置才能防止推测执行对系统产生意外的副作用。
现代处理器的分支预测准确率已经相当的高了,高达95%以上,所以预测错误引入的流水线惩罚也越来越忽略不计,预测失败对性能的影响微乎其微,总体上看是利大于弊的。但是,因为推测执行导致的程序异常和系统影响却不可不关注,通过MMU管理可以避免,就像CPU的乱序执行,需要程序员关注一样,手段是添加DMB等指令来阻止对程序有影响的乱序执行,CPU的推测执行也需要程序员关注,只是,这个程序员是更偏向于系统软件的,需要考虑MMU编程来管理。
如果说乱序执行和推测执行为什么分开描述,因为手册就是这样描述的,所以就只好这样去理解。但是,推测执行更加隐秘,不是软件流程写错了,而是CPU没有按照你熟知的套路出牌,
都是底层的指令级并行技术,软件层面是看不到的,这些并行技术本意是不影响软件意图的,无奈,系统复杂,一旦指令并行影响了应用软件,应用软件程序员抓破头皮也无济于事。
三、推测执行与指令预取规则(Speculative execution and instruction prefetching rules)
1、除非指令改变系统状态,否则允许推测执行指令。
2、不与内存交互的指令可以推测执行 。(直到内部推测寄存器资源耗尽)
3、针对Nornal属性的读内存操作可以推测执行。(写操作不可以推测执行,针对Device属性和strongly ordered属性的内存不可以推测执行)
4、指令预取将基于预测的程序流进行,包括从分支预测失败后的恢复,指令预取不涉及XN位被置位的地址。
5、推测读操作和指令预取(如果需要)将启动地址转换表walks动作。(发生在地址跨页的时候)
推测执行的影响细化了,并不是我们理解的推测执行什么事情都可以干,对内存无损坏的事情(读访问)可以提前干,对硬件寄存器的读访问不能顺便干。
四、MMU编程规则MMU programming rules
1、所有的转换表条目都必须被编程,不管是使用的Level 1,2和3,以及未使用的虚拟地址转换条目也必须用能报错的编码进行编程,访问敏感的区域必须编程为Device属性和Strongly Ordered Memory属性。
2、包含访问敏感属性的内存区域必须设置XN位。
3、TTBR中设置的cache属性必须与转换表地址范围中编程的cache属性相匹配。
这三点规则细化了MMU编程的注意事项,内存属性要设置正确,cache属性要设置正确,必要时要设置XN位(execute never)。