我写了一个内核模块来检查CR4.PCIDE,它没有设置。为什么Linux没有使用这样的功能来减少由于TLB失效和缓存污染导致的性能下降?
答案 0 :(得分:25)
更新:由于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上进行小的性能改进的时间不够)。
答案 1 :(得分:15)
是! Linux Kernel的最新版本具有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 cpu_vm_mask_var,我们永远不会收到超过一次击落IPI 非现行mm,但我们仍将获得TLB寿命的好处 在处理例如。任务轮流运行的管道工作负载 相同的CPU。
您还可以从该线程收集地址空间标识符长期以来在其他Linux体系结构上使用过。