Core 2的2级Cache
1级Cache分为 32KB L1i Cache和32KB L1d Cache,都是8路组相联write back buffer,64bytes per line,每个core拥有独立的L1 Cache,共享L2 Cache和总线接口, L2 Cache为16路组相联,64bytes per line,与L1 Cache之间的数据带宽为256bit。两个Core的L1d Cache之间可以互相传输数据,L1 Cache拥 有几个数据和指令硬件预取器,L2 Cache的预取器是基于L1 Cache预取器的访问模式和密集程度来工作的 ,使用了一个改进的Round-Robin算法动态的在两个处理器之间分配带宽。前端总线接口也采用了类似的 方式以确保平衡。L1 Cache和L2 Cache采用了独立访问设计,也就是说Core可以直接从L2 L1或Main Memory中直接取数据,无须逐级上升。intel cache使用了mainly inclusive设计,相比AMD使用的是 exclusive设计。
数据和指令地址对齐的重要性
现代微处理器架构在Load和Store内存时,如果访问地址为N的整数倍时,则可以一次操作N个字节(N = 2^M),但如果操作的N个字节处于的地址对N取余不为0,则需要2个或以上个时钟周期,特别是在地址跨越 了Cache Line后,性能影响更为严重。比如读取4 BYTE的int变量,如果此变量所在内存物理地址(注意 是物理地址,不是线性地址)正好为4的整数倍,则能高效的完成操作(处于同样的BUFFER中时)。而且 数据按其自然长度对齐还有一个好处就是将数据跨越Cache line的几率降到了最低(后面我们会详细讲到 Core微处理器架构的Cache工作原理)。既然对齐那么重要,那我们如何让数据位于对齐的地址上呢?
对于全局变量我们可以使用__declspec(align(N))来达到目的,当然也可以使用INTEL相关的一些类型 比如__m128,比如:
typedef __declspec(align(16)) int A16INT;
A16INT i;
现在这个变量i的地址就是16字节对齐的了。
对于位于堆栈中的变量特别复杂,当然我们同样可以使用__declspec(align(N))来对齐变量地址,但 需要提醒的是,microsoft visual c++ compiler 的默认堆栈对齐是4BYTE,但官方文档称编译器会智能 的判断数据组织,进行必要对齐转换,堆栈默认对齐相当诡异,我测试过跟编译优化选项有关系,实际上 变量在堆栈中的排列顺序与定义顺序通常是不一致的,而且也不敢保证struct的字节对齐,double在8字 节对齐除非手动加上__declspec(align(N)),在优化条件为/O2时,测试中显示堆栈都是自然长度对齐,仅 仅限于我的个人测试,我没有找到相关文档明确说明/O2条件下堆栈一定是数据自然对齐的,所以如果在 明确要求数据对齐的地方,还是要加上对齐标志。
动态内存分配的对齐
参考_aligned_malloc、_mm_malloc,如果用malloc分配的内存大小大于8,则内存是8字节对齐的,否 则为最小2的多次方对齐,比如如果分配7字节,则4字节对齐。
Pentium Pro, 2 and 3 pipeline