第二遍读这本书,每周花两到三小时时间,能读多少读多少(这次看了第 399~408 和 418~424 页,共 17 页)
第一遍对应笔记链接 https://www.cnblogs.com/stone94/p/10056104.html
各存储器速度差异的量化
CPU 访问一下设备中的数据分别需要的周期数
寄存器 0 个周期内
高速缓存 4~75 个周期
主存 上百个周期
磁盘 几千万个周期
理解存储器层次结果的实际作用
可以写出局部性好的程序,这样的程序运行的更快
RAM:Random-Access Memory,随机访问存储器
分为两类:
SRAM 静态 快 高速缓存
DRAM 动态 慢 主存
ROM:Read-Only Memory,只读存储器(注意:某些只读存储器既可以读也可以写,不要被名字迷惑)
硬盘就是 ROM 的一种
局部性
局部性通常有两种不同的形式:时间局部性和空间局部性
在一个具有良好时间局部性的程序中,被引用过一次的内存位置很可能在不远的将来再被多次引用
在一个具有良好空间局部性的程序中,如果一个内存位置被引用了一次,那么程序在很可能在不远的将来引用附近的一个内存位置。
有良好局部性的程序比局部性差的程序运行得更快。(局部性对程序员写程序的重要性)
现代计算机系统的各个层次,从硬件到操作系统、再到应用程序,它们的设计都利用了局部性。(局部性对计算机设计的重要性)
量化评价程序中局部性的一些简单原则
1、重复引用相同变量的程序有良好的时间局部性
2、对于具有不长为 k 的引用模式的程序,步长越小,空间局部性越好。具有步长为 1 的引用模式的程序有很好的空间局部性。在内存中以大步长跳来跳去的程序,空间局部性会很差。
3、对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。
缓存命中
当程序需要第 k+1 层的某个数据对象 d 时,他首先在当前存储在第 k 层的一个块中查找 d。如果 d 刚好缓存在第 k 层中,那么就是我们所说的缓存命中。
缓存不命中
相对于缓存命中,如果第 k 层中没有缓存数据对象 d,那么就是我们所说的缓存不命中。
缓存不命中的种类
区分不同种类的缓存不命中有时候是很有帮助的。如果第 k 层的缓存是空的,那么对任何数据对象的访问都会不命中。一个空的缓存有时被称为冷缓存,此类不命中称为强制性不命中或冷不命中。
由于发生不命中的情况是很正常的,所以在不命中发生的时候,必须有对应的放置策略。而如果采用最灵活的方式(即允许第 k+1 层的任何块放在第 k 层的任何块中),成本会比较高,因为随机地放置块,定位起来代价很高。因此,实际情况中,被使用的通常是更为严格的放置策略,即使第 k+1 层的块对第 k 层的块有一种“多对一”的映射关系(第 k+1 层的某几个块只能映射到第 k 层的某一个块中),这就会导致一种由放置策略引起的不命中,我们称之为冲突不命中。
要编写缓存友好的代码,需要遵从以下两点原则:
1、让最常见的情况运行的快。程序通常把大部分时间都花在少量的核心函数上,而这些函数通常把大部分时间都花在了少量循环上。所以要把注意力集中在核心函数里的循环上,而忽略其他部分。
2、尽量减小每个循环内部的缓存不命中数量。在其他条件相同的情况下,不命中率较低的循环运行得更快。