W.S*_*Sun 26 x86 assembly caching operating-system linux-kernel
我写了一个内核模块来检查CR4.PCIDE,它没有设置.为什么Linux不使用这样的功能来减少因TLB失效和缓存污染导致的性能下降?
Bre*_*dan 25
更新:由于2017年末和2018年初的Meltdown和Spectre攻击,这在4.15时间框架内发生了变化.有关详细信息,请参阅其他答案.
注意:我不是Linux开发人员
对于英特尔的"流程上下文标识符",限制为4096个ID.这意味着当有超过4096个进程需要管理它们时(例如,可能执行"最近最少使用"的事情,这样如果当前没有ID的进程需要执行,那么该ID来自某些其他过程并重复使用).
另一件事是多CPU系统上的"TLB击落".这些可能有点贵,所以人们会采取措施来避免它们.例如,如果一个进程只有一个线程,那么它只能在一个CPU上运行,你就知道不需要向其他CPU发送IPI(中断它们并要求它们进行"TLB击落").一旦开始使用PCID,您就不能确定其他CPU是否仍然没有TLB条目,并且无法通过这些技巧来避免"TLB击落".这也意味着(理论上,对于严重实施的PCID支持),您从PCID获得的性能可能低于由于未经保留的TLB击落和ID管理开销而导致的性能损失,从而导致净损失.
我所说的大部分内容是添加对PCID的支持有点复杂(这不像你可以在CR4中设置一个标志而忘记它).您必须进行一些研究(实验,原型,基准测试)以确定实施它的最有效方法.对于大型/复杂/旧内核(如Linux)来说,它会变得更加复杂,因为你必须小心不要意外地惹恼别的东西.另一件事是这个功能相对较新(如果我没记错的话,它只存在几年)并且没有很多CPU支持(例如任何年龄稍大的东西,以及任何来自AMD的东西).
基本上,我认为它归结为"时间与收益"(或者,对于有限数量的CPU来说,没有足够的时间来提高性能).
Bee*_*ope 16
是! 最新版本的Linux内核具有PCID支持.在提出这个问题的时候,这种支持并不存在,但它已经在2017年底附近添加,从4.14内核开始.您可以关注此LKML链中的一些原始补丁讨论.
此更改实际上并不关联每个进程的唯一PCID,因为数量有限,或尝试将它们分配给常用的基础,但每个CPU使用一个PCID缓存,因此可能在给定CPU上运行多个进程能够使用PCID机制来避免TLB刷新开销.
这最近变得更加相关,因为发现了一系列漏洞,这些漏洞允许无特权的用户代码读取内核内存,KPTI补丁被部署在内核中.这些补丁可能会对性能产生重大影响,因为任何内核调用都可能使用户级TLB条目无效.通过PCID支持,可以减少影响,因为保留了用户级TLB条目.
下面是这个答案的旧版本,当时发布的内核中没有PCID支持:
还没有,但似乎有些东西可能正在进行中.见线程开始在这里的LKML.特别是,提出了跨核心TLB击落问题的解决方案,其中包括:
如果在接收非当前PCID的TLB击落时,我们只是刷新该PCID的所有条目并从mm的cpu_vm_mask_var中移除CPU,我们将永远不会收到超过一次击落IPI的非当前mm,但我们在处理例如时,仍将获得TLB长寿的好处.管道工作负载,其中任务轮流在同一CPU上运行.
您还可以从该线程中收集地址空间标识符长期以来在其他Linux体系结构上使用的内容.