找出全书你认为学得最差的一章,深刻从新学习一下,要求(期末占5分):html
实际上,存储器系统是一个具备不一样容量、成本和访问时间的存储设备的层次结构。java
存储器层次结构是可行的。总体效果是一个大的存储器池,其成本与层次结构底层最便宜的存储设备至关,可是却以接近于层次结构顶部存储设备的高速率向程序提供数据。git
计算机系统中一个基本而持久的思想:若是你理解了系统是如何将数据在存储器层次结构中上下移动的,那么你就能够编写你的应用程序,使得它们的数据项存储在层次结构较高的地方,在那里cpu能更快的访问它们。程序员
这个思想围绕着计算机程序的一个称为局部性的基本属性。编程
在本章中,咱们会看看基本的存储技术,并描述它们是如何被组织成层次结构的。数组
随机访问存储器分为两类:静态,动态。SRAM比DRAM更快,更贵。SRAM做为高速缓存存储器。DRAM做为主存。缓存
SRAM将每一个位存储在一个双稳态存储单元里。只要有电,它就保持他的值。安全
DRAM将每一个位存储为对一个电容的充电。DRAM单元在10-100ms内失去电荷,因此须要刷新或者其余的方法保证数据正确性。dom
DRAM表示通常写成NW,w是一个单元的位数,N是单元数。自己称这个单元是超单元。而后N又表示为rc,这样的表示是寻址的时候地址引脚不会太多,好比N=16,就要4个引脚。4*4的话,4须要两个引脚。可是这种二维阵列组织有个缺点:两步发送地址,增长了访问时间。分布式
DRAM的加强型有:FPM DRAM,EDO DRAM,SDRAM,DDR SDRAM(DDR,DDR2,DDR3),Random DRAM,VRAM。
PC使用的DRAM历史:95以前FPM,96-99EDO,-02SDRAM和DDR,-10DDR3。
非易失性存储器,SRAM和DRAM都是易失的。
ROM称为只读存储器是历史缘由,不少ROM都是可写的。ROM的分类是以它们可以被重编程(写)的次数和对他们进行重编程的机制来划分的。
ROM包括:PROM,EPROM,EEPROM,闪存(基于EEPROM)。
存储在ROM设备中的程序一般称为固件。
总线事物:读事物——从主存传送数据到cpu,写事物——从cpu传送数据到内存。
磁盘是广为应用的保存大量数据的存储设备:盘片,表面,主轴,RPM,磁道,扇区,柱面。
对于SRAM和DRAM,KMGT一般是1024为基,但对于磁盘,KMGT以1000为基。
像图形卡,监视器,鼠标,键盘和磁盘这样的I/O设备,都是经过I/O总线(PCI)链接到cpu和主存的。
系统总线和存储器总线是与cpu总线相关的,但pci这样的总线和底层cpu无关。
I/O总线老是比系统总线和存储器总线慢,可是它能够容纳种类繁多的第三方I/O设备。主机总线适配器将一个或多个磁盘链接到I/O总线,最经常使用的是SCSI和SATA,前者更贵,更快。
cpu使用一种称为存储器映射I/O的技术,在使用该技术的系统中,地址空间中有一块地址是为与I/O设备通讯保留的。每一个这样的地址称为一个I/O端口。当一个设备链接到总线上时,它与一个或多个端口相联系。
cpu从磁盘读数据时发生的步骤:cpu经过将命令、逻辑块号和目的存储器地址写到与磁盘相关联的存储器映射地址,发起一个磁盘读;磁盘控制器读扇区,并执行到主存的DMA传送;DMA传送完成时,磁盘控制器用中断的方式通知CPU。
现代磁盘将他们的构造呈现为一个简单的视图,一个B个扇区大小的逻辑块序列。磁盘控制器维护着逻辑块号和实际(物理)磁盘扇区之间的映射关系。这里看到,逻辑块对应扇区。
SSD包,由一个或多个闪存芯片和闪存翻译层组成。
存储器和磁盘技术的一个基本事实:增长密度比下降访问时间更容易。
DRAM和磁盘的性能滞后于cpu的性能。现代计算机频繁的使用基于SRAM的高速缓存,试图弥补处理器-存储器之间的差距。这种方法可行是由于应用程序的局部性。
一个编写良好的计算机程序尝尝具备良好的局部性。也就是说,他们倾向于引用临近于其余最近引用过的数据项的数据项,或者最近引用过的数据项自己。
这种倾向性,被称为局部性原理,是一个持久的概念,对硬件和软件系统的设计和性能都有着极大的影响。
局部性一般有两种不一样的形式:时间局部性和空间局部性。
二者的区别在于时间对的是一个存储器位置,空间对的是附近的存储器位置。
被引用过一次的存储器位置极可能在不远的未来再被屡次引用——时间。一个存储器位置被引用了一次,那么程序极可能在不远的未来引用附近的一个存储器位置——空间。
对于空间局部性,步长为1的引用模式称为顺序引用模式,这种模式具备最好的空间局部性,如数组,一个一个的顺序访问具备最好的空间局部性。
多维数组,按照行优先顺序,具备最好的空间局部性。
量化评价一个程序中局部性的简单原则:
存储器层次结构是组织存储器系统的方法,人想的,如今全部的计算机系统都使用了这种方法。
通常而言,高速缓存是一个小而快速的存储器设备,它做为存储在更大,也更慢的设备中的数据对象的缓冲区域。使用高速缓存的过程称为缓存。
存储器层次结构的中心思想是:对于每一个k,位于k层的更快更小的存储设备做为位于k+1层的更大更慢的存储设备的缓存。
也就是说层次结构的每一层都缓存来自较低一层的数据对象。
这里必须强调一下,这也就是说数据时不能够越级的吗?
数据老是以块大小为传送单元在第k层和第k+1层之间来回拷贝的。例子:L1和L0的传送是1个字的块,L2和L1之间是8-16个字的块。
一些概念:缓存命中,缓存不命中,牺牲块,替换策略,冷缓存,强制性不命中,冷不命中,放置策略,冲突不命中,容量不命中。
归纳来讲,基于缓存的存储器层次结构行之有效,是由于较慢的存储设备比较快的存储设备更便宜,同时,还由于程序每每展现局部性。
早期计算机系统的存储器层次结构只有三层:cpu寄存器,DRAM主存,磁盘。随着cpu和主存之间差距的逐渐增长,系统设计者被迫加入了SRAM高速缓存存储器,称为L1/L2/L3高速缓存。
L1一般须要2-4个时钟周期,L2一般须要10个时钟周期,L3一般须要30-40个时钟周期。
高速缓存存储器结构的一些细节:直接映射高速缓存,组相联高速缓存,全相联高速缓存。
高速缓存参数的性能影响:不命中率,命中率,命中时间,不命中处罚。
(这一节,了解一些硬件知识,结构的细节无论了)
局部性比较好的程序更容易有较低的不命中率,而不命中率较低的程序每每比不命中率较高的程序运行的更快。
下面就是咱们用来确保代码高速缓存友好的基本方法:
让最多见的状况运行得快。程序一般把大部分时间都花在少许的核心函数上,而这些函数一般把大部分时间都花在了少许循环上。
每一个循环内部缓存不命中数量最小。(对局部变量的反复引用是好的,步长为1的引用模式是好的)
存储器系统的性能不是一个数字就能描述的,相反,它是一座时间和空间局部性的山,这座山的上升高度差异能够超过一个数量级。明智的程序员会试图构造他们的程序,使得程序运行在山峰而不是低谷。
仍是这几项,推荐的技术:
将你的注意力集中在内循环上,大部分计算和存储器访问都发生在这里。
经过按照数据对象存储在存储器中的顺序、以步长为1的来读数据,从而使得你程序中的空间局部性最大。
一旦从存储器中读入了一个数据对象,就尽量多的使用它,从而使得程序中的时间局部性最大。
6.7 小结
程序经过编写良好的局部性代码利用好缓存。
1.随机访问存储器(RAM, Random-Access Memory)
2.DRAM阵列
3.访问主存
系统总线是一组并行的导线,能携带地址、数据和控制信号。可是不一样总线不能直接互通,这就用到了I/O桥。
寻道时间:将磁头定位到目标扇区所在的磁道。这个时间依赖于磁头以前的位置和传动臂在盘面上移动的速度。一般3~9ms。
旋转时间:找到目标所在的第一个扇区。性能依赖于当前到达的磁道上相对目标扇区的位置和磁盘的旋转速度。
传送时间:读写扇区内容的时间。依赖于旋转速度和当前磁道的扇区数目。
1.基本构造
(S, E, B, m),m是地址w的位长度。
容量计算:
高速缓存肯定一个请求是否命中,而后取出被请求的字的过程,分为三步:1)组选择,2)行匹配,3)字抽取。当且仅当设置了有效位,并且标记位与w地址中的标记位相匹配时才算命中。
2.分类
全相联高速缓存,只有一个组,全部的缓存行都在一个组里。
N=64时:
sumA: 1/4
sumB: 1
sumC: 1/2
N= 60时:
sumA ,sumB,sumC的缓存不命中率均为 1/4
比较难判断的是N = 60时sumB的缓存不命中率(sumC与sumB是同样的),我写了一个函数返回不命中次数,将形参n赋值60便可。
//高速缓存命中率函数,返回不命中次数 int noHitPercentage(int n) { //不命中的次数 int result = 0; //总共要循环的次数 int count; //存储块的标记位 int a[256]; for(int i =0;i < 256;i++) { a[i] = -1; } for(int j = 0;j < n;j++) for(int i = 0;i < n;i++) { //求出这个数的相对索引 count = i * n + j; //求这个索引对应的块号 int blockNo = (count/4) % 256; //求出标记t int t = (count/4)/256; //若是标记位不相等则不明中 if(t != a[blockNo]) { a[blockNo] = t; result++; } } return result; }
void betterTranspose(int *dst,int *src,int dim) { <span style="white-space:pre"> </span>int i, j; <span style="white-space:pre"> </span>int iCount,jCount; <span style="white-space:pre"> </span>//以4 * 4 的方阵为单位依次计算,增长了写的缓存命中率,多个元素一块儿读写还减小了循环开销 <span style="white-space:pre"> </span>for(i = 0;i < dim - 3;i += 4) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>iCount = i * dim; <span style="white-space:pre"> </span>for(j = 0;j < dim - 3;j += 4) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>jCount = j * dim; <span style="white-space:pre"> </span>dst[jCount + i] = src[iCount + j]; //dst[j][i] = src[i][j] <span style="white-space:pre"> </span>dst[jCount + i + 1] = src[iCount + dim + j]; //dst[j][i + 1] = src[i + 1][j] <span style="white-space:pre"> </span>dst[jCount + i + 2] = src[iCount + dim * 2 + j]; //dst[j][i + 2] = src[i + 2][j] <span style="white-space:pre"> </span>dst[jCount + i + 3] = src[iCount + dim * 3 + j]; //dst[j][i + 3] = src[i + 3][j] <span style="white-space:pre"> </span>dst[jCount + dim + i] = src[iCount + j + 1]; //dst[j + 1][i] = src[i][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 1] = src[iCount + dim + j + 1]; //dst[j + 1][i + 1] = src[i + 1][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 2] = src[iCount + dim * 2 + j + 1]; //dst[j + 1][i + 2] = src[i + 2][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 3] = src[iCount + dim * 3 + j + 1]; //dst[j + 1][i + 3] = src[i + 3][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i] = src[iCount + j + 2]; //dst[j + 2][i] = src[i][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i + 1] = src[iCount + dim + j + 2]; //dst[j + 2][i + 1] = src[i + 1][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i + 2] = src[iCount + dim * 2 + j + 2]; //dst[j + 2][i + 2] = src[i + 2][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2+ i + 3] = src[iCount + dim * 3 + j + 2]; //dst[j + 2][i + 3] = src[i + 3][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i] = src[iCount + j + 3]; //dst[j + 3][i] = src[i][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 1] = src[iCount + dim + j + 3]; //dst[j + 3][i + 1] = src[i + 1][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 2] = src[iCount + dim * 2 + j + 3]; //dst[j + 3][i + 2] = src[i + 2][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 3] = src[iCount + dim * 3 + j + 3]; //dst[j + 3][i + 3] = src[i + 3][j + 3] <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>//记录当前行和列的索引,以便执行完剩余的项 <span style="white-space:pre"> </span>int curIndex = i; <span style="white-space:pre"> </span>//处理剩余项,简单的交换处理 <span style="white-space:pre"> </span>for(i = 0;i < curIndex;i++) <span style="white-space:pre"> </span>for(j = curIndex;j < dim;j++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>dst[j * dim + i] = src[i * dim + j]; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>for(i = curIndex;i < dim;i++) <span style="white-space:pre"> </span>for(j = 0;j < dim;j++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>dst[j * dim + i] = src[i * dim + j]; <span style="white-space:pre"> </span>} }
void better_col_convert(int *G,int dim) { int i, j; int iCount,jCount; //以4 * 4 的方阵为单位依次计算,增长了写的缓存命中率,多个元素一块儿读写还减小了循环开销 for(i = 0;i < dim - 3;i += 4) { iCount = i * dim; for(j = 0;j < dim - 3;j += 4) { jCount = j * dim; G[jCount + i] = G[iCount + j] || G[jCount + i]; //G[j][i] = G[i][j] || G[j][i] G[jCount + i + 1] = G[iCount + dim + j] || G[jCount + i + 1]; //G[j][i + 1] = G[i + 1][j] || G[j][i + 1] G[jCount + i + 2] = G[iCount + dim * 2 + j] || G[jCount + i + 2]; //G[j][i + 2] = G[i + 2][j] || G[j][i + 2] G[jCount + i + 3] = G[iCount + dim * 3 + j] || G[jCount + i + 3]; //G[j][i + 3] = G[i + 3][j] || G[j][i + 3] G[jCount + dim + i] = G[iCount + j + 1] || G[jCount + dim + i]; //G[j + 1][i] = G[i][j + 1] || G[j + 1][i] G[jCount + dim + i + 1] = G[iCount + dim + j + 1] || G[jCount + dim + i + 1]; //G[j + 1][i + 1] = G[i + 1][j + 1] || G[j +1][i + 1] G[jCount + dim + i + 2] = G[iCount + dim * 2 + j + 1] || G[jCount + dim + i + 2]; //G[j + 1][i + 2] = G[i + 2][j + 1] || G[j +1][i + 2] G[jCount + dim + i + 3] = G[iCount + dim * 3 + j + 1] || G[jCount + dim + i + 3]; //G[j + 1][i + 3] = G[i + 3][j + 1] || G[j + 1][i + 3] G[jCount + dim * 2 + i] = G[iCount + j + 2] || G[jCount + dim * 2 + i]; //G[j + 2][i] = G[i][j + 2] || G[j +2][i] G[jCount + dim * 2 + i + 1] = G[iCount + dim + j + 2] || G[jCount + dim * 2 + i +1]; //G[j + 2][i + 1] = G[i + 1][j + 2] || G[j +2][i + 1] G[jCount + dim * 2 + i + 2] = G[iCount + dim * 2 + j + 2] || G[jCount + dim * 2 + i + 2]; //G[j + 2][i + 2] = G[i + 2][j + 2] || G[j +2][i + 2] G[jCount + dim * 2+ i + 3] = G[iCount + dim * 3 + j + 2] || G[jCount + dim * 2 + i + 3]; //G[j + 2][i + 3] = G[i + 3][j + 2] || G[j + 2][i + 3] G[jCount + dim * 3 + i] = G[iCount + j + 3] || G[jCount + dim * 3 + i]; //G[j + 3][i] = G[i][j + 3] || G[j +3][i] G[jCount + dim * 3 + i + 1] = G[iCount + dim + j + 3] || G[jCount + dim * 3 + i + 1]; //G[j + 3][i + 1] = G[i + 1][j + 3] || G[j +3][i + 1] G[jCount + dim * 3 + i + 2] = G[iCount + dim * 2 + j + 3] || G[jCount + dim * 3 + i + 2]; //G[j + 3][i + 2] = G[i + 2][j + 3] || G[j + 3][i + 2] G[jCount + dim * 3 + i + 3] = G[iCount + dim * 3 + j + 3] || G[jCount + dim * 3 + i + 3]; //G[j + 3][i + 3] = G[i + 3][j + 3] || G[j + 3][i + 3] } } //记录当前行和列的索引,以便执行完剩余的项 int curIndex = i; //处理剩余项,简单的交换处理 for(i = 0;i < curIndex;i++) for(j = curIndex;j < dim;j++) { G[j * dim + i] = G[i * dim + j] || G[j * dim + i]; } for(i = curIndex;i < dim;i++) for(j = 0;j < dim;j++) { G[j * dim + i] = G[i * dim + j] || G[j * dim + i]; } }
(statistics.sh脚本的运行结果截图)
- [20155324](博客连接) - 结对照片 - 结对学习内容 - XXXX - XXXX - ...
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第十四周 | 3000/5000 | 1 /26 | 15/320 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进本身的计划能力。这个工做学习中很重要,也颇有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
计划学习时间:XX小时
实际学习时间:XX小时
改进状况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)