自用复习
这一篇是在备考的时候边想边做的笔记,考试的时候这章知识的大题基于本篇和课后题基本可以完全解决。
5.1 cache基本原理
cache位于CPU和主存之间,CPU与cache之间传送单位为字,cache与主存之间传送单位为块,一个块里通常包含多个字,一个字包含4个字节,共32bit
cache存储的是主存中最活跃的内容,是主存的复制品
CPU访问主存:将字对应的地址同时传送给cache和主存,若在cache中命中,那么立即将存储的数据传送给CPU,否则用主存读周期将主存中该字所在的块送到cache中
5.2 cache和主存的编址
5.2.1 主存地址
主存中存储着若干二进制数据,现以字节为单位对这些数进行地址编辑,一个字节分配一个地址
具体的划分中,主存中的数据被划分为几个块,那么如果想在主存中找到特定的字节,首先需要知道它在哪个块,其次在块里的哪个字,最后是字中的哪一个字节。
假设一个主存被分为M(=2^m)个块,一个块里有B(=2^b)个字,一个字有4(=2^2)个字节(字是以4字节的倍数对齐的,每个地址至少有两个位来指定字中的字节,因此当选择块中一个字时低两位常被忽略),给这M块编号显然需要m位,同理有b位,2位
由此引申出主存的基础地址组成:
主存块编号(m bit)+块内字编号(b bit)+字内字节编号(2 bit)
5.2.2 cache地址
cache是一个复制品,编址与主存自然是类似的
将cache划分为几行,每行内存储的内容与对应的主存里一个块里的内容相同
那么对于在cache里寻找一个字节也需要对行编号,对行里字编号,对字中字节编号
假设一个cache被分为C(=2^c)个行,一个行里有B(=2^b)个字,一个字有4(=2^2)个字节
由此引申出cache的基础地址组成:
cache行编号(c bit)+块内字编号(b bit)+字内字节编号(2 bit)
5.3 映射方式
5.3.1 直接映射
意思是主存中的一个块只对应cache中特定的一行
映射关系实际上是指块对应的行编号值是该块编号的一个函数
设块编号为bar,cache中共c行,那么其对应cache里的行编号row为:
row=bar mod c
显然,这并非一对一的映射,而是一对多的关系,cache中的一个位置可能对应主存中多个不同的地址,如下图:
那么要知道cache中的这个数是不是就是我们要访问的主存里的这个数还需要进一步的比对,这样需要给行里存储的东西在数据本身外引入新的部分,称为标记(tag),标记只需包含对应块地址中的高位,即没有用来索引cache行的那些位。
由于处理器刚启动时cache里没有数据,标记段也是没有意义的,这时一般还要给行里引入1位有效位来判断行里的数据是否有效
(直接映射)eg1. 当前主存地址为32位,按字节编址,cache有2^n行,块大小为2^m个字,现求cache总容量
主存地址中可以提取出字编号,字节编号,块编号的后几位用于索引行,其他部分是tag
cache里有2^n行,所以索引行要n位;
字编号m位,字节编号2位
tag就需要32-n-m-2位
那么对应的cache一行具体的分配就是:
①存储数据本身的所需:2^m · 2^2 · 8=2^(m+5) bit
②tag所需:32-n-m-2 bit
③有效位所需:1 bit
cache总容量就是:2^m · (2^(m+5) + 32-n-m-2 + 1) bit
(直接映射)eg2.(和P290对比,P290给出的地址是按字编址得到的地址,同时一个块里存一个字,实际上就是块编号,自然可以取低三位直接得到对应的行号)
这里给的是字节地址,一个块里也存了不止一个字
一个块16byte,因此块编号为1200/16=75
对应行编号75 mod 64=11,存在第11行
1200 D=0100 1011 0000 B,实际上的主存地址里的用来索引的位数显然不是低几位,tag和索引的那几位似乎是5.2.1中块编号的拆分
那么怎么理解0100 1011 0000呢?
计算机似乎是从高几位敲定了块编号,显然的,0100 1011 B=75 D,其低6位
001011 B =11 D,和计算结果相同。如果这里也采取的是一个字四个字节的存储方式,总的低2位00就是字节编号,3、2位的00就是字编号。实际上知道了一个块有16(2^4)字节,总的地址去掉低4位就是前面我们需要的部分,取高多少位,这个“多少”在块大小明确的情况下也是明确的,这和直接映射的地址分析也是吻合的。
5.3.2cache缺失处理
cache缺失引起流水线阻塞
首先讨论指令缺失。
指令访问引起一次缺失,那么指令寄存器中的内容无效。
为将正确的指令取回cache,必须通知存储器层级结构中较低层次进行一次读操作。由于在执行的第一个时钟周期,程序计数器已经进行自加运算,因此产生缺失的指令地址等于程序计数器中的值-4 。当地址产生时,就可以通知**主存**执行一次读操作,并且等待存储器的响应,然后把取回的字写入cache.
那么步骤就是:
5.3.3写操作处理(写缺失和数据缺失?)
讨论store指令。
只将该数据写入数据cache,再写入后主存与cache中相应的数据不相同,这种情况就产生了不一致
保持两者一致的最简单的方法就是将这个数据同时写入cache和主存,这种方法称为写直达。
在写直达的机制下,在cache里分配一块,从主存中取出包含所需字的块,数据块被取回并存入cache中后,我们就可以将引起缺失的字重新写入cache这个分配好的块的恰当位置中,同时我们用全地址将该字写入主存。
写直达简单但是耗时巨大,若10%的操作是store指令,无cache缺失的情况下CPI=1,每次写操作引起额外花费的100个周期,那么新的CPI=1+100*10%=11,性能降低10倍多。这种情况可以用写缓冲解决。
线多采用写回的方式解决不一致。
写回机制下,写操作时新值仅仅被写入cache,只有当修改过的块被替换时才需要写到较低层次的存储器中。
5.3.4 cache性能的评估与改进
性能改进技术:
1.减少存储器中不同数据块争用cache中同一位置的概率来降低缺失率
2.在存储器结构中额外增加一层,多级高速缓存技术
CPU时间=(CPU执行时钟周期数+存储器阻塞的时钟周期数 )· 时钟周期
存储器阻塞的时钟周期数=读操作引起阻塞的时钟周期+写操作引起阻塞的时钟周期
写操作引起阻塞的时钟周期=[(写的次数/ 程序数)· 写缺失率· 写缺失代价(处理写缺失需要的时钟周期)] + 写缓冲区阻塞
写缓冲区阻塞不仅仅取决于频率,还取决于写操作的执行时间,故不能由一个简单公式来计算
读操作引起阻塞的时钟周期=(读的次数/ 程序数)· 读缺失率· 读缺失代价
在大部分写直达cache结构中,读和写的缺失代价是一样的(都是从主存中取回数据块的时间)。如果假设写缓冲区阻塞可以被忽略,那么我们可以合并读写操作并共用一个缺失率和缺失代价:
存储器阻塞时钟周期数=(存储器访问次数 / 程序数)· 缺失率 · 缺失代价。
也可以表示如下:
存储器阻塞时钟周期数=(指令数/程序数)·(缺失数 / 指令)· 缺失代价。
平均存储器访问时间:AMAT = 命中时间 + 缺失率 · 缺失代价
5.3.5 全相联映射
主存中的每一个块对应到cache中的任意一行
标记存放的是该内容对应的主存中的块编号
缺点:标记位数增加,需要把主存的块和cache的行全部进行比较,加大了硬件开销
5.3.6组相联映射
映射思路:结合直接和全相连,组间直接映射,组内全相联映射
即根据索引字段,主存中的每个块对应cache中唯一的组,并且可以放到这个组中的任何一个位置上
此时匹配方式就变成了,先由块编号找到cache的组编号,再检索组中的所有行看是否命中
假设cache被分为Q(=2^q)组,每组包含R(=2^r)行,即R路组相联,则cache一共有Q✖R行,主存中某一字节地址中块编号为bar,对应的cache组编号为set,则映射关系为:
set=bar mod Q
如图所示,一个2路组相联:
在对主存地址的划分上与直接映射类似,但用来索引的部分应该根据有几组来确定,在上面的假设中,32位地址里用来索引组的位数应为q bit
(cache的缺失和相联度)eg.
显然这道题默认了字节编址
2路组相联采取最近最少替换原则,具体实现中“最少”优先级似乎高于“最近”
倘若cache扩充到8行,2路组相联缺失下降到3次,扩大到16行则以上三种映射方式缺失率相同,由此得判断cache性能时容量和相联度不能分开考虑
5.4 替换块的选择
组相联常用LRU法(最近最少替换法)
使用多级cache减少缺失代价
一级cache缺失时就去访问二级cache,如果二级中包含这个数据,就比访问主存快得多,这里一级相当于二级的一个"cache";但如果一二级均不包含,将会产生大得多的缺失代价
一级cache致力于减少命中时间以获得较短的时钟周期或较少的流水级,二级cache则侧重于改善缺失率以减少长时间的访存代价
多级cache的一级cache通常很小,与较小的容量相匹配的是缺失访问代价也小;而二级主要是改善缺失率,因此二级容量要大得多,相联度也更高
现评估使用二级cache后的缺失代价。
(多级cache的性能)eg.P307
处理器基本CPI:1
若所有指令在一级cache均命中,时钟频率4GHz
主存访问时间:100ns,包括缺失处理时间
设一级cache中每条指令缺失率为2%,现增加一二级cache,命中或缺失访问时间都是5ns,且容量大到使必须访问主存的缺失率降到0.5%
应该计算CPU时间
CPU时间=(CPU执行时钟周期数+存储器阻塞的时钟周期数 )· 时钟周期
一级cache总归都是要访问的,所给的时钟频率实际是将一级访问时间全部算上的情况,此时CPU时钟周期:1/4GHz=0.25ns,访问主存将产生额外的100/0.25=400个时钟周期
设共有i条指令,那么只有一级cache时,CPU时间为:(i+0.02i* 400)*0.25=(2.25i) ns
加入二级cache,CPU时间为:(0.02i *(5/0.25)+i+0.005i * 400) *0.25= (0.85i) ns,这里要注意那百分之二的缺失都要访问二级,然后总指令的0.5%最终需要访问主存,所以诸如“0.015i *20是错误的二级访问耗时
加速比为:2.25/0.85≈2.647
5.5 虚拟存储器
5.5.1虚拟存储器基本原理
基于程序局部性原理,与cache的构建很类似
可以将物理存储器看作是虚拟存储器的一个”cache "
虚拟存储器中块称为页,访问缺失称为缺页
虚拟存储器和物理存储器都被划分成页,因此一个虚拟页被映射到一个物理页
在虚拟存储器中,处理器产生一个虚拟地址,由软件和硬件结合,将其转换成一个物理地址,然后用来访问主存
当然一个虚拟页也可能不在主存中,因此无法映射到物理地址,在这种情况下,页存到磁盘上
物理页可以被两个指向相同物理地址的虚拟地址共享
5.5.2虚拟存储器编址
5.5.3页的存放和查找
在虚拟存储系统中,用一索引主存的表来定位页,这种结构称为页表,页表存放在主存中
硬件包含一个指向页表首地址的的寄存器,称为页表寄存器,虚存页号(可以类比于之前提到的块编号,行编号)+页面基地址就定位到页表中相应的位置,如果该页在主存中也有对应的页,那么有效位有效,并且该项里有主存的页号,而这就是实际主存中完整的物理页编号,因此并不需要cache中的所谓tag位来进一步确定;反之则有效位无效,发生一次缺页
5.5.4 缺页故障
对应页表中有效位无效—>产生缺页故障—>由异常机制将控制权转移给操作系统—>操作系统在下一级存储系统中(即先前提过的磁盘)中找到该页,并决定将该页放到主存中的哪个位置
Q1:虚拟地址并不会直接反映该页在磁盘中的哪个位置,因此在虚拟存储系统中我们必须保持跟踪记录虚拟地址空间的每一页在磁盘上的位置
solve:创建一个数据结构来记录每个虚拟页在磁盘中的存放位置
Q2:当一次缺页发生时,如果主存中所有的页都已经被使用,操作系统仍必须选择一页进行替换,但事先操作系统无法判断物理存储器中的哪一页会被替换出去
solve:在创建进程时通常在磁盘上为进程中所有页创建一个交换区
Q3:必须要替换时遵循哪种策略
solve:LRU最近最少替换策略。被替换的页写入磁盘的交换区
5.6 TLB
5.6.1TLB基础
页表放在主存中,所以每次访问至少需要2次:
1 :访问页表相应的页来获得实际主存中的物理地址(物理页编号)
2 :通过取得的物理地址访问主存并获得数据
现要提高访问性能,从页表访问的局部性入手:由于页表访问的时间局部性和空间局部性,一个转换的虚拟页号被使用时,在将来不久的时间内也很可能被再次用到。那么是不是可以参考cache与主存,做一个页表的”cache“,这样得到物理地址这一步骤就不用进入主存才能实现了
实际上,现代处理器均包含一个特殊的cache用以追踪最近使用过的地址变换,这个特殊的地址转换cache称为TLB(快表)
TLB存储构成:
TLB的标记项存储的是虚拟页编号的一部分,数据项为对应的物理页面编号
每次访问,我们都要在TLB中查找虚页号。如果命中,物理页号就用来形成地址,相应的引用位被置位。如果处理器执行的是写操作,脏位同样要被置位。如果TLB发生缺失,我们必须判断是发生缺页还是仅仅是一次TLB缺失。如果该页在主存中,那么TLB缺失只是一次转换缺失。在这种情况下,处理器可以通过将页表中的变换装载到TLB中并且重新访问来进行缺失处理。如果该页不在主存中,TLB缺失就是一次真的缺页。在这种情况下,处理器调用操作系统的异常处理。由于TLB中的项比主存中的页数少得多,发生TLB缺失会比缺页频繁得多。
5.6.2 TLB缺失
TLB中若无一个表项能匹配虚拟地址时,TLB缺失就会发生
TLB缺失有两种可能性:
1.页在主存中,只需创建缺失的TLB表项
2.页不在主存中,执行5.5.4中应对缺页的步骤,并更新页表和TLB的地址
fastmath虚存地址 TLB 物理地址 cache 之间的关系(此处虚拟和物理地址等长):
P329问题?
1.直接映射,块,页大小相同时,物理页号是否等同于块编号?若果是,物理页号的位数应该=物理地址标记+cache索引号,物理地址标记就是tag,cache索引就是cache行号?
2.块偏移是什么?不是字偏移吗?
3.以上成立还会有一个问题,下面例子中页偏移计算位数到了byte,这样的话页偏移所需位数=字偏移+字节偏移,是这样吗?
(TLB页表)eg.
将16进制地址转为2进制,页表大小32KB(字节单位),页偏移占2^5*2^10共15bit。先在TLB中寻找,V=0或者全部搜索后无tag 对应则去页表中找,找到了根据LRU原则替换(LRU这一行数值越大说明哪个很久没有被使用,则优先替换这个部分)
5.7存储层次的一般框架
cache,TLB和虚拟存储器的理解:
Q1 一个块可以被放在何处?
A1 一个位置(直接映射),一些位置(组相联),任意位置(全相联)
Q2 如何找到一个快?
A2 ①索引(直接映射的cache):需比较1次
②有限的查找(组相联映射):需比较与相联度一样多的次数
③全部查找(全相联映射):需比较次数取决于cache的容量
④单独的查找表(页表):需比较0
Q3 cache中缺失时应该替换哪一行?
A3 最近最少或者随机的一行
Q4 写操作如何处理?
A4 写直达or写回。虚拟存储器中,由于写磁盘的延迟很大,因此只有写回策略是可行的
3C模型
将存储器各层的缺失分为三类(compulsory\capacity\conflict)
1.强制缺失(compulsory miss)
从未在cache中出现的块第一次访问引起的缺失
2.容量缺失(capacity miss)
cache容纳不了一个程序执行所需要的所有块,某些块被替换出去,随后再被调入产生容量缺失
3.冲突缺失(conflict miss)
组相联或者直接映射的cache中多个块竞争一个组引起的缺失,在全相联中不存在
根据3C模型提出降低缺失率的策略:
增加块的容量和预取都可以减少强制缺失