多核CPU的TLB竞争:如何降低跨核刷新开销
页表缓存(Page Table Cache)是Linux内核中的一项关键机制,用于提高虚拟地址到物理地址转换的性能。它在操作系统内部维护了一个缓存,用来存储最近访问过的页表项。
当程序访问虚拟地址时,需要将其转换为物理地址才能进行实际的读写操作。这个转换过程涉及到查找对应的页表项,并且可能会导致缺页异常等开销较大的操作。为了减少这种开销,Linux内核引入了页表缓存。当某个虚拟页面第一次被访问时,相应的页表项会被加载到页表缓存中。如果之后再次访问同样的虚拟页面,就可以直接从页表缓存中获取对应的页表项,避免了频繁地查找和加载。
通过使用页表缓存,Linux内核能够显著提升虚拟地址到物理地址转换的速度,从而加快系统的响应和执行效率。不过需要注意,在多处理器或多核系统上,由于存在并发访问和一致性问题,对于共享数据结构如页表缓存的设计与管理需要特别小心。
一、页表缓存简介
1.1虚拟与物理的桥梁
在计算机的世界里,内存是数据和程序运行的舞台。其中,有两个关键概念:虚拟内存与物理内存。物理内存,就像是计算机实实在在拥有的 “舞台场地”,由内存条提供,程序运行时的指令和数据会临时存储在这个物理空间中 ,它的容量受限于硬件配置,像我们常见的 8GB、16GB 、32GB 内存规格,便是物理内存的大小体现。而虚拟内存,则像是一个 “虚拟的大舞台”,操作系统通过将硬盘的一部分空间模拟成内存来实现。当物理内存不够用时,它就会把暂时不用的数据从物理内存转移到硬盘上的虚拟内存区域,等需要的时候再取回来。这种机制使得程序可以使用比实际物理内存更大的内存空间,就好像给计算机 “借” 了更多的场地来表演。
不过,虚拟内存和物理内存之间存在着一个关键问题:地址转换。程序使用的是虚拟地址,而实际的数据存储在物理内存中,这就需要一种机制将虚拟地址转换为物理地址,才能准确地访问到数据。页表,就是实现这个转换的关键数据结构,它记录了虚拟地址和物理地址之间的映射关系。但页表通常存放在内存中,每次地址转换都要访问内存中的页表,而内存访问速度相对较慢,这就像每次找东西都要去一个比较远的仓库(内存)查清单(页表),效率不高。
这时,页表缓存(Translation Lookaside Buffer,TLB)就登场了,它就像是一个放在身边的 “快速清单”。TLB 是一种高速缓存,位于 CPU 的内存管理单元(MMU)中,专门用于存储虚拟地址到物理地址的映射关系 。当 CPU 需要访问一个虚拟地址时,会首先在 TLB 中查找对应的物理地址,如果找到了,就可以直接访问物理地址对应的内存,这就大大加快了地址转换的速度,如同直接在身边的快速清单里找到了要找东西的位置,无需再跑去远处的仓库查清单,极大地提高了内存访问的效率。页表缓存虽小,却在虚拟内存与物理内存之间搭建起了一座高速桥梁,是计算机高效运行不可或缺的关键角色。
1.2虚拟地址到物理地址的映射过程
虚拟地址到物理地址的映射过程是通过页表完成的。在使用虚拟内存时,操作系统将物理内存划分成固定大小的页面(通常为4KB),并将每个进程的虚拟地址空间划分成相同大小的页面。
当程序访问虚拟地址时,CPU会将该虚拟地址发送给内存管理单元(MMU),其中包含一个页表基址寄存器(Page Table Base Register, PTBR)指向当前进程的页表。
映射过程如下:
CPU将虚拟地址发送给MMU。MMU根据虚拟地址中的页号找到对应的页表项。如果页表项中标记为有效,则获取对应的物理页框号。将物理页框号与虚拟地址中的偏移量组合,得到最终的物理地址。将最终物理地址返回给CPU,程序可以访问该物理地址上存储的数据。如果在步骤3中发现页表项无效,则表示所请求的页面不在物理内存中。这时可能触发缺页异常,操作系统需要从磁盘上加载对应页面,并更新页表项以建立新的映射关系。
(1)虚拟地址到物理地址转换机制
①当应用程序需要访问内存时,会生成一个虚拟地址。这个虚拟地址由两个部分组成:页号和偏移量。
②操作系统将虚拟地址中的页号与页面表进行匹配,找到对应的Page Table Entry(PTE)。
③如果PTE中记录了该页面在物理内存中的位置,则操作系统将物理内存地址和偏移量组合成一个物理地址,并返回给应用程序。如果PTE中未记录该页面在物理内存中的位置,则产生一个缺页异常。
④在发生缺页异常时,操作系统会尝试从磁盘或其他存储设备上加载相应页面,并更新PTE以反映新页面所处的位置。
⑤一旦新页面加载到物理内存中,操作系统就可以使用步骤3中描述的方式来计算出该页面在物理内存中的位置,并返回给应用程序。
这样,在之后访问同一段虚拟地址时,就不需要再次发生缺页异常,而是直接查找PTE并返回对应的物理地址。
(2)线性地址和虚拟地址之间的关系
线性地址是CPU产生的地址,它是由段选择符和偏移量组成。在进行内存访问时,CPU会将线性地址转换为物理地址,并将数据从物理内存中读取或写入。因此,线性地址是在CPU内部使用的,不直接对应物理内存中的位置。而虚拟地址则是应用程序使用的地址,它也由两部分组成:页号和偏移量。虚拟地址对应了应用程序所需访问的具体数据块在逻辑上的位置。操作系统会负责将虚拟地址转换为物理地址,并实现内存访问。
在这个过程中,操作系统采用了一些技术来实现虚拟地址到物理地址的转换。例如,在32位x86架构中常用的方法是利用分页机制(paging),将整个逻辑空间划分为大小相等、连续编号的页面(page)。每个页面包含若干个字节,并且与一个PTE相对应。PTE记录了该页面是否已经加载到物理内存中以及其在物理内存中的位置等信息。
当应用程序需要访问某个虚拟地址时,操作系统首先根据虚拟地址的页号查找PTE,如果该页面已经在物理内存中,则可以通过PTE计算出对应的物理地址,并将数据从物理内存中读取或写入。否则,就会发生缺页异常,并且操作系统需要将相应页面从磁盘或其他存储设备上加载到物理内存中。
因此,线性地址和虚拟地址之间存在一定的关系。在32位x86架构中,线性地址是由段选择符和偏移量组成的,而偏移量部分直接对应了虚拟地址的偏移量部分。同时,在进行内存访问时,CPU会自动执行线性地址到物理地址的转换,并且可以利用硬件支持来提高访问速度。
二、页表缓存是什么
页表缓存,全称是 Translation Lookaside Buffer,简称 TLB ,也常被叫做快表,从专业角度来讲,它是一种用于提高虚拟地址到物理地址转换速度的硬件缓存机制。
在计算机系统中,CPU 运行程序时产生的是虚拟地址,而数据实际存储在物理内存中,这中间就需要页表来完成虚拟地址到物理地址的映射。然而,页表存放在内存里,每次查询页表都要访问内存,内存访问速度相对较慢,这就好比每次找东西都要去较远的仓库翻清单,效率不高。
TLB 就如同在身边设置的一个快速清单。它集成在 CPU 的内存管理单元(MMU)中,是一种高速缓存,专门用来存放近期使用过的虚拟地址与物理地址的映射关系 。当 CPU 要访问一个虚拟地址时,会先到 TLB 里查找对应的物理地址。要是找到了(这就是命中),就能直接用找到的物理地址去访问内存,极大地加快了地址转换速度;要是没找到(即未命中),CPU 就会去内存中的页表查询物理地址,然后把新的映射关系存入 TLB,方便下次快速查找 。可以说,TLB 虽然容量不大,却在虚拟内存和物理内存之间搭建起了一座高速桥梁,大大提升了内存访问效率,是计算机系统高效运行的关键一环。
三、页表缓存的工作原理
3.1地址查询
当处理器需要访问内存时,会如同在图书馆查找一本急需的书籍一般,首先在页表缓存这个 “快速索引区” 查找所需的虚拟地址到物理地址的映射。假设我们正在运行一个办公软件,当软件中的程序指令需要读取存储在内存中的用户文档数据时,CPU会产生一个虚拟地址。
这个虚拟地址就像是一个带有编号的 “虚拟书架位置”,CPU拿着这个编号先来到页表缓存这个“快速清单”前查找。如果在页表缓存中找到了匹配的条目,也就是命中了,就好比在快速索引区找到了这本书的实际书架位置,CPU可以直接获取对应的物理地址,从而避免了访问内存中完整的页表,大大提高了地址转换速度,快速读取到所需的数据,让办公软件能流畅地将文档内容展示在用户面前 。
3.2缓存更新
要是在页表缓存中未找到所需的映射,即未命中,情况就像在快速索引区没找到那本书的位置,处理器就不得不去内存中的页表这个 “完整藏书目录” 查询物理地址。当完成查询,得到新的物理地址后,处理器会如同将新书的位置信息补充到快速索引区一样,将新的映射关系添加到页表缓存中,以便后续再次访问相同虚拟地址时能够更快地找到对应的物理地址 。
为了保证页表缓存始终能高效工作,在添加新映射时,如果缓存已满,就需要按照一定的替换策略,将那些不常用的条目替换出去,比如采用最近最少使用(LRU)策略,把长时间未被访问的映射条目替换掉,让页表缓存时刻保持 “新鲜”,随时为快速地址转换服务,确保计算机系统的高效运行 。
3.3页表缓存的特点剖析
(1)高速缓存
页表缓存堪称计算机硬件世界里的 “短跑冠军”,它通常由高速硬件打造而成,要么是专用的高速缓存芯片,如同为其量身定制的高性能装备;要么直接集成在处理器内部,与处理器紧密协作,就像亲密无间的伙伴,能在极短时间内完成地址查询,访问延迟低至几个时钟周期 。
与之形成鲜明对比的是内存访问,内存访问速度相对较慢,每次查询内存中的页表,都如同在一条漫长的道路上行走,需要经过内存总线等硬件设备,可能要耗费多个时钟周期才能完成一次访问。在计算机运行过程中,若每次地址转换都依赖内存访问页表,系统性能将会大幅下降,就像一个人背着沉重的包袱跑步,速度会大受影响。而页表缓存的高速特性,使得 CPU 在进行地址转换时,能快速获取所需的物理地址,极大地提升了系统性能,让计算机的运行更加流畅高效,如同为计算机插上了高速飞行的翅膀 。
(2)小容量
由于成本和芯片面积等因素的限制,页表缓存的容量相对较小,通常只能存储几百到几千个映射条目,就像一个空间有限的小型仓库 。在实际应用中,计算机系统运行的程序众多,进程的虚拟地址空间庞大,页表中记录的虚拟地址到物理地址的映射关系数量巨大,相比之下,页表缓存的容量就显得捉襟见肘。
当处理器访问的虚拟地址在页表缓存中未命中时,就不得不去内存中查询页表,这不仅增加了地址转换的时间,还可能导致系统性能的波动。为了应对这一挑战,计算机系统采用了多种策略,比如优化页面置换算法,像最近最少使用(LRU)算法,优先替换长时间未被访问的映射条目,确保缓存中始终保留最有可能被再次访问的映射关系;还有预取技术,操作系统根据程序的执行路径和内存访问模式,提前将可能需要的页表项预取到页表缓存中,提高缓存命中率,以充分发挥页表缓存的作用 。
(3)关联性
页表缓存一般采用组相联或全相联的映射方式,来提高缓存的命中率,就像精心规划的分类存放系统 。以组相联映射为例,页表缓存被巧妙地分为多个组,每个组内又包含多个缓存行,宛如一个大型图书馆被划分成多个书架区域,每个书架区域里又有多层书架。
当处理器拿着虚拟地址来查询物理地址时,虚拟地址会根据其索引字段映射到特定的组,这就如同根据书籍的分类编号快速找到对应的书架区域。然后在组内进行查找,就像在特定书架区域的多层书架中寻找具体的书籍。这种映射方式,相比直接映射缓存,能在同一组内存储多个页表项,降低了因地址冲突导致的缓存未命中情况。比如,当不同的虚拟地址映射到相同的缓存位置(即地址冲突)时,如果是直接映射缓存,就只能保留一个映射关系,其他的会被覆盖,导致后续访问可能未命中;而组相联映射方式,由于同一组内可以存放多个映射关系,就大大减少了这种冲突,提高了缓存命中率,使得页表缓存能更高效地为地址转换服务 。
四、Linux内核页表结构
在Linux内核中,页表是用来管理虚拟内存和物理内存之间映射关系的数据结构。Linux采用了两级页表(two-level page table)的结构,具体包括以下几个部分:
一级页表(Level 1 Page Table):也称为顶层页表(Top-Level Page Table),它是整个页表层次结构的入口点。一级页表的条目数与物理内存大小相关,每个条目指向二级页表。二级页表(Level 2 Page Table):也称为中间层页表(Intermediate Page Table)。二级页表将虚拟地址空间划分成更小的区域,并对应到三级页表。三级页表(Level 3 Page Table):也称为底层页表(Leaf Page Table)。三级页表对应着最细粒度的页面大小,通常是4KB或2MB。每个条目包含了虚拟地址和物理地址之间的映射关系。通过多级页表结构,Linux 内核能够有效地管理大型虚拟地址空间和物理内存。当进程访问一个虚拟地址时,内核会根据虚拟地址在不同层次的页表中进行查找和转换,最终得到对应的物理地址。
需要注意的是,在64位版本的 Linux 内核中,由于更广阔的虚拟地址空间和更大容量的物理内存支持,可能会有更多级的页表结构。具体的层次结构和细节可能因不同的架构、配置和内核版本而有所变化,上述描述仅为一般情况下的常见页表结构。
4.1页表项
页表项(Page Table Entry)是页表中的每个条目,用于描述虚拟地址与物理地址之间的映射关系。每个页表项通常包含以下字段:
物理页面基址(Physical Page Base Address):指向对应的物理内存页面的起始地址。标志位(Flags):用于控制页面的访问权限、缓存策略和其他特性。常见的标志位包括可读/写/执行权限、缓存禁用、全局标志等。状态位(Status Bits):记录页面的状态信息,如脏页标记、引用位等。其他辅助字段:可能包含一些额外信息,如页表层次索引、保留位等。根据操作系统和硬件架构的不同,页表项可能有不同的结构和长度。例如,在x86体系结构上,一个典型的32位页表项长度为4字节(32 bits),而在64位上则是8字节(64 bits)。这些长度限制了能够表示的物理内存大小和虚拟地址空间范围。
通过逐级查找和解析页表项,操作系统可以将虚拟地址转换为物理地址,并进行访问控制和管理。因此,正确配置和使用页表项对于有效管理内存和实现安全性至关重要。
4.2各种类型的页面
Page Table Entry (PTE):记录了一个页面在物理内存中的地址以及相关信息,用于虚拟地址到物理地址的映射。Page Global Directory (PGD):一种高级页表结构,用于管理大量虚拟内存。它将多个Page Table组织起来,形成更大的虚拟地址空间。Page Middle Directory (PMD):类似于PGD,但粒度更小。通常用于管理特定区域内的虚拟内存。Inverted Page Table (IPT):与传统页表不同,IPT根据物理地址索引每个页面对应的虚拟地址和进程信息。它可以减少页表占用的内存,并提高查找效率。Translation Lookaside Buffer (TLB):高速缓存,位于CPU芯片上,加速虚拟地址到物理地址转换过程。4.3页表缓存与页表的关系解读
页表缓存与页表,虽然都服务于虚拟地址到物理地址的转换,但它们在计算机系统中扮演着截然不同的角色 。
从定义上看,页表是一种数据结构,就像一本详细的 “地址映射大全”,它完整记录了虚拟地址空间中的页与物理内存中的页框之间的映射关系,是虚拟内存管理的核心所在,为操作系统实现虚拟内存到物理内存的转换提供了最基础的依据 。而页表缓存,即快表(TLB),则像是从这本 “地址映射大全” 中精选出来的 “常用地址速查表”,是一种高速缓存机制,专门用于缓存页表中最近使用的映射关系,是对页表部分内容进行快速存储和访问的硬件结构 。
在作用方面,页表承担着实现虚拟地址到物理地址完整映射的重任,操作系统依靠它来管理进程的虚拟地址空间,进行内存分配、回收以及地址转换等一系列关键操作,确保每个进程都能在自己独立的虚拟地址空间中准确无误地访问内存,实现内存的有效隔离和保护 。页表缓存的主要作用则是加速这一地址转换过程,通过缓存最近使用的页表项,减少访问内存中页表的次数,就像为地址转换开辟了一条高速通道,从而显著提高地址转换速度,提升整个系统的运行性能 。
存储位置与访问速度上,二者也有很大差异。页表通常存储在主内存中,由于内存访问需要经过内存总线等硬件设备,就像要穿过一条漫长的通道才能到达,每次访问可能需要多个时钟周期才能完成,速度相对较慢 。页表缓存一般集成在处理器内部,或者靠近处理器的高速缓存芯片中,离处理器非常近,能在几个时钟周期内快速完成地址查询,极大地缩短了地址转换时间,就像在处理器身边随时待命,快速响应地址转换请求 。
从数据结构与容量来看,页表是一个完整且通常较为庞大的数据结构,包含了进程虚拟地址空间中所有页与物理内存页框的映射关系,其大小取决于虚拟地址空间的大小和页的大小等因素,可能会占用大量的内存空间 。页表缓存的数据结构相对简单,主要包含虚拟页号、物理页框号等关键信息,以及一些用于管理和查找的标志位等,其容量相对较小,通常只能存储几百到几千个映射条目 。
在数据更新与维护方面,页表由操作系统在进行内存管理操作,如进程创建、内存分配、页面置换等时进行更新和维护,以确保虚拟地址到物理地址映射的正确性和完整性 。页表缓存一方面会在操作系统更新页表时,根据更新策略相应地更新缓存中的条目;另一方面,在发生地址转换时,如果在页表缓存中未命中,会从页表中加载新的映射关系到页表缓存中,并根据替换策略替换掉不常用的条目 。页表缓存就像是页表的 “高速助手”,虽然依赖于页表,但通过自身的特性,大大提升了地址转换的效率,与页表共同协作,保障计算机系统的高效运行 。
4.4页表缓存的重要性与应用场景
在计算机系统中,页表缓存(TLB)就像一个隐藏在幕后却掌控全局的关键角色,其重要性不言而喻,在提升内存访问效率和系统整体性能方面发挥着不可替代的作用 。
从内存访问效率来看,页表缓存是加速地址转换的 “加速器”。在没有页表缓存的情况下,每次内存访问都需要查询内存中的页表,由于内存访问速度相对较慢,这会大大增加地址转换的时间。而页表缓存的存在,使得 CPU 能够在极短时间内完成地址转换,快速获取所需数据,减少了处理器等待数据的时间,让计算机能够高效运行。例如,在程序运行过程中,频繁地访问内存中的指令和数据,如果每次都要经过漫长的页表查询过程,程序的执行速度将大幅下降,而页表缓存的高速特性则有效避免了这种情况,确保程序能够流畅运行 。
从系统整体性能角度而言,页表缓存对提升系统性能有着至关重要的影响。它能够显著提高 CPU 的利用率,因为减少了内存访问的延迟,CPU 可以更快地执行指令,从而提高整个系统的吞吐量。在多任务处理环境下,页表缓存使得不同进程之间的切换更加高效,每个进程都能快速访问自己的内存空间,减少了进程上下文切换带来的开销,提高了系统的并发处理能力,让计算机能够同时处理多个复杂任务而不卡顿 。
页表缓存的身影广泛出现在各类计算机应用场景中 。在操作系统运行时,页表缓存为操作系统的高效运行提供了有力支持。操作系统需要频繁地访问内存中的各种数据结构和程序代码,页表缓存能够快速完成地址转换,使得操作系统能够及时响应各种系统调用和中断请求,保证系统的稳定性和流畅性 。比如在 Windows 系统中,当用户打开多个应用程序时,操作系统通过页表缓存快速管理各个应用程序的内存访问,确保系统的高效运行 。
在大型软件运行时,页表缓存同样发挥着关键作用。像3D游戏、视频编辑软件等大型软件,它们通常需要处理大量的数据和复杂的图形渲染任务,对内存访问的速度要求极高。页表缓存能够快速将虚拟地址转换为物理地址,让软件能够快速读取和处理所需的数据,保证软件的流畅运行,为用户提供更好的使用体验 。以热门的 3D 游戏为例,游戏中的场景渲染、角色动作等都需要大量的数据支持,页表缓存能够快速响应游戏对内存的访问请求,使得游戏画面更加流畅,避免出现卡顿现象 。
在服务器环境中,页表缓存更是不可或缺。服务器需要同时处理大量的客户端请求,对系统性能和稳定性要求极高。页表缓存能够提高服务器对内存的访问效率,加快数据的处理速度,从而提高服务器的并发处理能力,确保服务器能够稳定地为大量用户提供服务 。例如,在电商网站的服务器中,在购物高峰期,大量用户同时访问网站进行商品浏览、下单等操作,页表缓存能够帮助服务器快速处理这些请求,保证网站的正常运行 。
五、页表缓存原理
由于页表存放在主存中,因此程序每次访存至少需要两次:一次访存获取物理地址,第二次访存才获得数据。提高访存性能的关键在于依靠页表的访问局部性。当一个转换的虚拟页号被使用时,它可能在不久的将来再次被使用到,。
TLB是一种高速缓存,内存管理硬件使用它来改善虚拟地址到物理地址的转换速度。当前所有的个人桌面,笔记本和服务器处理器都使用TLB来进行虚拟地址到物理地址的映射。使用TLB内核可以快速的找到虚拟地址指向物理地址,而不需要请求RAM内存获取虚拟地址到物理地址的映射关系。这与data cache和instruction caches有很大的相似之处。
TLB的原理如下:
当CPU访问一个虚拟地址时,首先检查TLB中是否有对应的页表项。如果TLB中有对应的页表项(即命中),则直接从TLB获取物理地址。如果TLB中没有对应的页表项(即未命中),则需要访问内存来获取正确的页表项。在未命中情况下,操作系统会进行相应处理,从主存中获取正确的页表项,并将其加载到TLB中以供后续使用。一旦正确的页表项加载到TLB中,CPU再次访问相同虚拟地址时就可以直接在TLB中找到映射关系,提高了转换效率。TLB具有快速查找和高效缓存机制,能够极大地减少查询页表所需的时间。然而,由于TLB是有限容量的,在大型程序或多任务环境下可能无法完全覆盖所有需要转换的页面。当发生TLB未命中时,则会导致额外的内存访问开销;操作系统会负责管理和维护TLB,包括缓存策略、TLB的刷新机制等。常见的缓存策略有全相联、组相联和直接映射等。
5.1TLB原理
当cpu要访问一个虚拟地址/线性地址时,CPU会首先根据虚拟地址的高20位(20是x86特定的,不同架构有不同的值)在TLB中查找。如果是表中没有相应的表项,称为TLB miss,需要通过访问慢速RAM中的页表计算出相应的物理地址。同时,物理地址被存放在一个TLB表项中,以后对同一线性地址的访问,直接从TLB表项中获取物理地址即可,称为TLB hit。
想像一下x86_32架构下没有TLB的存在时的情况,对线性地址的访问,首先从PGD中获取PTE(第一次内存访问),在PTE中获取页框地址(第二次内存访问),最后访问物理地址,总共需要3次RAM的访问。如果有TLB存在,并且TLB hit,那么只需要一次RAM访问即可。
5.2TLB表项
TLB内部存放的基本单位是页表条目,对应着RAM中存放的页表条目。页表条目的大小固定不变的,所以TLB容量越大,所能存放的页表条目越多,TLB hit的几率也越大。但是TLB容量毕竟是有限的,因此RAM页表和TLB页表条目无法做到一一对应。因此CPU收到一个线性地址,那么必须快速做两个判断:
所需的也表示否已经缓存在TLB内部(TLB miss或者TLB hit)所需的页表在TLB的哪个条目内为了尽量减少CPU做出这些判断所需的时间,那么就必须在TLB页表条目和内存页表条目之间的对应方式做足功夫
全相连 - full associative
在这种组织方式下,TLB cache中的表项和线性地址之间没有任何关系,也就是说,一个TLB表项可以和任意线性地址的页表项关联。这种关联方式使得TLB表项空间的利用率最大。但是延迟也可能相当的大,因为每次CPU请求,TLB硬件都把线性地址和TLB的表项逐一比较,直到TLB hit或者所有TLB表项比较完成。特别是随着CPU缓存越来越大,需要比较大量的TLB表项,所以这种组织方式只适合小容量TLB
直接匹配
每一个线性地址块都可通过模运算对应到唯一的TLB表项,这样只需进行一次比较,降低了TLB内比较的延迟。但是这个方式产生冲突的几率非常高,导致TLB miss的发生,降低了命中率。
比如,我们假定TLB cache共包含16个表项,CPU顺序访问以下线性地址块:1, 17 , 1, 33。当CPU访问地址块1时,1 mod 16 = 1,TLB查看它的第一个页表项是否包含指定的线性地址块1,包含则命中,否则从RAM装入;然后CPU方位地址块17,17 mod 16 = 1,TLB发现它的第一个页表项对应的不是线性地址块17,TLB miss发生,TLB访问RAM把地址块17的页表项装入TLB;CPU接下来访问地址块1,此时又发生了miss,TLB只好访问RAM重新装入地址块1对应的页表项。因此在某些特定访问模式下,直接匹配的性能差到了极点
组相连 - set-associative
为了解决全相连内部比较效率低和直接匹配的冲突,引入了组相连。这种方式把所有的TLB表项分成多个组,每个线性地址块对应的不再是一个TLB表项,而是一个TLB表项组。CPU做地址转换时,首先计算线性地址块对应哪个TLB表项组,然后在这个TLB表项组顺序比对。按照组长度,我们可以称之为2路,4路,8路。
经过长期的工程实践,发现8路组相连是一个性能分界点。8路组相连的命中率几乎和全相连命中率几乎一样,超过8路,组内对比延迟带来的缺点就超过命中率提高带来的好处了。
这三种方式各有优缺点,组相连是个折衷的选择,适合大部分应用环境。当然针对不同的领域,也可以采用其他的cache组织形式。
TLB表项更新
TLB表项更新可以有TLB硬件自动发起,也可以有软件主动更新
TLB miss发生后,CPU从RAM获取页表项,会自动更新TLB表项TLB中的表项在某些情况下是无效的,比如进程切换,更改内核页表等,此时CPU硬件不知道哪些TLB表项是无效的,只能由软件在这些场景下,刷新TLB。在linux kernel软件层,提供了丰富的TLB表项刷新方法,但是不同的体系结构提供的硬件接口不同。比如x86_32仅提供了两种硬件接口来刷新TLB表项:
向cr3寄存器写入值时,会导致处理器自动刷新非全局页的TLB表项在Pentium Pro以后,invlpg汇编指令用来无效指定线性地址的单个TLB表项无效。内核对页缓存的操作函数
内核对页缓存的基本操作包含了在一个页缓存所形成的radix树中查找,增加和删除一个页缓存。基于radix的基本操作函数,页高速缓存的处理函数如下:
page_cache_alloc():分配一个新的页缓存;find_get_page():在页高速缓存中查找指定页;add_to_page_cache():把一个新页添加到页高速缓存;remove_from_page_cache():将指定页从页高速缓存中移除;read_cache_page():确保指定页在页高速缓存中包含最新的数据;