编写高速缓冲友好的代码
做一点总结
高速缓存运行机制简单介绍
一种层次存储结构,利用时间,空间局部性:
高速缓存通过 -直接映射高速缓存,-组相联高速缓存,-全相联高速缓存 三种方式在缓存中进行查找。
如果命中(hit)进行读或写包括write though,write back等方式进行后续处理。
若没命中(cache miss)有两种可能:冷不命中时执行放置策略,但是放置策略可能引起冲突不命中(即有空位但却不使用),不是空缓存的话会执行替换策略(有LRU,LFU,随机等方法)。同时有write allocate,not write allocate等方式进行后续处理。
评价高速缓存性能有命中率,不命中率,命中时间,不命中惩罚。
影响高速缓存性能的有 块的大小,相联度,写策略缓存大小等。
基本方法
- 关注核心函数的循环
- 在每个循环最内部的缓存不命中数量最小
- 对局部变量反复引用
- 以步长为1读取数据(因为所有层次上缓存都将数据存储为连续的块,空间局部性)
下面是一个计算矩阵乘积的函数的不同循环顺序(步长)简单对比,假设缓存块大小为32KB,n很大,数组类型为double:
1 | // ijk版本 |
| 每次迭代 | A不命中次数 | B不命中次数 | C不命中次数 | 总不命中次数 |
|---|---|---|---|---|
| ijk | 0.25 | 1 | 0 | 1.25 |
| jki | 1 | 0 | 1 | 2 |
| kij | 0 | 0.25 | 0.25 | 0.5 |
因为double长度是8个字节,所以每次加载4双字到高速缓存块中。然后可以看出kij的每次迭代不命中次数是最小的。