我写了一个内核模块来检查CR4.PCIDE,它没有设置。为什么Linux不使用这样的功能来减少因TLB失效和缓存污染导致的性能下降?
更新:由于2017年末和2018年初的Meltdown and Spectre attacks,这在4.15时间框架内发生了变化。有关详细信息,请参阅the other answer。
注意:我不是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来说,没有足够的时间来提高性能)。
是!最新版本的Linux内核具有PCID支持。在提出这个问题的时候,这种支持并不存在,但是从2017年底开始,从4.14 kernel开始增加。您可以关注一些原始的补丁讨论in this LKML chain。
此更改实际上并不关联每个进程的唯一PCID,因为数量有限,或尝试将它们分配给常用的基础,但每个CPU使用一个PCID缓存,因此可能在给定CPU上运行多个进程能够使用PCID机制来避免TLB刷新开销。
这最近变得更加相关,因为a series of vulnerabilities发现允许无特权的用户代码读取内核内存,KPTI patches部署在内核内存中。这些补丁可能会对性能产生重大影响,因为任何内核调用都可能使用户级TLB条目无效。通过PCID支持,可以减少影响,因为保留了用户级TLB条目。
下面是这个答案的旧版本,当时发布的内核中没有PCID支持:
还没有,但似乎有些东西可能正在进行中。查看在LKML上启动around here的主题。特别是,提出了跨核心TLB击落问题的解决方案,其中包括:
如果在接收非当前PCID的TLB击落时,我们只是刷新该PCID的所有条目并从mm的cpu_vm_mask_var中移除CPU,我们将永远不会收到超过一次击落IPI的非当前mm,但我们在处理例如时,仍将获得TLB长寿的好处。管道工作负载,其中任务轮流在同一CPU上运行。
您还可以从该线程中收集地址空间标识符长期用于其他Linux体系结构。