(其中一些是x86和Intel专用的。大多数关键点适用于任何执行硬件页面遍历的CPU。我还讨论了ISA,如用软件处理TLB未命中的MIPS。)
现代x86微架构具有专用的页游硬件。他们甚至可以推测地进行页面遍历,以便在TLB遗漏发生之前加载TLB条目。为了支持硬件虚拟化,页面漫游器可以在主机VM中处理来宾页表。(来宾物理内存=主机虚拟内存,或多或少。VMWare发表了一篇论文,总结了EPT和Nehalem上的基准测试)。
Skylake甚至可以同时在飞行中进行两次页面行走,参见英特尔优化手册第2.1.3节。(Intel还将页面拆分负载损失从大约100个额外的延迟周期降低到大约5或10个额外的延迟周期,与高速缓存行拆分相同,但吞吐量更差。这可能是相关的,或者可能增加第二个页面遍历单元是发现页面拆分访问(和TLB未命中?)比以前在实际工作负载中估计的更重要的一个单独的响应)。
一些微体系结构通过将未缓存的PTE推测性加载但在第一次真正使用条目之前用存储区修改到页表时,将其视为误推测来保护您免受推测性页面遍历。例如,窥探页面表条目中存储的仅推测的TLB条目,这些条目在架构上没有被任何早期指令引用。
(Win9x依赖于这一点,而不破坏现有的重要代码是CPU供应商关心的问题。当Win9x编写时,当前的TLB无效规则还不存在,所以它甚至不是一个bug;参见下面引用的Andy Glew的评论)。AMD推土机家族违反了这一假设,给你的只是x86手册上说的纸上。
由页面遍历硬件生成的页表加载可以在L1、L2或L3缓存中命中。例如,Broadwell perf计数器可以计算L1、L2、L3或内存中的页面遍历命中数(即缓存未命中)。事件名称为page_walker_loads.dtlb_l1
,用于表示L1+FB中的DTLB页面walker命中数,其他事件名称为ITLB和其他级别的缓存。
由于现代页表使用基数树格式,页目录项指向页表项的表,因此更高级别的PDE(页目录项)值得在页遍历硬件中缓存。这意味着在您可能认为不需要刷新TLB的情况下,您需要刷新TLB。英特尔和AMD实际上这样做,根据本文(第3节)。ARM也是,它们的中间表遍历缓存
那篇论文说,AMD CPU上的页面遍历加载忽略了L1,但确实通过了L2。(可能是为了避免污染L1,或者减少读取端口的争用)。无论如何,这使得在页面遍历硬件中缓存几个高级PDE(每个PDE包含许多不同的翻译条目)变得更加有价值,因为指针追逐链的代价更高,延迟也更高。
但是请注意,Intel保证不会对TLB条目进行负缓存。将页从无效更改为有效不需要invlpg
。(因此,如果一个真正的实现确实想要进行这种负缓存,它必须窥探或以某种方式仍然实现Intel手册所保证的语义。)
但是有些旧的Cyrix CPU确实执行负缓存。跨厂商的x86保障的通用子集并不总是像英特尔的那样强大。不过,64位内核应该能够安全地将PTE从not-present更改为present,而不需要invlpg,因为这些Cyrix芯片只有32位。(如果Intel、AMD和Via手册都认为它是安全的,那么其他任何x86-64供应商的IDK。)
(历史记录:Andy Glew在Electronics.se上对这个问题的重复回答说,在P5和更早的时候,硬件页面漫步加载绕过了内部的L1缓存(它通常是写通过的,所以这使得pagewalk与存储保持一致)。IIRC,我的奔腾MMX主板在mobo上有L2缓存,可能作为内存端缓存。Andy还证实P6和更晚的时候确实从普通的L1d缓存加载。
另一个答案在结尾也有一些有趣的链接,包括我在最后一段结尾链接的论文。它似乎还认为操作系统可能会在页面错误(HW pagewalk找不到条目)时更新TLB本身,而不仅仅是页表,并想知道在x86上是否可以禁用HW页面遍历。(但实际上操作系统只是修改内存中的页表,从#pf
返回时会重新运行错误指令,这样HW pagewalk这次就会成功。)也许这篇论文正在考虑像MIPS这样的ISA,在那里软件TLB管理/遗漏处理是可能的。
我认为在P5(或任何其他x86)上禁用HW pagewalk实际上是不可能的。这将要求软件使用专用指令(没有专用指令)或WRMSR
或MMIO存储更新TLB条目。令人困惑的是,安迪说(在我下面引用的一个帖子中),软件TLB处理在P5上更快。我想他的意思是如果有可能的话会更快。他当时在模仿(在MIPS上)工作,在那里SW页面遍历是一个选项(有时是唯一的选项),不像x86。
或者,他的意思是,在您预计还没有TLB条目的情况下,使用MSR提前设置TLB条目,以避免一些页面遍历。显然,386/486通过特殊寄存器具有TLB-entry query/set访问权限:https://retrocomputing.stackexchange.com/questions/21963/how-did-the-test-register-work-on-the-i386-and-the-i486,但对于386/486功能,可能没有等效的P5 MSR。
AFAIK,没有办法让TLB错过一个软件功能(禁用分页?)即使在386/486上,所以你不能完全避免HW页面步行者,只要prime TLB来避免一些TLB失误,至少在386/486上是这样。
正如Paul Clayton所指出的(关于TLB未命中的另一个问题),硬件页面遍历的最大优势是TLB未命中不一定会使CPU停滞不前。(乱序执行正常进行,直到重新排序缓冲区填满为止,因为加载/存储区不能退役。退役是按顺序进行的,因为如果前面的指令出错,CPU就不能正式提交任何本不应该发生的事情。)
顺便说一句,可能会构建一个x86 CPU,通过捕获微码来处理TLB未命中,而不是专用的硬件状态机。这会(很多?)性能较差,可能不值得推测性地触发(因为从微码发出uops意味着不能从正在运行的代码发出指令。)
如果您在一个单独的硬件线程中运行这些UOP,理论上来说,微编码TLB处理可能并不可怕(有趣的想法),SMT风格。在从单线程切换到两个活动逻辑核心时,您需要它的启动/停止开销比普通的超线程少得多(必须等待事情耗尽,直到它可以对ROB、存储队列等进行分区),因为与普通的逻辑核心相比,它的启动/停止频率非常高。但是如果它不是一个完全独立的线程,而是一些独立的退休状态,那么这是可能的,所以它的缓存丢失不会阻止主代码的退休,并让它使用两个隐藏的内部寄存器来存储临时代码。它必须运行的代码是由CPU设计者选择的,因此额外的HW线程不必接近x86核心的完整架构状态。它很少做任何存储(也许只是为了PTES中的访问标志?),所以让这些存储使用相同的存储队列作为主线程也不错。您只需对前端进行分区,以混合到TLB管理UOP,并让它们与主线程无序地执行。如果您可以将每个pagewalk的UOP数量保持在较小的范围内,它可能不会很糟糕。
据我所知,没有CPU在单独的HW线程中使用微码进行“HW”页面遍历,但这是理论上的可能性。
在一些RISC体系结构(如MIPS)中,OS内核负责处理TLB未命中。TLB未命中导致内核的TLB未命中中断处理程序的执行。这意味着操作系统可以自由地在这样的体系结构上定义自己的页表格式。我想,如果CPU不知道页表格式,那么在写入后将页标记为脏也需要对OS提供的例程设置陷阱。
本章来自操作系统教科书,解释虚拟内存、页表和TLB。它们描述了软件管理的TLB(MIPS,SPARCv9)和硬件管理的TLB(x86)之间的区别。如果您想要一个真实的例子,一篇关于几个内存管理单元、TLB-Refill机制和页表组织的文章展示了Ultrix中的TLB miss处理程序的一些示例代码。
Oprofile
计算页面遍历周期)Intel开始运行页表遍历缓存而不是绕过缓存的主要原因是性能。在P6之前,页表遍历很慢,没有从缓存中受益,而且不是推测性的。速度足够慢,以至于软件TLB丢失处理是一个性能胜利1。P6加速的TLB由于使用缓存和缓存中间节点(如页面目录项)而错过了这些操作。
顺便说一句,AMD不愿意做TLB小姐处理投机。我想是因为他们受到了DEC VAX Alpha建筑师事务所的影响。DEC Alpha的一位架构师非常强调地告诉我,对TLB未命中的推测处理,如P6所做的,是不正确的,永远不会奏效。当我在2002年左右到达AMD时,他们仍然有一个叫做“TLB栅栏”的东西--不是栅栏指令,而是rop或微码序列中的一个点,在那里TLB可能会或不可能发生--恐怕我不记得它到底是如何工作的。
因此,我认为这并不是说推土机放弃了TLB和页表行走的一致性,不管这意味着什么,因为推土机可能是第一个AMD机器做适度积极的TLB失误处理。
回想一下,当P6启动时,P5并没有发布:现有的x86es都跳过了缓存,页面表按顺序遍历,没有异步预取,而是在通过缓存写入时遍历。即。它们是缓存一致的,操作系统可以依赖于TLB条目的确定性替换。IIRC我编写了关于推测性和非确定性可缓存性的体系结构规则,用于TLB条目以及数据和指令缓存。您不能责怪Windows和UNIX以及Netware等操作系统没有遵循当时还不存在的页表和TLB管理规则。
IIRC我编写了关于推测性和非确定性可缓存性的体系结构规则,用于TLB条目以及数据和指令缓存。您不能责怪Windows和UNIX以及Netware等操作系统没有遵循当时还不存在的页表和TLB管理规则。
(2a')最尴尬的bug之一是与带进位的内存添加有关。在早期的微码中。加载将结束,进位标志将被更新,存储可能会出错--但进位标志已经被更新,因此指令无法重新启动。//这是一个简单的微代码修复,在写入进位标志之前进行存储--但额外的一个uop足以使该指令不适用于“中速”ucode系统。
(3)不管怎样-P6及其后代对处理TLB一致性问题的主要“支持”是在报告错误之前在退休时重新遍历页表。这避免了当页表表示不应该有错误时报告错误,从而使操作系统感到困惑。
(4)元注释:我不认为任何体系结构都有正确定义的规则来缓存无效的TLB条目。//AFAIK大多数处理器不会缓存无效的TLB条目--可能Itanium及其NAT(不是东西)页面除外。但确实需要:推测性内存访问可能是对野生地址的访问,错过TLB,执行昂贵的页表遍历,减慢其他指令和线程--然后一遍又一遍地这样做,因为没有记住“这是一个糟糕的地址,不需要遍历页表”这一事实。//我怀疑DOS攻击可能会利用这个。
(4')更糟糕的是,OSE可能会做出隐含的假设,即无效的翻译永远不会被缓存,因此在从无效转换到有效时不执行TLB无效化或MP TLB击落。//更糟^2:假设您正在缓存页表缓存的内部节点。设想PD包含所有无效的PDE;更糟糕的是^3,PD包含有效的d个PDE,这些PDE指向所有无效的PTs。您仍然可以缓存那些PDE吗?操作系统到底什么时候需要使一个条目无效?
(4')因为使用处理器间中断的MP TLB击落代价很高,所以OS性能人员(就像我以前一样)总是提出这样的论点:“在将PTE从无效改为有效后,我们不需要使TLB无效”或“用不同的地址从有效只读改为有效可写”。或者“在更改PDE以指向PTE与原始PT完全相同的不同PT后,我们不需要使TLB无效...”。//许多伟大而巧妙的论点。不幸的是,并不总是正确的。
我的一些计算机架构师朋友现在支持连贯的TLB:像数据缓存一样窥探写的TLB。主要是为了允许我们构建更积极的TLB和页表缓存,如果叶节点和内部节点的条目有效和无效。也不用担心操作系统的人的假设。//我还没有:对于低端硬件来说太贵了。但在高端可能值得做。
类似的情况也适用于自修改代码:与其说我们想让自修改代码运行得快,不如说试图让用于自修改代码的遗留机制--为序列化指令如CPUID而耗尽管道--比仅仅窥探Icache和管道更慢。但是,这同样适用于高端机器:在低端机器上,遗留机制足够快和便宜。
记忆排序也一样。高端窥探更快;低端排水更便宜。
很难维持这种二分法。
问题内容: 我想知道当你使用注释方法时实际发生了什么?当然,我知道Spring将把该方法包装在Transaction中。 但是,我有以下疑问: 听说Spring创建了代理类?有人可以更深入地解释这一点。该代理类中实际包含什么?实际班级会怎样?我怎么能看到Spring创建的代理类 我还在Spring文档中读到: 注意:由于此机制基于代理,因此仅会拦截通过代理传入的“外部”方法调用。这意味着“自调用”
我在yarn cluster上运行的spark应用程序崩溃了,我正在试图确定根本原因。在我使用从yarn获得的日志中,我看到在块获取期间有一大堆连接被拒绝,还有一个内存不足错误。很难说出根本原因是什么。我的问题是当容器因为OutOfMemory异常而被杀死时会发生什么。因此,在容器日志中,我看到这是如何在容器上启动执行器的 我还看到许多。在应用程序崩溃之前,似乎有多个这样的问题。spark重试一个
假设我有一个普通的应用程序,其中我正在使用ApplicationContext ApplicationContext=new FileSystemXmlApplicationContext(“bean.xml”)创建一个Spring应用程序上下文 现在,假设在这个bean.xml有Spring bean的bean定义,所以当我创建应用程序上下文时,Spring容器将为这个实例化和初始化一个对象。
流程 解析 URL 域名解析 发送 HTTP 请求 查找缓存 接收 HTTP 响应 解析响应内容 HTML 图片 视频 音频 PDF 资料 浏览器输入 URL 后发生了什么?
本文向大家介绍浅谈内存耗尽后Redis会发生什么,包括了浅谈内存耗尽后Redis会发生什么的使用技巧和注意事项,需要的朋友参考一下 前言 作为一台服务器来说,内存并不是无限的,所以总会存在内存耗尽的情况,那么当 Redis 服务器的内存耗尽后,如果继续执行请求命令,Redis 会如何处理呢? 内存回收 使用Redis 服务时,很多情况下某些键值对只会在特定的时间内有效,为了防止这种类型的数据一直占
嗨,一个星期以来,我一直在追踪我的办公代码中的一个错误。它与Spring、Hibernate和Transaction有关。 我所知道的: 1.延迟加载。 2. Spring如何使用代理和拦截器进行事务管理。 3. Spring中的事务传播,我们的代码使用默认的REQUIRED。 4.每个请求/会话的会话和Hibernate的分离实体基础来保持会话,以及我们的会话不是每个会话的事实。 我的场景:我的