教材学习内容总结
随机访问存储器
基本的存储技术包括SRAM存储器、DRAM存储器、ROM存储器和旋转的和固态的硬盘
RAM分为静态SRAM和动态DRAM。SRAM比DRAM更快,也更贵。SRAM作为告诉缓存存储器,既可以在CPU芯片上,也可以在片下。DRAM作为主存以及图形系统的帧缓冲区。
ROM是非易失的,统称为只读存储器
总线是一组并行的导线,能携带地址、数据和控制信号
系统总线——连接CPU和I/O桥
存储器总线——连接I/O桥和主存
I/O总线:I/O桥将系统总线的电子信号翻译成存储器总线的电子信号,也将系统总线和存储器总线连接到I/O总线
磁盘存储
1、磁盘构造
(1)由盘片构成,每个盘片有两面或者称为表面,表面覆盖着磁性记录材料。盘片中央有一个可以旋转的主轴,使得盘片以固定的旋转速率旋转,通常是5400~15000转每分钟(RPM)
(2)每个表面是由一组称为磁道的同心圆组成;每个磁道被划分成一组扇区;每个扇区包含相等数量的数据位(通常是512字节);这些数据编码在扇区上的磁性材料中。扇区之间由一些 间隙分隔开,这些间隙中不存在数据位。间隙存储用来标识扇区的格式化位。
2、磁盘容量
(1)一个磁盘上可以记录的最大位数称为它的最大容量/容量。
(2)磁盘容量的决定因素:
记录密度:磁道一英寸的段可以放入的位数。
磁道密度:从盘片中心出发半径上一英寸的段内可以有的磁道数。
面密度:记录密度与磁道密度的乘积。
磁盘是重点,涉及到后面的i/o和文件系统,做好相关练习
磁盘操作
1、磁盘用读写头来读写存储在磁性表面的位,而读写头连接到一个转动臂一端。寻道就是通过沿着半径轴前后移动这个转动臂,使得驱动器可以将读写头定位在盘面上的任何磁道上。
任何时刻,所有的读写头都位于同一柱面上。
在传动臂末端的读/写头在磁盘表面高度约0.1微米处一层薄薄的气垫上飞翔,速度大约为80km/h。
磁盘以扇区大小的块来读写数据。
2、访问时间:
(1)寻道时间:为了读取某个目标扇区的内容,传动臂把读/写头首先定位到包含目标扇区的磁道上,所需时间即为寻道时间,约等于最大旋转时间。
寻道时间Tseek依赖于读写头以前的位置和转动臂在盘面上移动的速度。
(2)旋转时间:定位到期望的磁道后,驱动器等待目标扇区的第一个位旋转到读/写头下。依赖于当读写头到达目标扇区时盘面的位置和磁盘旋转速度。
定位到期望的磁道后,驱动器等待目标扇区的第一个位旋转到读/写头下。
最大旋转时间 = 1/最大旋转数率
平均旋转时间 = (1/2) * 最大旋转时间。
(3)传送时间:当目标扇区的第一个位位于读写头下时,驱动器就可以开始读或者写该扇区的内容。依赖于旋转速度和每条磁道的扇区数目。
平均传送时间 = (1/最大旋转数率) * (1/每磁道的平均扇区数)
逻辑磁盘块
1、内存可以看成字节数组、磁盘可以看成块数组
2、现代磁盘构造复杂,有多个盘面,这些盘面上有不同的记忆区。为了对操作系统隐藏这样的复杂性,现代磁盘将他们的构造呈现为一个简单的试图,一个B个扇区大小的逻辑块的序列,编号为0,1,...,B-1。
3、磁盘中有一个小的硬件/固件设备,称为磁盘控制器,维护着逻辑块号和实际(物理)扇区之间的映射关系。
4、控制器上的固件执行一个快速表查找,将一个逻辑块号翻译一个(盘面、磁道、扇区)的三元组,这个三原则唯一地表示了对应的物理扇区。控制器上的硬件解释这个三元组,将读写头移动到适当的煮面,等待扇区移动到读写头下,将读写头感知到的位放在控制器上的一个小缓冲区中,然后将他们拷贝到主存中。
连接到I/O设备
1、想图形卡、监视器、鼠标、键盘和磁盘这样的输入输出设备,都是通过I/O总线连接到CPU和主存的。
2、系统总线和存储器总线是与CPU相关的,I/O总线设计成与底层CPU无关。
3、I/O总线比系统总线比存储器总线慢,但是它可以容纳种类繁多的第三方I/O设备。
通用串行总线USB:2.0最大带宽60MB/S,3.0最大带宽600MB/S
图形卡(适配器)
主机总线适配器
访问磁盘
1、CPU使用一种存储器映射I/O技术来向I/O设备发出命令,在使用存储器映射I/O的系统中,地址空间中有一块地址是为与I/O设备通信保留的,称为I/O端口。当一个设备连接到总线时,它与一个或多个端口相连。
2、直接存储器访问:设备可以自己执行读或者写总线事务,而不需要CPU干涉的过程。这种数据传送称为DMA传送。
固体磁盘
1、固态硬盘是一种基于闪存的存储技术。
2、一个SSD包由一个或多个闪存芯片和闪存翻译层组成,闪存芯片替代传统旋转磁盘中机械驱动器;闪存翻译层(一个硬件/固件设备)替代磁盘控制器,将对逻辑块的请求翻译成对底层物理设备的访问。
3、性能特性
顺序读和写(CPU按顺序访问逻辑磁盘块)性能相当,顺序读比顺序写稍快一点。
随机顺序访问逻辑块时,写比读慢一个数量级。
读写性能差别是由底层闪存基本属性决定的。
4、优缺点
(1)优点:
由半导体构成,没有移动的部件
随机访问时间比旋转磁盘要快、能耗低、结实
(2)缺点:易磨损、更贵
高速缓存友好代码分析
#include<stdio.h>
void main()
{
int a[4]={1,2,3,4};
int i;
int sum=0;
for(i=0;i<4;i++)
sum+=a[i];
}
该程序具有良好的时间局部性,因为i,sum均被重复使用多次;该程序也具有良好的空间局部性,因为依次读取数组a的4个元素,由于int类型占据4个字节,因此只要高速缓存块大小大于16个字节(intel i7的块大小为64Bytes,因此足够),它们就可以一起被读入高速缓存块中,而仅仅是a[0]发生了高速缓存不命中,因为它第一个被读取需要加载,而后面3个量均为高速缓存命中。
高速缓存不友好代码分析
#include<stdio.h>
void main()
{
int a[2][2]={{1,2},{3,4}};
int i,j,sum=0;
for(int j=0;j<2;j++) {
for(int i=0;i<2;i++) {
sum+=a[i][j];
}
}
}
由于C语言是按行优先顺序来存储的,所以这个循环的步长不是以1为单位的,并且每次读取都要换行,所以所有的读取都发生了缓存不命中情况,程序运行效率会比高速缓存友好的程序慢一倍!
教材中的内容及解决
习题6.2
计算这样一个磁盘的容量。它有2个盘片,10 000个柱面,每条磁道平均有400个扇区,每个扇区平均有512个字节
磁盘容量 = (512/400)*400*10000*2*2= 8 192 000 000 字节 = 8.192GB
习题6.3
估计访问下面的一个磁盘上的一个扇区需要的时间(以ms为单位)。旋转速率:15000RPM;Taveseek = 8ms;每条磁道的平均扇区数:500
访问时间 = Taveseek+Taverotation+Tavetransfer = 8ms+0.51/15000RPM60secs.min1000ms/s+1/15000RPM1/50060secs/min1000ms/s=8ms+2ms+0.008ms=10.008ms
习题6.4
假设1MB的文件由512字节的逻辑块组成,存储在有如下特性的磁盘驱动器上(旋转速率:10 000RPM,Taveseek=5ms,平均扇区/磁道 = 1000)。
(1)最好的情况:给定逻辑块到磁盘扇区的最好的可能的映射(即,顺序的),估计读这个文件需要的最优时间
(2)随机的情况:如果块是随机地映射到磁盘扇区的,估计读这个文件需要的时间
(1)T=Taveseek+Taverotation+2Tmaxrotation=5ms+3ms+26ms=20ms
(2)在这种情况下,块被随机的映射到扇区上,读2000块的每一块都需要Taveseek+Tavgrotation=8ms。所以读这个文件的总时间为
T =8ms*2000=16000ms=16s
习题6.11
在前面dotprod的例子中,在我们对数组x做了填充之后,所有对x和y的引用的命中率是多少?
在填充了之后,对于x和y数组,只有在引用第0个和第4个元素的时候发生不命中。因而命中率为75%
代码调试中的问题及解决方法
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdarg.h>
#include<errno.h>
#define BUFSIZE 512
#define LEN 2
void err_exit(char *fmt,...);
int main(int argc,char *argv[])
{
pid_t pid;
int loop;
for(loop=0;loop<LEN;loop++)
{
printf("Now is No.%d loop:
",loop);
if((pid=fork()) < 0)
err_exit("[fork:%d]: ",loop);
else if(pid == 0)
{
printf("[Child process]P:%d C:%d
",getpid(),getppid());
}
else
{
sleep(5);
}
}
return 0;
}
现在我们可以开始解答我们的疑问了,
首先父进程执行循环,通过fork创建一个子进程,然后sleep5秒。
再来看父进程创建的这个子进程,这里我们记为子进程1.子进程1完全复制了这个父进程的数据部分,但是需要注意的是它的正文段是和父进程共享的。也就是说,子进程1开始执行代码的部分并不是从main的 { 开始执行的,而是主函数执行到哪里了,它就接着执行,具体而言就是它会执行fork后面的代码。所以子进程1首先会打印出它的ID和它的父进程的ID。然后继续第二遍循环,然后这个子进程1再来创建一个子进程,我们记为子进程11,子进程1开始sleep。
子进程11接着子进程1执行的代码开始执行(即fork后面),它也是打印出它的ID和父进程ID(子进程1),然后此时loop的值再加1就等于2了,所以子进程2直接就返回了。
那个子进程1sleep完了之后也是loop的值加1之后变成了2,所以子进程1也返回了!
然后我们再返回去看父进程,它仅仅循环了一次,sleep完之后再来进行第二次循环,这次又创建了一个子进程我们记为子进程2。然后父进程开始sleep,sleep完了之后也结束了。
那么那个子进程2怎么样了呢?它从fork后开始执行,此时loop等于1,它打印完它的ID和父进程ID之后,就结束循环了,整个子进程2就直接结束了!
代码托管
学习与感悟
本周主要学习代码的部分,经过自己的探索了解了每个代码的具体含义,并把每个代码都进行了实际操作,达到了正确的结果,不足之处在于细节上还不是很理解,还需要慢慢消化
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 |
---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 |
第一周 | 10 /10 | 1/1 | 10/10 |
第二周 | 40 /70 | 2/4 | 18/38 |
第三周 | 150/200 | 3/7 | 15/60 |
第四周 | 160/210 | 6/8 | 23/70 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
参考:软件工程软件的估计为什么这么难,软件工程 估计方法
计划学习时间:20小时
实际学习时间:23小时
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)
参考资料
《深入理解计算机系统V3》学习指导