《深入理解计算机系统》学习笔记 - 第一课 - 课程简介

Lecture 01 Course Overview 课程简介

概述

我的这些课程是通过B站视频学习《深入立即计算机系统》书籍学习所做的一些笔记。
分享出来希望和大家共同学习。

学习的资料:
【精校中英字幕】2015 CMU 15-213 CSAPP 深入理解计算机系统 课程视频
CS:APP主页
csapp 代码地址

不要抄袭

放弃复制黏贴,放弃搜索。

书籍推荐

  • Computer Systems: A Programmer’s Perspective(CS:APP3e)
    地址:http://csapp.cs.cmu.edu

  • The C Programming Language
    作者:Brian Kernighan and Dennis Ritchie
    C语言学习书籍。

课程内容

  • Lecture

    • Highter level concepts 高层级概念
  • Recitations 背诵
    所以不要忽略记忆。死记硬背也是基础。概念都不知道何来后面的。

  • Labs 实验
    课程的灵魂,编程只有不断的实践,遇到问题,解决问题,才会有所成长。
    背诵只是让你知道,实践才可以让你能够真正处理问题。

  • Exams 考试

帮助

网址:http://www.cs.cmu.edu/~123

实验

使用 Autolab 来做作业。

使用机器:
ssh shark.ics.cs.cmu.edu

课堂纪律

  • 可以带电脑,但是不要用于通信等其他与课程无光用途。
    认真听讲
  • 不考勤,自愿来不来

考试分数

考试和实验室分数各分50%,期中考试20%,期末考试30%

课程

主题一:程序和数据

  • 位操作,运算,汇编语言程序
  • C 语言控制和数据结构描述
  • 体系解雇和编译器

作业:

  • L1(datalab): Manipulating bits(操作位)
  • L2(bomblab): Defusing a binary bomb (拆除二进制炸弹)
  • L3(attacklab): The basics of code injection attacks(代码注入)

主题二:内存层次结构

  • 内存技术,内存层次,缓存,磁盘,局部性
  • 体系结构和操作系统

作业:

  • L4(cachelab): Building a cache simulator and optmizing for locality.
    构建缓存模拟器并优化局部性。
    学习如何在程序中利用局部性。

主题三:例外的控制流程

  • 硬件,进程,进程控制,unix 信号
  • 编译器,操作系统,体系结构。

作业:
L5(tshlab): Writing your own Unix shell
写一个自己的shell工具。
开始了解并发。

主题四:虚拟内存

  • 虚拟内存,地址转换,动态存储分配
  • 体系结构,操作系统

作业:
L6(malloclab): Writing your own malloc package
写一个自己的内存(malloc)包
获得对系统级编程的真实感受。

主题五:网络和并发

  • 高级/低级 I/O, 网络编程
  • 服务,web服务器
  • 并发,并发服务器设计,线程
  • I/O 多路复用与选择
  • 网络,操作系统,体系结构

作业:
L7(proxylab): Writing your own Web proxy
写一个自己的Web代理
学习网络编程和更多关于并发和同步。

课程实例

Great Reality #1

Example 1: Is x2 ≥ 0?

Ints are not Integers, Floats are not Reals

  • Example 1: Is x^2 >= 0 ?
    float:是的
    Int:
40000	*	40000		➙	1600000000
50000	*	50000		➙	??
Example 2: Is (x + y) + z = x + (y + z)?

Unsigned & Signed Int’s: Yes!
Float’s:

(1e20	+	-1e20)	+	3.14	-->	3.14	
1e20	+	(-1e20	+	3.14)	-->	??	

简单的理解:就是浮点运算时会进行舍入, (-1e20 + 3.14)导致3.14丢失。

代码

Great Reality #1

  • Example 1: Is x2 ≥ 0?
#include <stdio.h>

void reality(int a) {
    printf("%d*%d=%d\n",a, a, a*a);
}

int main() {
    reality(40000);
    reality(50000);
}

// output:
// 40000*40000= 1600000000
// 50000*50000=-1794967296

2^31 = 2147483648
50000*50000 = 2500000000
超出int32的边界了。

  • Example 2: Is (x + y) + z = x + (y + z)?
#include <stdio.h>

void floatAdd(float a) {
    printf("(%f-%f)+3.14=%f\n",a,a, (a-a)+3.14);
    printf("%f+(-%f+3.14)=%f\n",a,a, a + (-a+3.14));
}

int main() {
    floatAdd(1e20);
}

// output:
// (100000002004087730000.000000-100000002004087730000.000000)+3.14=3.140000
// 100000002004087730000.000000+(-100000002004087730000.000000+3.14)=0.000000
  • Memory Referencing Bug
typedef struct {
    int a[2];
    double d;
}struct_t;

