2017-2018-1 20155231 《信息安全系统设计基础》第9周学习总结
教材学习内容总结
第六章 存储器层次结构
第一节 存储技术
- 所谓“随机存取”,指的是当存储器中的数据被读取或写入时,所需要的时间与这段信息所在的位置或所写入的位置无关。相对的,读取或写入顺序访问(Sequential Access)存储设备中的信息时,其所需要的时间与位置就会有关系。它主要用来存放操作系统、各种应用程序、数据等
- 当电源关闭时RAM不能保留数据。如果需要保存数据,就必须把它们写入一个长期的存储设备中(例如硬盘)。
- 动态DRAM(DRAM):将每个位存储为对电容的充电。电容约为30×10-15F。
- 磁盘存储:公式:磁盘容量=字节数/扇区平均盘区数/磁道磁道数/表面表面数/盘片盘片数/磁盘
- 任何时刻,所有的读写头都位于同一柱面上。
磁盘以扇区大小的块来读写数据。
传送时间:当目标扇区的第一个位位于读写头下时,驱动器就可以开始读或者写该扇区的内容。依赖于旋转速度和每条磁道的扇区数目。
平均传送时间 = (1/最大旋转数率) * (1/每磁道的平均扇区数)
- 磁盘中有一个小的硬件/固件设备,称为磁盘控制器,维护着逻辑块号和实际(物理)扇区之间的映射关系。
第二节 局部性
- 有良好局部性的程序比局部性差的程序运行得更快
- 步长为1的引用模式:就是顺序访问一个向量的每个元素,有时也被称为顺序引用模式,是程序中空间局部性常见和重要的来源。
一般来说,随着步长增加,空间局部性下降。
- 语言中数组在存储器中是按照行顺序存放的,所以按照行优先顺序执行的代码的局部性要好于按列优先顺序的代码。
- 量化评价一个程序中局部性的简单原则
- 重复引用同一个变量的程序有良好的时间局部性
- 对于具有步长为k的引用模式的程序,步长越小,空间局部性越好
- 对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。
第三节 存储器层次结构
- 高层往底层走,存储设备变的更慢、更便宜、更大。每一层存储设备都是下一层的缓存。
- 存储器层次结构的中心思想:对于每个k,位于k层的更快更小的存储设备作为位于k+1层的更大更慢的存储设备的缓存。即每层存储设备都是下一层的“缓存”
数据总是以块大小为传送单元在第k层与第k+1层之间来回拷贝。任一对相邻的层次之间块大小是固定的,但是其他的层次对之间可以有不同的块大小。
- 替换策略:决定替换哪个块
- 随机替换策略:随机选择一个牺牲块
- 最近最少被使用替换策略(LRU):选择最后被访问的时间距现在最远的块
- 冲突不命中:由于一个放置策略:将第k+1层的某个块限制放置在第k层块的一个小的子集中,这就会导致缓存没有满,但是那个对应的块满了,就会不命中。
- 容量不命中:当工作集的大小超过缓存的大小时,缓存会经历容量不命中,就是说缓存太小了,不能处理这个工作集。
第四节 高速缓存存储器
- 高速缓存大小:较大的高速缓存可能会提高命中率,但使大存储器运行的更快是更难一些的。
- 块大小:较大的块能利用程序中可能存在的空间局部性,帮助提高命中率;但块越大意味着高速缓存行较少,损害时间局部性。
- 相联度:相联度较大(E值较大)优点是降低了高速缓存由于冲突不命中出现抖动的可能性,但成本较高。
- 写策略:直写高速缓存易实现,而且能使用独立于高速缓存的写缓冲区,用来更新存储器,不命中开销小。写回高速缓存引起的传送比较少,允许更多的到存储器的宽带用于执行DMA的I/O设备。越下层,越可能用写回而不是直写。
第五节 编写高速缓存友好的代码
确保代码高速缓存友好的基本方法:
- 让最常见的情况运行的快
- 在每个循环内部缓存不命中数量最小
- 两种局限性:空间、时间
教材学习中的问题和解决过程
- 问题1: pwd 命令查看默认工作目录的完整路径
- 问题1解决方案:
[[email protected] ~]# pwd
/root
[[email protected] ~]#
- 问题2:pwd 命令查看指定文件夹
- 问题2解决方案:
[[email protected] ~]# cd /opt/soft/
[[email protected] soft]# pwd
/opt/soft
[[email protected] soft]#
代码调试中的问题和解决过程
- 问题1:实现pwd
- 解决问题:
- ```
ino_t get_ino_byname(char *filename)
{
struct stat file_stat;
if(0 != stat(filename, &file_stat)) //stat()通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
{
perror("stat");
exit(-1);
}
return file_stat.st_ino;
}
//根据inode-number, 在当前目录中查找对呀的文件名
char find_name_byino(ino_t ino)
{
DIR dp = NULL;
struct dirent dptr = NULL;
char filename = NULL;
if(NULL == (dp = opendir("."))) //opendir()打开一个目录,在失败的时候返回一个空的指针,成返回DIR结构体 { fprintf(stderr, "Can not open Current Directory\n"); exit(-1); } else { while(NULL != (dptr = readdir(dp))) //readdir()用来读取目录。返回是dirent结构体指针 { if(dptr->d_ino == ino) { filename = strdup(dptr->d_name); //strdup()将串拷贝到新建的位置处,返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值. break; } } closedir(dp); } return filename;
}
int main(int argc, char argv[])
{
//记录目名的栈
char dir_stack[MAX_DIR_DEPTH];
unsigned current_depth = 0;
while(TRUE) { ino_t current_ino = get_ino_byname("."); //通过特殊的文件名"."获取当期目录的inode-number ino_t parent_ino = get_ino_byname(".."); //通过特殊的文件名".."获取当前目录的父目录的inode-number if(current_ino == parent_ino) break; //达到根目录,推出循环 /*两个inode-number不一样*/ chdir(".."); //更改当前工作目录,变为当前目录的父目录 dir_stack[current_depth++] = find_name_byino(current_ino); //"文件名"地址存放 if(current_depth >= MAX_DIR_DEPTH) //路径名太深 { fprintf(stderr, "Directory tree is too deep.\n"); exit(-1); } } int i = current_depth - 1; for(i = current_depth - 1; i >= 0; i--) //打印路径 { fprintf(stdout, "/%s", dir_stack[i]); } fprintf(stdout, "%s\n", current_depth == 0 ? "/" : ""); return 0;
}
```
代码托管
上周考试错题总结
- 有关exec系列函数,下面说法正确的是:
- 进程调用了exec系列函数后,代码会改变。
- exec系列函数中带e的要传入环境变量参数
- 解析:不能用char[][] 来传递argv,结尾的0(null)无法处理;system=fork+exec+wait;
- 关于代码 int main(){} 说法正确的是:
- 返回值是0;
- 会调用exit(0);
- 上面代码运行完,在命令行中运行echo $? 的值是0
- 解析:main中不调用exit,会补上exit(0)
结对及互评
点评模板:
- 博客中值得学习的或问题:
- xxx
- xxx
- ...
- 代码中值得学习的或问题:
- xxx
- xxx
- ...
- 其他
本周结对学习情况
- [结对同学学号1](博客链接)
- 结对照片
- 结对学习内容
- XXXX
- XXXX
- ...
其他(感悟、思考等,可选)
本周学习东西很多。有些实验还没完成,还在学习。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第9周 | 299/2700 | 1/5 | 11/1000 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
- 计划学习时间:16小时
- 实际学习时间:11小时
- 改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)