Caching 为什么从缓冲区加载/存储需要一个完整的时钟周期?

Caching 为什么从缓冲区加载/存储需要一个完整的时钟周期?,caching,assembly,parallel-processing,cpu,clock,Caching,Assembly,Parallel Processing,Cpu,Clock,在本视频中: 28:00,他开始解释以下示例: ld rax <- [rbx+16] //Clock 0 Starts add rbx,16 cmp rax,0 jeq null_chk st [rbx-16] <- rcx //Clock 1 Starts ld rcx <- [rdx+0] //Clock 2 Starts. Why clock 1 only does one op? ld rax <- [rax+8] //Clock 3 Star

在本视频中:

28:00,他开始解释以下示例:

ld rax <- [rbx+16]   //Clock 0 Starts
add rbx,16
cmp rax,0
jeq null_chk
st [rbx-16] <- rcx   //Clock 1 Starts
ld rcx <- [rdx+0]    //Clock 2 Starts. Why clock 1 only does one op?
ld rax <- [rax+8]    //Clock 3 Starts. Why?

ld-rax不,他说有两个缓存未命中
并行运行

这里有4次内存访问(数据内存,但我们忽略代码/页面漫游等):

  • 地址
    [rbx+16]
    的第一个ld可以被分派并发送到内存中
  • 该存储只有在退休后才能执行,因为他知道它肯定是非伪造的(他提到分支可能被错误预测——这在退休前的执行时间可以知道,但可能还有其他他没有提到的情况,如故障或异常)。此外,存储地址需要等待计算
    add rbx,16
    ,但这不会花费太长时间。但是,保存存储的分支的执行和最终失效取决于
    rax
    compare&jmp的结果,而这又取决于第一次加载(此处假定为进入内存)(换句话说,不要屏住呼吸)
  • 第二次加载(来自
    [rdx+0]
    )是独立的,可以调度-这是并行完成的第二次加载
  • 第三次加载无法调度-其地址取决于
    rax
    ,这就像cmp+jmp必须等待第一次加载完成一样。这意味着我们无法处理这个负载,我们甚至不知道实际地址。例如,考虑如果负载返回,写入
    rax
    ,并且
    [rax+8]
    等于
    [rbx-16]
    ,在硬件中会发生什么?您必须从存储转发数据

  • 因此,在执行代码时,我们可以立即(使用1-2个周期,取决于解码和地址计算时间)发送2个加载—第1和第3节。其他内存操作将不得不等待。性能的关键因素是尽早启动加载,并尽可能并行启动。

    感谢您对缓存未命中的解释!最后一个问题,为什么时钟1、2和3只有一个操作,而时钟0只有4个操作?这有点过于简单化了,但假设每一条指令都可以在1个周期(当然不包括内存延迟)内解码和“启动”(基本上分配到OOO执行引擎)——他假设机器可以并行执行4条指令(查找,但还有另一个限制-每个周期不超过一条加载/存储指令,因此最后3条指令必须一个接一个地执行。与这里的内存延迟相比,它仍然可以忽略不计。真正的CPU经常被如此小的限制所困扰。