diff --git a/W7D1.md b/W7D1.md new file mode 100644 index 0000000..a12bc36 --- /dev/null +++ b/W7D1.md @@ -0,0 +1,68 @@ +# Reduce the miss rate + +## 7.reducing misses by compiler optimization + +### 7.1 merging arrays example +``` +/* Before: 2 sequential arrays */ +int val[SIZE]; +int key[SIZE]; + +/* After: 1 array of stuctures */ +struct merge { + int val; + int key; +}; +struct merge merged_array[SIZE]; +``` +分析:增加了空间局部性,减少了潜在的val与key竞争同一index导致的cache conficts. + +### 7.2 loop interchange example +``` +遍历a[i][j]时 +Before: 外层循环枚举j,内层循环枚举i +After: 外层循环枚举i,内层循环枚举j +``` +分析:由二维数组在内存中的存储方式,可知后者有更好的空间局限性,cache miss rate更低 + +### 7.3 Blocking example +``` +计算矩阵乘法A = B * C +Before: 三层循环,i,j分别枚举A的行列,k枚举做内积的两个向量的下标 +After: 五层循环,先将原来的B和C划分为更小的矩阵,而每个子矩阵块在一段时间内被频繁使用,之前之后不被使用 +增大了数据局限性(题外话:同时可能具有更好的并行性) +``` + +## 一个衔接性的问题 +``` +Q: 随着miss rate变大,我们为什么不考虑把一级cache做的更大,而是转而设计二级缓存这类分层次的架构? +A: 容量大与速度快不可兼得(*后续举了一个例子)。如果无限制地加大一级缓存,虽然miss rate变低了, +但是hit情形下所需时间也在增大,总体来说得不偿失。alei如是说:“目前容量越来越大,未来的存储结构一定是不断往层次化方向发展的” + +简单例子如下:考虑输入一个4位的信号,要求选中16条可能的线中唯一与之对应的线,要做到这一点需要4层逻辑判断。 +如果一级缓存变得过大,那么用以表征位置的位数也越大,故时间开销也越大。 +``` +还讲了一些简明公式: +AMATL1+L2 = Thit-L1 + Pmiss-L1 * (Thit-L2 + Pmiss-L2 * Tpenalty) +若只有一二级缓存, 其中Tpenalty = AMATM = Taddr + Taccess + Ttrans + +# Reduce the miss penalty + +miss 之后从缓存到内存之间这一段路程是我们现在需要讨论的 + +## write policy : write through vs write back +``` +write through中,所有的写操作都会同时更新缓存和底层内存或高速缓存, +write back中,只在缓存中更新,并引入一个dirty位标记表示当前缓存数据被更改过,只有当此缓存被替换时才会更新底层内存或高速缓存 + +前者缓存管理更简单,但是对于带宽要求高,同时对于高延迟内存的容忍性较差 +``` + +## Read Priority over Write on Miss +考虑write back策略中以下情形:如果read过程中miss了,并且对应Index中valid位为1,dirty位为1 +``` +(1)方案一:从内存中取出所需数据之后不能直接写入缓存行,而是先将脏位的缓存行写入内存,腾出位置之后再写入缓存行 +(2)方案二:设置一个Write buffer放脏位的缓存行,之后从内存取所需数据以及将脏位的缓存行写入内存的操作可以并行进行, +由于buffer已经存放了脏位的缓存行数据,不再存在写缓存要等写内存完成之后才能进行的说法。 +``` +方案二采用一个非常自然的优化,将上述情形所需的时钟周期直接砍半 \ No newline at end of file