本文主要是介绍Hybrid TLB Coalescing:Improving TLB Translation Coverage under Diverse Fragmented Memory Allocations,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Hybrid TLB Coalescing: Improving TLB Translation Coverage under Diverse Fragmented Memory Allocations
-
摘要:
- 背景:
- 在大的存储类应用程序中,会出现很多TLB缺失,因此出现了一些技术(大页,变长段variable length segments,硬件合并TLB表项)用来增加有限硬件资源的TLB的覆盖范围,这些技术主要依赖于连续的内存分配策略
- 问题:在异构存储系统中,使用大页经常导致性能下降或者是更加难以分配大页,并且之前的技术都需要最优的块大小,而现实中,内存的分配并不能够提供这种完美的块大小
- 论文工作:为缓解碎片化和多样化存储分配情况下的TLB缺失,提出了软硬件混合的地址翻译结构,能够高效的适应不同的存储映射
- 论文提出的混合合并策略中,OS在分配连续存储的信息存放在页表项的子集中,这些页表项称为锚表项(anchor entry)
- 在地址翻译的过程中,锚项可以提供在其之后的连续的页的地址翻译。因此少量的锚项可以覆盖很大的虚拟地址空间的翻译,从而改进TLB的覆盖范围
- 混合合并策略最重要的优点在于能够动态的改变锚项的覆盖范围,从而反映出当前分配连续性的状态
- 优点:通过OS直接设置的内存分配的连续性信息,论文在很小的硬件改动下,可以提供可伸缩的TLB地址翻译覆盖范围的改进,同时允许灵活的内存分配
- 背景:
-
介绍:
- 改进TLB地址翻译效率的两类方法:
- 改进覆盖范围,在给定面积和功耗预算的情况下,提升TLB翻译的覆盖范围
- 减少TLB缺失的代价
- 改进TLB覆盖范围的技术
- 增加页的大小(最为常见)。在商业x86处理器中,同时支持4KB,2MB和1GB的页大小
- 变长的HW段翻译替代基于页的地址翻译,依赖于OS能否为每一个段分配连续的大存储区域
- 基于硬件的合并技术(CoLT和cluster TLB),将多个页面的地址翻译合并到一个TLB表项中,只要页面的物理地址在一个连续的区域中,OS不需要保证一定要分配固定大小的页面
- 内存分配的灵活性(allocation flexibility)和地址翻译覆盖范围的伸缩性(scalability of translation coverage)
- 增加页大小:限制了覆盖范围的伸缩性
- 可变硬件段:覆盖范围的伸缩性最好,但是分配策略需要更加的严格,才能够得到好处
- 硬件合并:允许灵活的分配,但是覆盖范围被限定在4或8页面(由于是硬件实现)
- NUMA存储系统中的新问题:
- 在NUMA中连续的内存分配并不总是可能,并且可能会降低性能
- 存储的异构型要求细粒度的存储映射,以保证将频繁使用的页面放在更快更近的地方,因此很难分配大的连续内存块
- 为了适应多样的内存分配场景,论文提出了混合的地址翻译技术(hybrid coalescing),以改进地址翻译的覆盖范围
- 锚项是每N个页表项上指定的一个表项,包含着内存连续分配的信息,即能够指示该表项之后多少个页是分配在连续的物理内存中
- 当L1 TLB缺失,并且在L2 TLB中没有找到时,搜索该虚拟地址对应的最近的锚项,判断当前的虚拟地址是否在锚项的表示范围内
- 如果程序的大部分内存被分配在连续的内存中,则大部分的TLB表项将都是锚项,即地址翻译覆盖的范围也会因此增加
- 在设计过程中,OS可以动态改变锚项在页表中的密度(N的大小),因此该技术可以动态适应内存分支的场景。如果当前内存分配比较连续,此时锚项的密度可以变小,否则可以变得更加密集
- HW-SW合并技术的优势
- 可以动态更改用于翻译合并的块大小,从而动态适应当前内存分配中存在的连续性
- 相对于固定的大页,OS的分配策略仍旧很灵活
- 地址翻译覆盖范围的伸缩性很好
- 对TLB和页表的修改非常小
- 改进TLB地址翻译效率的两类方法:
-
论文动机
-
改进翻译的覆盖范围
- 多种页大小。X86中支持4KB,2MB,1GB的页面,程序可以明确的指明使用大页或者使用THP(透明大页)支持,从而使得OS分配2MB的页面。在最新的处理器中,L2 TLB中可以同时支持4KB和2MB页大小,但是需要一个额外的1GB页面的L2 TLB。缺点:覆盖范围固定,OS必须能够分配这些大页
- 变长的段机制。RMM(Redundant Memory Mapping,冗余的存储映射)支持一个或者多个可变长度的段区域,操作系统必须为每个段区域分配连续的内存块。利用这种方式可以将翻译覆盖的范围扩展的很大。缺点:段翻译表项很小(全相联查找),分配连续内存块更严格
- 硬件的合并技术。CoLT和clusterTLB,利用硬件的TLB控制器搜索页表项(一个cache line中的页表项),找到连续分配的页。缺点:由于硬件的控制器可以利用的连续性是受限的,因此只支持4到8个页的合并。CoLT增加了全相联的查找模式,可以增大并行的页数量,但是也限制了TLB的表项数
-
存储中非一致性的增加
- 存储中非一致性的增加会导致大页的使用更加困难
- NUMA中,线程调度经常会使得之后的线程要访问的数据区域和当前线程不一致。之前研究显示,在多线程应用中,使用2MB的大页经常会降低性能。并且在实际系统中,当存储是非一致性时,分配中等大小的2MB页面也非常的困难
- stacked memory(栈内存)的大小足够成为主存的一部分,因此物理地址空间将存在fast-near和far-slow的内存区域,在这种情况下需要更加细粒度的页面映射,从而才能够利用这种潜在的优势。但是这种情况也会造成大页的分配会造成额外的浪费(并不是页内所有的数据都会经常访问)
-
内存分配多样性的影响:
-
在两种不同的x86机器上(分别是2和4套接字的NUMA机器),系统为Linux 3.16.0和3.19.0,运行PARSEC测试程序,记录内存分配的连续性。运行过程中,包括两种场景:单独运行选择的基准程序;后台运行parsec中其它的程序
-
实验1:测试了程序在单独运行和多种后台程序运行情况下,内存分配的连续性的分布。虚线代表着程序单独运行,其它代表着随机个数的后台程序在运行情况下的程序运行。结论:初始状态和多个进程的产生的存储请求的个数会使得程序内存分配的连续性发生变化
-
结论:程序的内存映射的可变性要求需要设计一种能够在不同的映射情况下都能够表项好的翻译策略
-
-
-
Anchored Page Table(带有锚项的页表)
-
相对于使用硬件识别连续页的方式,论文提出由操作系统直接将内存分配时的连续性信息记录在页表项中。
-
为了记录连续块信息,每N个页表项设计一个anchor表项(锚项),即锚项是以N对齐,两个连续的锚项之间间隔N个页表项。
-
每个锚项中记录了从该锚项开始多少个页面是连续分配的(使用表项中未被使用的位域)
-
锚项中的连续性由OS维护,当页面第一次分配,重新分配或者回收时,OS需要更新锚项中的连续性信息
-
-
真实的内存分配通常由不同的块大小组成,主要的决定因素有程序的内存分配行为,OS的分配策略,系统内存的配置以及当前的碎片情况,因此锚项之间的距离N必须严格的设置。论文提出了一种OS算法用于寻找最佳的N。同时锚项间距N是进程的一部分信息,因此必须随着进程的换入换出动态的发生变化
-
对于页表中的锚表项,会利用页表项中尚未使用到的位域保存连续性信息,对于TLB,则需要为每一个表项增加一些位域保存连续性信息
-
锚项最大可表示的连续性的范围:
- 页表项总是8个一组的形式存储,因为cache block大小为64B,如果锚项间距为8,此时只需要将缓存块中第一个页表项中的3位作为记录连续性的位域即可
- 如果需要表示更大的锚项间距,此时每个页表项中仍旧有8位(总计11位)可以使用,此时最多可以表示2048。这种情况下,仍旧只需要读取缓存块中的第一个页表项即可
- 如果需要再大的锚项间距,则可以使用锚项所在的缓存块中的其它页表项中的未被使用的位域,即最大为2^(11*8)
-
-
带有锚项的页表翻译过程
-
MMU需要修改,TLB只需要增加一定的位域即可,正常页表项和锚项共用一个TLB。L1 TLB的访问延迟需要很小,因此在L2 TLB中支持锚项
-
地址翻译过程
- L1 TLB命中,则结束
- L1 TLB缺失,寻找L2 TLB,如果命中,结束
- L2 TLB缺失,根据锚间距,确定地址对应的锚表项的VPN,查找该表项,如果命中,进一步查看是否在该锚项的覆盖范围内,如果在,则命中,结束;否则进行页表查找
-
TLB的更新:
- 如果L2 TLB命中或者是锚项命中,并且连续性匹配,则需不需要更新
- 如果锚项命中,但是不在锚项的表示范围内,则查找页表,找到对应表项,更新TLB
- 如果锚项未命中(不在TLB中),但是发现页表中的锚项可以覆盖该地址,则查找页表,找到对应的页表项和相应的锚项,并且只是用锚项更新TLB
- 如果锚项未命中,并且该锚项不可覆盖该地址,则只使用该地址对应的页表项更新TLB
-
如何查找锚项
- 锚页表项的VPN使用AVPN表项,并且对齐于锚项间距,例如间距为4,则AVPN为0,4,8…
- 根据地址翻译请求的VPN和锚项间距,得到该地址所在的锚项的AVPN(低d位清零,d=log2(锚间距))
-
TLB中如何存储更有效的锚表项(尽可能的分散,而不是都存放在0set)
-
对于锚表项的AVPN,低d位,即[12:d+12)位为零,为了避免正常TLB替换策略中,将这些锚项都存放在第0组,此时使用[d+12:d+12+N)作为组索引,N为索引所有TLB set需要的位数。通过这种方式可以将锚表项充分的使用TLB中所有的set
-
在查找时,使用同样的策略,例如[d+12:d+12+N)找到对应的组索引,比较tag和低d位,以判断是否命中锚表项,并且处在覆盖范围内,如果命中并且匹配,则最终的物理页号为APPN+(VPN-AVPN)
-
-
-
操作系统的影响
- 更新内存映射:
- 当OS更新一个进程的内存映射时,包括进程创建时的内存分配,页面变化时的页表更新等,如果锚项中的连续性信息会受到影响,此时也必须更新
- 在更新页表项和锚表项之后,会调用常规的TLB关闭操作,将所有核的TLB中的表项设置为无效
- 锚项间距的变化:根据内存分配的状态,决定每个进程最佳的锚项间距(不频繁)
- 更新页表:在更新过程中,更改所有的新的锚项,当间距变大时,只需要更新更少的锚项;反之,则需要更多的锚项要被更新。实验测量的更新成本(进程使用了30GB的内存):从4更新到8,64,512需要的时间分别为452ms,71.7ms,1.7ms。
- 如果在程序执行过程中,内存映射的情况频繁的发生变化,会产生不同的最优的锚项间距,此时OS会根据切换的开销和带来的好处进行权衡,判断是否切换
- 同步TLB:在更新整个页表之后,无效整个TLB。论文在实验中选择间隔1billion指令,检查是否需要更新锚项间距,并且论文发现,更新的操作很少
- 页的权限管理和页共享
- 尽管页的分配可能是连续的地址喵,但是页之间仍旧可能有不同的权限喵,因此需要论文提出如果页的物理地址连续喵,但是权限不同喵,此时仍旧认为是不连续的页喵。之前是论文提出这种情况下比较少
- 对于进程之间共享的页面,每个进程都会在自己的页表中设置连续性喵,尽管可能设置的锚项间距不同
- 更新内存映射:
-
动态的锚项间距
- 动态改变间距的原因:
- 进程本身可能会动态的分配和回收内存,从而导致内存映射发生变化
- OS可能会重新组织内存映射以优化性能(linux会尝试压缩内存,以产生更大的页面)
- 选择算法概括
- 根本目标:最小化进程使用的TLB表项数目
- 为了评估内存分配的连续性状态,OS需要维护一个连续性分布直方图。利用直方图和启发式近似估计TLB中存储页面映射的成本,从而选择出能够使得成本最低的锚项间距
- 为了统计精确的直方图信息,必须频繁的访问页表,意味着很大的开销,因此在选择锚项间距的算法只是用基于静态内存映射信息总结得到的直方图
- 启发式选择
- 连续性直方图:连续性和频率。前者代表着块的大小,后者代表着这种大小块被分配的次数
- 算法思路:根据直方图,估计在每一种锚项间距的情况下,覆盖所有进程所占用的内存需要多少TLB表项,以此作为代价cost
- 算法描述:TLB需要的表项数被分为三种类型:4KB页表项,2MB大页和锚区域。例如当锚项间距为16时,每个锚项可以覆盖64KB大小。对于每一个块大小,首先计算锚项可以覆盖的块大小和锚项个数,然后剩余的部分在依次计算2MB和4KB页所需要的TLB表项个数(锚项可能覆盖范围超过2MB)。最终将所有的部分组合在一起,作为当前锚项间距的cost
- 算法得到的间距的稳定性:
- 选择算法间隔一段周期之后进行选择,从而适应比较大的存储映射分布变化
- 论文通过实验发现,尽管每次都在选择最优的间距,但是基本不发生变化(在进程已经分配了大量的内存页之后)
// contiguity_histogram is a list of (contiguity, frequency) pairs// List of available anchor distances in the system Distances ← [2, 4, 8, ... 216]// Costs for different anchor distances ∀d ∈ Distances costd ← 0for each d in Distances do// Calculate distance cost for each contiguity of histogramfor each (cont,freq) in contiguity_histogram doanchors ← cont/ anch_dist × freqlarge_pgs ← remainder / 512 × freqpages ← remainder × freq// Weigh down costs of entries with larger coveragecostd + = anchors /anch_distcostd + = large_pgs/512costd + = pagesend forend for// Pick anchor distance with min costmin_dist ← min∀d∈Distances(costd)setProcAnchorDistance(min_dist) // Set distance of the process
- 动态改变间距的原因:
-
未来工作
- 目前采用的锚项间距只有一个,但是在进程地址空间中,不同的语义区域(代码段,数据段,共享库,堆栈等)可能有着不同的连续性,并且在同一个语义区域内也有可能有不同的连续性
- 论文引入区域的概念,region区域代表着部分的虚拟地址空间,拥有私有的锚项间距。
- 为了支持多区域的锚项TLB,需要增加额外的硬件保存每个区域的(starting VPN,ending VPN,anchor distance)
- 在搜索过程中,region表也需要和TLB并行查找,并且要求所有的区域都需要并行的查找,以确定地址所在区域对应的锚项间距
这篇关于Hybrid TLB Coalescing:Improving TLB Translation Coverage under Diverse Fragmented Memory Allocations的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!