随机访问存储器 RAM
- 静态RAM 常用作Cache
- 动态RAM DRAM会因为泄漏电流各种因素在10~100毫秒失去电荷,但计算机运行是在纳秒级别。存储器系统会周期性读出再写入来刷新存储位,有些系统使用额外的位来提供纠错码,硬件级纠错。
DRAM的一种二维阵列组织
二维阵列组织读取,先接收行地址,将其对应行拷贝到内部行缓冲区,接收列地址,从缓冲区拷贝对就列单元发送至存储控制器。
磁盘以扇区大小的块来读写数据。对扇区的访问时间( access time)有三个主要的部分:寻道时间( seek time)、旋转时间(rotational latency〉和传送时间( transfer time ):
- 寻道时间
- 旋转时间:分最大旋转时间与平均时间,平均为max一半
- 传送时间:旋转时间 / 每圈磁道的扇区数
一般而言,层次结构中较低层(离CPU较远〉的设备的访问时间较长,因此为了补偿这些较长的访问时间,倾向于使用较大的块。
缓存
程序通常是按照一系列阶段(例如,循环)来运行的,每个阶段访问缓存块的某个相对稳定不变的集合。例如,一个嵌套的循环可能会反复地访问同一个数组的元素。这个块的集合被称为这个阶段的工作集
( working set)。当工作集的大小超过缓存的大小时,缓存会经历缓存不命中
(capacitymiss)。换句话说,缓存就是太小了,不能处理这个工作集。
一个空的缓存有时被称为冷缓存
(cold cache),此类不命中被称为强制性不命中
(compulsory miss)或冷不命中
(cold miss)。这通常是短哲的事件,不会在稳定状态中出现,稳定状态指的就是在反复的存储器访问已经将缓存变暖
( warmed up〉了之后。
冲突不命中
(conflict miss),缓存太小,有些转换策略会使缓存一直不命中。
高速缓存映射
当高速缓存确定一个请求命中时,抽取出被请求的字的过程,分为三步:①组选:②行匹配:③字拾取。
用中间位来索引更好
:为了提高高速缓存的效率(在一个拥有较好空间局部性的程序中,可能只访问第一组缓存),使存入的数组相邻的的块总是存入不同的高速缓存行上。
术语"抖动
"(thrash)描述的是这样一种情况,其中高速缓存反复地加载和驱逐高速缓存块相同的组。来回存储x和y的内容的块,导致冲突不命中。
-
直接映射高速缓存
-
组相联高速缓存:这时有组内行替换策略。例如,最不常使用( least-frequently-used,LFU)策略会替换在过去某个时间窗口内引用次数最少的那―行;最近最少使用(least-recently-used,LRU)策略会替最后一次访问时间最久远的那一行。所有这些策略都需要额外的时间和硬件。但是,越往存储器层次结构下面走,远离CPU,一次不命中的开销就会更加昂贵,用更好的替换策略使得不命中最少也变得更加值得了。
-
块相相关高速缓存:因为高速缓存电路必须并行地搜索许多相匹配的标记,构造一个又大又快的相联高速缓存很困难,而且很昂贵。因此,全相联高速缓存只适合做小的高速缓存,例如虚拟存储器系统中的翻译备用缓冲器(TLB),它缓存页表项。
写相关
假设CPU写一个已经缓存了的字 w [写命中
( write hit)]。在高速缓存更新了它的w的拷贝之后,更新w在存储器中的拷贝
- 最简单的方法,称为
直写
( write-through),就是立即将w的高速缓存块写回到存储器中。虽然简单,但是直写的缺点是每条存储指令都会引起总线上的一个写事务。 - 另一种方法,称为
写回
( write-back),尽可能地推迟存储器更新,只有当替换算法要驱逐己更新的块时,才把它写到存储器。由于局部性,写回能显著地减少总线事务的数量,但是它的缺点是增加了复杂性。高速缓存必须为每个高速缓存行维护一个额外的修改位(dirty bit)
,表明这个高速缓存块是否被修改过。
写不命中
- 一种方法,称为
写分配
( write-alocate),加载相应的存储器块到高速缓存中,然后更新这个高速缓存块。写分配试图利用写的空间局部性,但是缺点是每次不命中都会导致一个块从存储器传送到高速缓存。写回高速缓存通常是写分配的。 - 另一种方法,称为
非写分配
( not-write-allocate ),避开高速缓存,直接把这个字写到存储器中。直写高速缓存通常是非写分配的。
通常,由于较长的传送时间,存储器层次结构中较低层的缓存更可能使用写回,而不是真写。例如,虚拟存储器系统(用主存作为存储在磁盘上的块的缓存)只使用写回。
高速缓存既保存数据,也保存指令。只保存指令的高速缓存称为i-cache
。只保存程序数据的高速缓存称为d-cache
。既保存指令又包括数据的高速缓存称为统一的高速缓存
(unified cache)。一个典型的桌面系统CPU芯片本身就包括一个L1 i-cache
和个L1 d-cache
。
性能影响分析
-
高速缓存大小的影响
一方面,较大的高速缓存可能会提高命中率。另一方面,使得大存储器运行得更快总是要难一些的。结果,较大的高速缓存可能会增加命中时间。对于芯片上的 Ll高速缓存来说这一点尤为重要,因为它的命中时间必须为一个时钟周期。 -
块大小的影响
大的块有利有弊。一方面,较大的块能利用程序中可能存在的空间局部性,帮助提高命中率。不过,对于给定的高速缓存大小,块越大就意味着高速缓存行数越少,这会损害时间局部性比空间局部性更好的程序中的命中率。较大的块对不命中处罚
也有负面影响,因为块越大,传送时间就越长。现代系统通常会折中,使高速缓存块包含4~8个字。 -
相联度的影响
较高的相联度(也就是E的值较大)的优点是降低了高速缓存由于冲突不命中出现抖动的可能性。较高的相联度会增加命中时间,因为复杂性增加了.另外,还会增加不命中处罚
,因为选择牺牲行( victim line)的复杂性也增加了。 -
写策略的影响
直写高速缓存比较容易实现,而且能使用写缓冲区
(write buffer),它独立于高速缓存,用来更新存储器。此外,读不命巾开销没这么大,因为它们不会触发存储器写。另一方面,写回高速缓存引起的传送比较少,它允许更多的到存储器的带宽用于执行DMA的IO没备。此外,越往层次结构下面走,传送时间增加,减少传送的数量就变得更加重要。一般而言,高速缓存越往下坛,越可能使用写回而不是直写。
存储器山
步长轴方向表示为空间局部性斜坡,为读取数组内容的循环步长
工作集轴方向表示为时间局部性斜坡,因为是不同的缓冲级别
实验代码
wget http://csapp.cs.cmu.edu/3e/mountain.tar
tar -xvf mountain.tar
cd mountain/
./mountain > text.txt
实验中cpu数据
[tom@tom-virtual-machine ~]$lscpu
Architecture: x86_64
CPU 运行模式: 32-bit, 64-bit
CPU MHz: 2808.000
L1d 缓存: 32K
L1i 缓存: 32K
L2 缓存: 256K
L3 缓存: 6144K
...
[root@tom-virtual-machine ~]#cat /proc/cpuinfo
model name : Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
...

AB型 sum += A[i][k] * B[k][j]; 步长1扫描A的一行(因为在最外循环i固定,k切分); 以步长n扫描B的一列(列j固定,k取n行)
(ijk)
for (i = 0; i < n; i++)
for (j = 0; j< n; j++){
sum = 0.0 ;.
for (k = 0 ; k < n; k++)
sum += A[i][k] * B[k][j];
c[i][j] += sum;
}
(jik)
for (j = 0; j< n; j++)
for (i = 0; i < n; i++){
sum = 0.0 ;.
for (k = 0 ; k < n; k++)
sum += A[i][k] * B[k][j];
c[i][j] += sum;
}
AC型 c[i][j] += A[i][k]*r; 步长n扫描A的列(因为在最内循环列j固定,i取n行); 以步长n扫描C的列
(jki)
for (j= 0; j < n; j++)
for (k = 0 ; k < n; k++ ) {
r = B[k][j];
for (i = 0; i < n; i++ )
c[i][j] += A[i][k]*r;
}
(kji)
for (k = 0 ; k < n; k++ )
for (j= 0; j < n; j++){
r = B[k][j];
for (i = 0; i < n; i++ )
c[i][j] += A[i][k]*r;
}
BC型 c[i][j] += r*B[k][j]; 步长1扫描B的列(因为在最外循环k固定,j切分); 以步长1扫描c的列
(kij)
for (k = 0; k < n; k++)
for (i = 0; i < n; i++ ) {
r = A[i][k];
for (j = 0; j < n; j++)
c[i][j] += r*B[k][j];
}
(ikj)
for (i = 0; i < n; i++ )
for (k = 0; k < n; k++){
r = A[i][k];
for (j = 0; j < n; j++)
c[i][j] += r*B[k][j];
}
假设只能存数组的四个内容
- 注意高速缓存不命中率并不是问题的全部,存储器访问的数量也很重要,需在二者中权衡,来达到最优性能。