当我阅读RISC-V用户级ISA手册时,我注意到它说“OpenRISC有条件代码和分支延迟槽,这使更高性能的实现变得复杂。”所以RISC-V没有分支延迟槽RISC-V用户级ISA手动链接。此外,维基百科说,大多数较新的RISC设计都省略了分支延迟槽。为什么大多数较新的RISC架构逐渐省略了分支延迟槽?
分支延迟槽是在最早的单一问题中作为性能解决方案引入的,以便RISC实现。早在这些体系结构的第二次商业实现时,就已经很清楚,延迟槽和单一条件代码的概念都将成为阻碍。当我们在HaL开发64位SPARC体系结构时,注册窗口已经添加到该列表中。这些共同的挑战已经足够了,我们建议使用动态二进制翻译来支持SPARC32,这样我们就可以放弃遗留的负担。在这一点上,它们的成本是芯片面积的40%,指令发出率的20%-25%。
现代处理器的实现严重无序(阅读“寄存器重命名”或“Tomasulo算法”),动态调度,在许多情况下是多问题的。因此,延迟分支已经从性能增强变成了一种复杂性,即为了兼容性,指令排序单元和寄存器重命名逻辑必须小心地绕过。
坦率地说,这在SOAR/SPARC或MIPS芯片上也不是一个好主意。延迟分支为调试器中的单步、动态二进制转换器和二进制代码分析带来了有趣的挑战(我曾经实现过所有这些)。即使在单问题机器上,它们也为异常处理带来了一些有趣的复杂性。早在这些指令集的第二次商业实现时,延迟时隙和单条件代码的概念就已经成为阻碍。
Alain关于Pentium分支成本的评论并没有直接延续到RISC部分,而且这个问题比他建议的要复杂一点。在固定长度的指令集上,实现称为“分支目标缓冲区”的东西很简单,它将指令缓存在分支目标处,这样就不会因分支而导致管道失速。在最初的RISC机器(IBM603)上,John Cocke包含了一条“准备分支”指令,其目的是允许程序(或更准确地说,编译器)将可能的目标显式加载到分支目标缓冲区中。在一个好的实现中,BTB中的指令是预解码的,这减少了管道中的一个周期,并使正确预测的BTB转换几乎免费。此时的问题是条件代码和错误预测。
由于BTB和多问题,需要重新设想分支延迟和分支预测失误延迟的概念。在许多多问题机器上实际发生的情况是,处理器沿着分支的两条路径前进,至少可以从指令提取单元中当前预加载的缓存线或BTB中获取指令。这会减缓分支两侧的指令发出速度,但也可以让您在分支两侧取得进展。分支解析后,“不应采用”路径将被放弃。对于整数处理,这会减慢您的速度。对于浮点运算,由于计算操作需要几个周期,所以不太清楚。
在内部,积极的多问题机器在分支时可能有三到四个操作在内部排队,因此通常可以通过执行这些已经排队的指令,然后重新构建队列深度来补偿分支延迟。
延迟槽仅在较短的有序标量流水线上有用,而不是高性能超标量,或者尤其是在无序执行的情况下。
它们使异常处理显着复杂化(对于硬件和软件),因为您需要记录当前程序计数器和单独的下一台PC地址,以防延迟槽中的指令出现异常。
它们还使6级标量或超标量MIPS中的未命中预测需要杀死多少条指令变得复杂?通过引入多种可能性,例如分支延迟指令已经在管道中并且不需要终止,而仍然在等待I-cache未命中,因此重新引导前端需要等到它获取分支延迟指令之后。
分支延迟插槽在体系结构上公开了顺序式经典RISC管道的实现细节,以提高这种uarch的性能,但其他任何东西都必须围绕它来工作。如果您的uarch是标量经典RISC,那么它只会避免从执行的分支获取代码气泡(即使没有分支预测)。
即使是现代的顺序uarch也需要分支预测才能获得良好的性能,内存延迟(以CPU时钟周期衡量)远远高于早期MIPS时代。
(有趣的事实:MIPS的1个延迟槽足以隐藏R2000 MIPS I上的总分支延迟,这要归功于巧妙的设计,将其保持在1个周期。)
编译器不能总是以最佳方式填充分支延迟槽,因此即使我们可以在没有显着开销的高性能CPU中实现它们,它们也会根据每条指令完成的总工作来降低吞吐量。程序通常需要执行更多指令,而不是更少,ISA中的延迟槽。
(虽然有时在比较和分支之后执行无条件操作可以允许重用寄存器,而不需要新的寄存器,但在没有MIPS等标志的ISA上,分支指令直接测试整数寄存器。)
引用Henessy和Patterson(计算机架构与设计,第5版)
谬误:你可以设计一个完美的架构
所有架构设计都涉及在一组硬件和软件技术的背景下进行的权衡。随着时间的推移,这些技术可能会发生变化,而在做出决策时可能是正确的决策看起来就像是错误。(...) RISC阵营中的一个例子是延迟分支。使用五级管道控制管道危害很简单,但对于具有较长管道且每个时钟周期发出多条指令的处理器来说,这是一个挑战。
事实上,就软件而言,延迟分支只有缺点,因为它使程序更难阅读,效率更低,因为插槽经常由NOP填充。
在硬件方面,这是一个在80年代有一定意义的技术决定,当时管道是5或6级,无法避免一个周期分支的惩罚。
但目前,管道也更加复杂。在最近的奔腾μ体系结构上,分支惩罚为15-25个周期。因此,一个指令延迟分支是无用的,用一个15条指令延迟分支来隐藏这个延迟槽显然是不可能的,这将破坏指令集的兼容性。
我们开发了新技术。分支预测是一项非常成熟的技术。使用目前的分支预测器,预测失误远远低于具有无用(nop)延迟槽的分支数量,因此更有效,即使在6周期的计算机上(如nios-f)。
因此,延迟分支在硬件和软件方面效率较低。没有理由保留它们。
我读了Patterson的以下声明 随着处理器进入更长的流水线并在每个时钟周期发出多条指令,分支延迟变得更长,单个延迟槽是不够的。 我可以理解为什么“每个时钟周期发出多条指令”会导致单个延迟槽不足,但我不知道为什么“更长的管道”会导致它。 另外,我不明白为什么更长的管道会导致分支延迟变得更长。即使管道更长(完成一条指令的步骤),也不能保证周期会增加,那么为什么分支延迟会增加呢?
1、mybatis 是否支持延迟加载? 延迟加载其实就是讲数据加载时机推迟,比如推迟嵌套查询的时机。 延迟加载可以实现先查询主表,按需实时做关联查询,返回关联表结果集,一定程度上提高了效率。 mybatis仅支持关联对象association和关联集合对象collection的延迟加载,association是一对一,collection是一对多查询,在mybatis配置文件中可以配置lazylo
问题内容: 我试图在收到请求后立即发送页面响应,然后进行处理,但是我发现响应即使按代码顺序排列也没有“首先”发送。在现实生活中,我有一个页面可供上传一个Excel工作表,该工作表保存到数据库中需要花费时间(50000+行),并且希望更新用户进度。这是一个简化的示例;(取决于您有多少RAM,您可能需要添加几个零来计数才能看到结果) 问题答案: HTTP协议的原始概念是一个简单的请求- 响应服务器-客
问题内容: 我需要在循环中对数据库进行SQL查询: 更好的方法是:保持原样或循环后移动: 或者是其他东西 ? 问题答案: 整个要点是直到函数返回才执行,因此将其放置在要关闭的资源打开后的适当位置。但是,由于要在循环内创建资源,因此根本不要使用defer- 否则,在函数退出之前,您不会关闭在循环内创建的任何资源,因此它们会堆积直到然后。相反,您应该在每次循环迭代结束时关闭它们, 而无需 :
问题内容: 我只是好奇为什么不赞成使用HTML中的标记。 通过将容器封装在标签中,这是一种快速居中对齐文本和图像块的简单方法,我现在真的找不到任何更简单的方法。 任何人都知道关于如何使“东西”居中(而不是和宽度的东西)的任何简单方法吗?而且,为什么不推荐使用它? 问题答案: 该元素已弃用,因为它定义了其内容的 表示形式 —它未描述其内容。 居中的一种方法是将元素的和属性设置为,然后将父元素的属性设
我在计算一个简单蒸汽的最大值,结果是: (S11000,S1,值:999) (S12000,S1,值:41) 最后一行数据明显迟到了: 为什么按第一个窗口(0-1000)计算? 我认为第一个窗口应该在到达时触发。 对于这个结果,我很疑惑。 MyReductingMax(),MyWindowFunction()