double memoryRefBug(int i) {
    volatile struct_t s;
    s.d = 3.14;
    s.a[i] = 1073741824;
    printf("%d -> %lf\n",i,s.d);
    return s.d;
}
int main() {
    memoryRefBug(0);
    memoryRefBug(1);
    memoryRefBug(2);
    memoryRefBug(3);
    memoryRefBug(4);
    memoryRefBug(5);
    memoryRefBug(6);
    memoryRefBug(7);
}

// output:
// 0 -> 3.140000
// 1 -> 3.140000
// 2 -> 3.140000
// 3 -> 2.000001
// 4 -> 3.140000
// 5 -> 3.140000
// 6 -> 3.140000

结构体和数组类似,元素的存储是紧挨着的。a[1] | a[2] | d
通过a[i]取,a[2]开始,就是引用的d中的值了进行操作了。

  • Memory System Performance Example
#include <stdio.h>
#include <windows.h>

void copyij(int src[2048][2048], int dst[2048][2048]) {
    int i,j;
    for (i = 0;i < 2048;i++)
        for (j = 0;j < 2048;j++)
            dst[i][j] = src[i][j];
}

void copyji(int src[2048][2048], int dst[2048][2048]) {
    int i,j;
    for (j = 0;j < 2048;j++)
        for (i = 0;i < 2048;i++)
            dst[i][j] = src[i][j];
}

int main() {
    int src[2048][2048],dst[2048][2048];
    int i,j;
    for (j = 0;j < 2048;j++)
        for (i = 0;i < 2048;i++)
            src[i][j] = i;
    int start,end1,end2;
    start = GetTickCount();
    copyij(src,dst);
    end1 = GetTickCount();
    copyji(src,dst);
    end2 = GetTickCount();
    printf("copyij: %d, copyji:%d", end1 - start, end2 - end1);
}

// output:
// copyij: 0, copyji:0

结果分析:
教材显示copyij() 的性能远远好于 copyji()。
为什么我运行的没有这个问题。难道是这个已经修复了?

问题:
在windows下报错:“Process finished with exit code -1073741571 (0xC00000FD)”
致的原因是StackOverflow(栈区溢出)
将数组设置为500长度就没事了。

linux 代码:

#include <stdio.h>
#include <math.h>
#include <time.h>

int main() {
    int src[2048][2048],dst[2048][2048];
    int i,j;
    for (j = 0;j < 2048;j++)
        for (i = 0;i < 2048;i++)
            src[i][j] = i;
    clock_t start,end1,end2;
    start = clock();
    copyij(src,dst);
    end1 = clock();
    copyji(src,dst);
    end2 = clock();
    printf("copyij: %d, copyji:%d", ((double )(end1 - start))/CLOCKS_PER_SEC, ((double )(end2 - end1))/CLOCKS_PER_SEC);
}

报错:”Segmentation fault“

分析:
Segmentation fault就是指访问的内存超出了系统所给这个程序的内存空间。一般是随意使用野指针或者数组、数组越界。

处理方案:
将数组设置为500长度。

结果:

copyij: 0, copyji:3668

二维数组行遍历效率远高于列遍历效率

  • c语言遍历
    对c语言而言,数组在内存中是按行储存的,按行遍历时可以由指向数组第一个数的指针一直往下走,就可以遍历完整个数组,而按列遍历则要获得指向每一列的第一行的元素的指针,然后每次将指针指下一行,

  • CPU高速缓存
    缓存从内存中抓取一般都是整个数据块,所以它的物理内存是连续的,几乎都是同行不同列的,而如果内循环以列的方式进行遍历的话,将会使整个缓存块无法被利用,而不得不从内存中读取数据,而从内存读取速度是远远小于从缓存中读取数据的。

  • 分页调度
    物理内存是以页的方式进行划分的,当一个二维数组很大是如 int[128][1024],假设一页的内存为4096个字节,而每一行正好占据内存的一页,如果以列的形式进行遍历,就会发生128*1024次的页面调度,而如果以行遍历则只有128次页面调度,而页面调度是有时间消耗的,因而调度次数越多,遍历的时间就越长。

  • 局部性原理: CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。

三种不同类型的局部性:时间局部性,空间局部性,顺序局部性。

文档

二维数组按行和按列遍历效率哪个高?

《深入理解计算机系统》书籍学习笔记

《深入理解计算机系统》学习笔记 - 第一课 - 课程简介
《深入理解计算机系统》学习笔记 - 第二课 - 位,字节和整型
《深入理解计算机系统》学习笔记 - 第三课 - 位,字节和整型
《深入理解计算机系统》学习笔记 - 第四课 - 浮点数
《深入理解计算机系统》学习笔记 - 第五课 - 机器级别的程序
《深入理解计算机系统》学习笔记 - 第六课 - 机器级别的程序二
《深入理解计算机系统》学习笔记 - 第七课 - 机器级别的程序三

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值