L1 DCache (L1D)
L1D指的是一级数据缓存,通过缓存内部的数据结构(即硬件逻辑),管理所有类型的读存与访存请求:
- 允许投机式,乱序发射读存与写存请求
- 确保退役的读存与写存指令在退役时具有正确的数据
- 确保读存与写存操作遵循IA32与Intel 64指令集架构定义的访存顺序规则
表:L1D的构件
Component | Sandy Bridge | Nehalem |
DCU – Data Cache Unit | 32KB, 8 ways | 32KB, 8 ways |
Load Buffers | 64 entries | 48 entries |
Store Buffers | 36 entires | 32 entries |
Line fill buffers (LFB) | 10 entries | 10 entries |
DCU的容量是32K字节大小,8路组相联;DCU缓存行大小是64字节,组织在8个存储体中(即每个存储体保存8个字节)
在DCU内部,每次访问可达16字节,如果是256位Intel AVX指令操作则执行两个16字节访问。每个周期可以同时处理两个读存操作与一个写存操作。
L1D会维护不能立即完成的访存请求。导致访存延迟的因素有:缓存未命中,跨缓存行的非对齐访问,来自于前一个写存操作的数据还不能进行转发,读存操作遭遇存储体冲突,读存由于缓存行需要被替换而阻塞。
从微指令分配阶段直到退役阶段,L1D可以维护最多64条读存操作(注:正好是读存缓冲区的容量);可以维护最多36个写存操作(注:写存缓冲区容量),从分配阶段直到数据被提交到DCU中,或者对于非时效写存操作,直到数据写入到行填充缓冲区LFB中。
L1D可以处理多个未完成缓存未中事件,持续的为读存与写存操作提供服务。使用LFB缓冲区,可以同时管理最多10个缓存行未中请求。
L1D是回写式写分配(write-back write-allocate)高速缓存。回写式指的是命中DCU的写存操作不会更新更低层级的存储器(即不更新L2,L3和memory)。写分配指的是未命中DCU的写存操作会导致在DCU中分配一个新的缓存行。
Loads
L1D架构可以每周期服务两个读存操作,每个操作可以请求最大16字节长的数据。最多可以维护32个处于不同阶段的读存操作,从乱序引擎的分配阶段直到将数据传输到执行核阶段。
读操作可以:
- 尽管在指令顺序上写操作位于读操作之前,但是如果已知读操作地址与写操作地址没有冲突(即地址没有重叠或不相等),则读操作可以在写操作之前发生(即乱序执行)。
- 在前面的分支指令被计算决断之前,可以投机式地执行读操作。
- 以乱序且可以重叠的方式处理缓存未中情形
读操作不可以:
- 投机读不能产生任何处理器故障或陷阱
- 投机读不能访问非缓存的(uncacheable)存储器区域。
通常,读存操作时延是5个周期。当使用简单寻址模式时,即基址参量加上小于2048的位移量,这种类型的读存时延是4个周期。这种技术对指针追逐代码(pointer-chasing code)尤其有用。但是,由于执行栈旁路效应,整体时延会根据目标寄存器数据类型产生变化。
表:寻址模式对读操作的影响
Data Type/Addressing Mode | Base + Offset > 2048; Base + Index [+ offset] | Base + offset < 2048 |
Integer | 5 | 4 |
MMX, SSE, 128-bit AVX | 6 | 5 |
x87 | 7 | 6 |
256-bit AVX | 7 | 7 |
Stores
写存操作实际上分两个阶段执行:
- 执行阶段。把写操作的线性地址,物理地址,与数据填充到写存缓冲区。一旦地址和数据可用(即位于写存缓冲区中),数据即可被转发给后续需要的读存指令。
- 完成阶段。在写存指令退役后, L1D将数据从写存缓冲区移到DCU,每周期最多16字节。
Address Translation
DTLB每个周期可以执行总共三个线性地址到物理地址的转换操作,两个为读存操作,一个为写存操作。如果要转换的地址不在DTLB中(即DTLB未中),处理器会继续查找STLB(同时保存指令页面与数据页面的转换信息)。如果DTLB未中但是STLB命中,性能损失是7个周期。除了4KB,2MB/4MB的页面,大页面转换支持还包括1GB页面。
表:DTLB和STLB参数
TLB | Page Size | Entries |
DTLB | 4KB | 64 |
| 2MB/4MB | 32 |
| 1GB | 4 |
STLB | 4KB | 512 |