首页 文章

指令流水线和每条指令周期之间的链接

提问于
浏览
7

我理解instruction pipelining的基本原理 .

我还得到一些指令可能需要更长时间才能执行(cycles per instruction) .

但我没有得到两者之间的联系 .

我看到的所有管道图似乎都有“完美”指令,它们都具有相同的长度(周期数) .

4-staged pipeline

但是,如果第一条指令需要5个周期,第二条指令需要3个周期呢? cpu是否会停顿2个周期?

这个摊位会被称为bubble吗?或者这与hazards和数据依赖有什么不同?

此外,指令的长度(以字节为单位)是否以任何方式重要?

2 回答

  • 3

    在你的问题中,你提到了很多事情,所以我会花2美分试着让它变得更加清晰 . 让我们看一个有序的MIPS架构作为一个例子 - 除了可变长度指令之外,它还包含你提到的所有内容 .

    许多MIPS CPU具有5级流水线,其阶段为: IF -> ID -> EX -> MEM -> WB . (https://en.wikipedia.org/wiki/Classic_RISC_pipeline) . 让's first look at those instructions where each of these stages will generally take a single clock-cycle (this might not be the case on cache misses, for example). For instance, SW (store word to memory), BNEZ (branch on not zero) and ADD (add two registers and store to register). Not all of these instructions have useful work in all pipe stages. For example, SW has no work to do in WB stage, BNEZ can be finished as early as ID stage (that'最早可以计算目标地址)并且ADD在MEM阶段没有工作 .

    无论如何,这些指令中的每一个都将经历管道的每个阶段,即使它们中的某些部分没有工作 . 该指令将占用一个给定的阶段,但不会进行实际的工作(即没有结果写入WB阶段的寄存器用于SW指令) . 换句话说,在这种情况下不会有摊位 .

    转移到更复杂的指令,其EX阶段可能需要数十个周期,如MUL或DIV . 这里的事情变得更加棘手 . 现在,指令可以按顺序完成,即使它们总是按顺序获取(意味着现在可以使用WAW hazards) . 请看以下示例:

    MUL R1, R10, R11
    ADD R2, R5, R6
    

    首先获取MUL并在ADD之前到达EX阶段,但是在MUL的EX阶段运行超过10个时钟周期之前ADD将完成 . 但是,管道不会在任何时候停止,因为这个序列中不存在危险 - RAW和WAW都不可能发生危险 . 举另一个例子:

    MUL R1, R10, R11
    ADD R1, R5, R6
    

    现在,MUL和ADD都写入相同的寄存器 . 由于ADD将比MUL早完成,它将完成WB并写入其结果 . 稍后,MUL将执行相同的操作,R1最终会出现错误(旧)值 . 这是需要管道 stall 的地方 . 解决此问题的一种方法是防止ADD发出(从ID移到EX阶段),直到MUL进入MEM阶段 . 这是通过冻结或停止管道来完成的 . 引入浮点运算会导致管道中出现类似问题 .

    通过触及固定长度与可变长度指令格式的主题,我完成了我的答案(即使你没有明确要求它) . MIPS(和大多数RISC)CPU具有固定长度编码 . 这极大地简化了CPU流水线的实现,因为指令可以在一个周期内被解码并且输入寄存器被读取(假设寄存器位置以给定的指令格式固定,这对于MIPS是正确的) . 另外,由于指令总是具有相同的长度,因此简化了取出,因此不需要开始解码指令以找到其长度 .

    当然存在缺点:减少生成紧凑二进制文件的可能性,这导致更大的程序,这反过来导致较差的高速缓存性能 . 此外,存储器流量增加以及从存储器读取/写入更多字节的数据,这对于节能平台而言可能是重要的 .

    这一优势导致一些RISC架构定义了16位指令长度模式(MIPS16或ARM Thumb),甚至是可变长度指令集(ARM Thumb2具有16位和32位指令) . 与x86不同,Thumb2旨在使您可以轻松快速地确定指令长度,因此CPU仍然可以轻松解码 .

    这些压缩的ISA通常需要更多指令来实现相同的程序,但如果代码获取比管道中的指令吞吐量更多地成为瓶颈,则占用更少的总空间并且运行得更快 . (小/不存在的指令高速缓存,和/或从嵌入式CPU中的ROM读取) .

  • 2

    它实际上比你想象的要复杂一点 .

    对于一个CPU不执行指令,它执行uops,其次它可以不按顺序执行uops .

    uops
    简单的指令转换为单个uop,复杂的指令被拆分为多个微指令 . CPU有一个uop缓存,可以保留最后一个(例如1024个)uop . uops比完整指令更相似,因此在管道中配对更好 .

    Out of order execution
    如果CPU需要等待计算结果,它会查找不依赖于前一条指令的uops并执行这些操作 .
    为了允许OoO执行,CPU具有寄存器文件,该寄存器文件具有比程序员可用的寄存器多得多的寄存器(例如256个通用寄存器) . 它可以用它作为便笺簿来存储中间结果 .
    所有执行的指令都进入退休缓冲区,其中结果以原始顺序输出 .

    Buffers
    除此之外,停顿问题由缓冲区修复 .
    指令是以推测方式获取的,并且位于缓冲区中等待解码 .

    Constant time decoding
    X86 / X64以其复杂的解码而臭名昭着 . AMD和英特尔都通过在解码问题上投入大量的硅来解决这个问题,因此他们的cpus可以解码每个周期的恒定字节数,与指令复杂性无关 . 指令的长度并不重要,因为时间关键代码(紧密循环)是从uop-cache执行的,不需要解码 . 此外,解码通常是超尺寸的,因此几乎肯定不是瓶颈 .

    More stages
    现代CPU有14个或更多阶段,而不是你想象的4个阶段 .

    例如,参见AMD对Zen架构的阐述:https://www.extremetech.com/computing/234354-a-state-of-zen-amd-unveils-new-architectural-details-on-its-latest-cpu-core

    因此,除了管道之外,还有相当多的其他过程,其中的一些过程是为了防止失速和填充气泡 .

    在实践中,现代处理器在配对具有不同延迟的指令时不会受到影响 . 低延迟uops的使用已经在很大程度上消除了这个问题 .

    Hazards
    您链接的维基百科文章很好地解释了它 . 现代CPU使用Tomasulo's algorithm with register renaming来防止气泡 .

相关问题