Loads
当指令从回写类型的存储器中读取某个地址时,处理器会按照如下的规则从高速缓存或存储器中查找数据(确切的说是匹配地址):
- 发起核(即执行读存指令的处理器核)的一级数据缓存
- 其他核的一级数据缓存和二级缓存
- 系统存储器
在第二步中,如果命中其他核的一级数据缓存且数据是修改状态,则从其他核中获取数据,此时会忽略二级缓存行返回的数据及数据状态。
下表是从存储器簇中不同的层级部件中的某存储部分读取前4个字节的性能特征。尽管延迟列提供了对访问延迟的估值,但是实际上的延迟会根据很多因素发生变化,例如高速缓存和存储器的繁忙程度,以及它们的参数。
表:Intel Core微架构上Load/Store操作的性能特征
Data Locality |
Load |
Store |
||
Latency |
Throughput |
Latency |
Throughput |
|
DCU |
3 |
1 |
2 |
1 |
DCU (other core in modified state) |
14 + 5.5 bus cycles |
14 + 5.5 bus cycles |
14 + 5.5 bus cycles |
N/A |
L2 Cache |
14 |
3 |
14 |
3 |
Memory |
14 + 5.5 bus cycles + memory |
Depends on bus read protocol |
14 + 5.5 bus cycles + memory |
Depends on bus write protocol |
有时候,修改状态的缓存行必须被evict,这样为新的缓存行腾空间。缓存行的eviction与新数据的读入可以并行执行,并不会增加额外的延迟。但是,当数据被写回存储器时,eviction操作需要使用缓存带宽,有可能还会使用总线带宽。因此,当发生多次缓存未命中事件时,导致短时间内多个修改状态的缓存行被eviction,这样缓存的整体响应时间会恶化。
Stores
当指令向某个回写类型的存储器地址写入数据时,处理器会首先保证该地址对应的缓存行位于发起核的一级数据缓存中且缓存行状态必须是“独占”或者“修改”状态。为了满足 这个条件,处理器会发起一个属主读请求(read-for-ownership),并按如下顺序查找缓存行:
- 发起核的一级数据缓存
- 其他核的一级数据缓存以及共享的二级缓存
- 系统存储器器
如果在其他核一级数据缓存命中且数据行是修改状态,则发起核接收这个数据行,同时会忽略二级缓存返回的查找结果及状态信息。当完成属主读请求后,数据被写入到发起核的一级缓存中,将缓存行的状态标志设置为“修改”。
属主读请求以及存储数据到发起核的一级数据缓存操作都发生在写存指令退役之后,而且按照指令退役的顺序发生(即处理器不会做投机式写存)。因此缓存的写入延迟并不会影响写存指令的延迟。但是,多个连续的写存指令可能会导致累积地延迟,从而影响程序性能。上面的表中(位于loads一节)展示了存储器层次中各级的存储延迟。