随机存取内存(RAM):静态(SRAM)和动态(DRAM)。
静态(SRAM)
(1)静态RAM(SRAM)比动态RAM(DRAM)更快更贵。
(2)SRAM用于寄存器和高速缓存;DRAM用于主存。系统最多只有几兆字节的SRAM,但却有几百或几千兆字节的DRAM。
静态RAM双稳态的特性:
静态RAM的电路能够无限期地保持在两种不同的电压配置中。任何其他状态都将不稳定—从那个状态开始,电路将迅速移动到其中一个稳定状态。由于其双稳态的特性,只要保持通电,SRAM记忆单元将无限期地保持其值。与DRAM不同,SRAM不需要刷新。SRAM的访问速度比DRAM快。
动态RAM(DRAM)
每个单元由一个电容器和一个单独的访问晶体管组成。DRAM记忆单元对任何干扰都非常敏感,DRAM单元在大约10到100毫秒的时间内失去电荷。内存系统必须定期刷新每一个内存位,通过读取然后重写来完成。
在DRAM芯片中,存储单元(位)被划分为d个超级单元,每个超级单元由w个DRAM单元组成。一个d×w的DRAM总共存储dw位信息。这些超级单元被组织成一个矩形数组。
信息通过称为引脚的外部连接器进出芯片,每个引脚携带1位信号每个DRAM芯片都连接到某些电路,称为内存控制器。该控制器可以一次从每个DRAM芯片传输w位。为了读取超级单元(i,j)的内容,内存控制器先发送行地址i到DRAM,随后发送列地址j。
DRAM通过将超级单元(i,j)的内容发送回控制器来响应。
行地址i称为RAS(行访问选通)请求,列地址j称为CAS(列访问选通)请求。
DRAM组织为二维数组,这样可以减少芯片上的地址引脚数量。
二维数组组织的缺点是地址必须在两个不同的步骤中发送,这增加了访问时间。
DRAM被封装在内存模块中,这些模块插主板上的扩展槽中。
2.1 引言
计算机先驱准确预测到程序员会希望拥有无限数量的快速存储器。满足这一愿望的一种经济型解决方法是存储器层次结构。基于局部性原理下和“在给定实现工艺和功耗预算下,硬件越小,速度越快”的指导原则,产生了存储器层次结构,这些层次由速度和容量各不相同的存储组成。
因为快速存储器非常昂贵,所以存储器层次结构被分为几个级别--离处理器越近,容量越小,速度越快,每字节的成本越高。存储器的终极目标是提供一种存储器系统,每字节的成本几乎与最便宜的存储器级别相同,而速度几乎与最快的存储器级别相同。在大多数情况下,低层级存储器中的数据是上一级存储器中数据的超集,这一性质被称为包含性质,则层次结构的最低级别必须具有包含性质。
尽管处理器请求速率和存储器访问速率的差距多年来显著增大,但由于单处理器的性能没有大幅提升,导致处理器与DRAM之间的差距的增速放缓。
因为高端处理器有多个核,所以带宽需求大于单核处理器。intel core i7 6700有4个核,每个核每周期会产生2次访问存储器的请求,时钟频率为4.2GHz。每秒最多生成328(4.2*2*4)亿次64位数据访存,总峰值带宽为409.6GB/s,这一难以置信的高带宽是通过以下方式实现的:缓存的多端口和流水线;利用三级缓存。
传统上,存储器层次结构的设计人员把重点放在优化存储器的平均访问时间上,这一时间是由缓存命中时间、缺失率和缺失代价决定的。但最近功耗已经成为设计人员的主要考虑事项,包括不执行操作时候的漏电功耗(静态功耗)和执行读写时候的有效功耗(动态功耗),在PMD的处理器中,缓存功耗可能占到总功耗的25%~50%。
存储器层次结构基础:快速回顾
若缓存缺失,出于效率原因,会一次从下一级存储结构提取多个字,这称为块(行)。这样做还有另外一个原因:局部性原理。每个缓存块都包含一个标签tag,用来指明它与那个存储器地址相对应。
在设计时需要考虑一个非常重要的决策:那些块可以放在缓存中。最常见的是组相联,其中组是指缓存中的一组块。一个块首先被映射到一个组上,然后将这个块放在这个组中的任意位置。要查找一个块,首先将这个块的地址映射到这个组,然后在搜索这个组(通常是并行搜索)。这个组是根据数据地址选择的:
块地址 MOD(缓存中的组数)
如果组中有n个块,则缓存的布局称为n路组相连。组相连的端点有自己的名字。直接映射缓存的每组中只有一个块(所以块总是放在同一个位置),全相连缓存只有一个组(所有块可以放在任何地方)。
向缓存中写入数据难一些,比如缓存副本和存储器怎样才能保持一致?主要有2种策略。一种是写直达缓存,当它更新缓存中的条目时(若存在),会同时将数据写入主存储器中,并对其进行更新。另一种是写回缓存,仅更新缓存中的副本。在要替换这个块时,再将它复制回存储器。这两种写入策略都可以使用写缓冲区。
衡量不同缓存组织方式优劣的一个指标是缺失率。缺失率是指那些未能找到预期目标的缓存访问所占的比例,即未找到目标的访问数目除以总访问数目。
为了深入理解造成高缺失率的原因,3C模型将所有缺失情景分为以下3种情况:
(1)强制缺失:对数据块的第一次访问肯定不会在缓存中,所以必须将这个块放入缓存中。即使拥有无限大的缓存,也会造成强制缺失。
(2)容量缺失:如果缓存不能包含程序运行期间所需要的全部块,就会因为有些块先被丢弃之后然后再被调入而导致容量缺失(除了强制缺失之外)。
(3)冲突缺失:如果块放置策略不是全相连的,并且多个块映射到一个块的组中,对不同块的访问混杂在一起,那么一个块可能会被丢弃,之后再被调入,从而发生冲突缺失(除强制缺失和容量缺失之外)。
多线程和多核增加了缓存的复杂性,即增大了发生容量缺失的可能性,又因为缓存刷新而增加了第4种C缺失--一致性缺失。
然而,缺失率可能因为多个原因而产生误导。因此,一些设计人员喜欢测量每条指令的缺失次数,而不是每次存储器访问的缺失次数。(通常采用整数,而不是分数,比如每千条指令的缺失数)
缺失次数/指令数 = 缺失率*存储器访问次数/指令数
以上指标的问题在于,它们都没有考虑缺失代价。存储器平均访问时间:
存储器平均访问时间 = 命中时间+缺失率*缺失代价
命中时间是指在缓存中命中目标的时间,缺失代价是将块从存储器读取到缓存所需要的时间(即缓存缺失的开销)。存储器平均访问时间仍然是一个间接的性能测量指标,尽管它比缺失率好一些,但不能替换执行时间。支持推测执行的处理器可以在缺失期间执行其他指令,从而降低实际缺失代价。使用多线程也允许处理器容忍一些缺失,而不会被强制转入空闲状态。
附录B中缓存优化方法:
(1)增大缓存块以降低缺失率。降低缺失率的最简单办法是利用空间局部性,并增大块的大小。使用较大的块可以减少强制缺失,但也增加了缺失代价。因为较大的块意味着较少的标签,所以略微降低静态功耗。较大的块还会增加容量缺失或冲突缺失,特别是当缓存块的容量较小时。
(2)增大缓存以降低缺失率。要减少容量缺失,一种显而易见的方法是增大缓存容量。缺点包括延长缓存命中时间,增加成本和静态/动态功耗。
(3)提高相连度以降低缺失率。提高相连度可以减少冲突缺失。较大的相连度是以延长命中时间和增大功耗为代价的。
(4)采用多级缓存以降低缺失代价。是加快缓存命中速度,跟上处理器的高速时钟频率,还是加大缓存,以缩小处理器访问和主存储器访问之间的差距?第一级缓存可以小到足以匹配快速的时钟周期,而第二级或第三级缓存大到足以捕获许多本来要对主存储器的访问。为了