八月初开始接触《深入理解计算机系统》这本书,当时看的是英文版,花了一个月的时间大体上过了一遍,但我知道其实还是有很多没看懂的地方,于是借了一本中文版,如今总算可以说我真正看过了这本书,可以写一写读书笔记了。

深入理解计算机系统读书笔记

p39-40
把二进制数转为无符号十进制数 B2U(w)=∑xi*2^i (0<=i<=w-1)
B2U(4)([1011])=1*2^3+0*2^2+1*2^1+1*2^0=11

转换为补码形式 B2T(w)=-x(w-1)*2^(w-1)+∑xi*2^i (0<=i<=w-2)
B2T(4)([1011])=-1*2^3+0*2^2+1*2^1+1*2^0=-5

p45-46
无符号与补码之间转换
T2U(w)=x+2^w (x<0) 
=x (x>=0)

U2T(w)=u (u<2^(w-1))
=u-2^w (u>=2^(w-1))

p52
无符号数的截断结果 B2U([x(k-1),x(k-2)...x0])=B2U([x(w-1)...x0])mod 2^k
补码数字截断结果 B2T([x(k-1),x(k-2)...x0])=U2T(B2U([x(w-1)...x0])mod 2^k)

p55
无符号加法 x+(u,w)y= x+y (x+y<2^w)
= x+y-2^w (2^w<=x+y<=2^(w+1))

p58
补码加法  x+(t,w)y= x+y-2^w (2^(w-1)<=x+y) 正溢出
=x+y (-2^(w-1)<=x+y<2^(w-1)) 正常
=x+y+2^w (x+y<-2^(w-1)) 负溢出

p64
乘积移位操作:x*K,让K用二进制数表示,假设K可表示为一组从位位置n到位位置m的连续的1(n>=m),我们可以用下面两种不同形式中的一种来计算这些位对乘积的影响
形式A:(x<<n)+(x<<n-1)+...+(x<<m)
形式B:(x<<n+1)-(x<<m)
通过这种形式,不用做乘法,我们就能计算出x*K

p333
代码移动:这类优化包括识别要执行多次但是计算结果不会改变的计算,将计算移动到代码前面不会多次求值的部分
例如:for (int i=0;i<strlen(s);i++) 这里应该把strlen(s)提前,用一个变量length保存
改写后: int length=strlen(s); for(int i=0;i<length;i++)

p338
循环展开:这是一种程序变换,通过增加每次迭代计算的元素的数量,减少循环的迭代次数
例如:
for(i=0;i<limit;i+=2)
 acc=(acc OP data[i]) OP data[i+1]
上面就是展开循环K=2次,不过最后几个元素需要单独处理

p351
两路并行:对于可结合和可交换的合并运算来说,可以通过将一组合并运算分割成两个或更多部分,并在最后合并结果来提高性能
例如:
for(i=0;i<limit;i+=2)
{
 acc0=acc0 OP data[i];
 acc1=acc1 OP data[i+1];
}
...
*dest=acc0 OP acc1
上面利用了两次循环展开以及两路并行

p354
重新结合变换:对代码做很小的改动,改变合并方式,能够减少计算中关键路径上操作的数量,通过更好地利用功能单元的流水线能力得到更好的性能
例如:
acc=(acc OP data[i]) OP data[i+1]
acc=acc OP(data[i] OP data[i+1])
仅仅是括号的差别,但是性能却大不一样

p359
关键路径指明了执行某程序所需时间的一个基本的下界,如果某程序存在数据相关链,这条链上所有延迟之和等于T,那么这个程序至少需要T个周期才能执行完
同时功能单元的吞吐量界限也是程序执行的一个下界,假设一个程序一共需要N个某种运算的计算,而微处理器只有m个能够执行这个操作的功能单元,并且这些单元的发射时间为i,那么该程序执行至少需要N*i/m个周期

p369
性能提高技术
A-高级设计 选择适当的算法和数据结构
B-基本编码原则
消除连续的函数调用,尽量将计算移到循环外
消除不必要的存储器引用,引入临时变量来保存中间结构,只有最后计算出的值才保存在数组或全局变量中
C-低级优化
展开循环,降低开销,并且使得进一步的优化成为可能
通过使用例如多个累计变量和重新结合等技术,找到方法提高指令级并行
用功能的风格重写条件操作,使得编译采用条件数据传送

p374
Amdahl定律:当我们加快系统一个部分的速度时,对系统整体性能的影响依赖于这个部分有多重要和速度提高了多少
假设系统某个部分需要整个应用程序执行时间的百分比为α,则
加速比 S=1/[(1-α)+α/k] 
所以要想大幅度提高整个系统的速度,必须提高整个系统很大一部分的速度

p402-403
局部性:时间局部性(重复引用),空间局部性(引用附近的一个位置)
步长为1的引用模式为顺序引用模式,一般而言,随着步长的增加,空间局部性下降
评价局部性原则:
重复引用同一个变量的程序有良好的时间局部性
对于步长为k的引用模式的程序,步长越小,空间局部性越好。步长为1有很好的空间局部性,使用大步长的程序空间局部性很差
对于取指令来说,循环有好的时间和空间局部性,循环迭代次数越多,局部性就越好

p433
使用下列技术利用局部性:
将你的注意力集中在内循环上,大部分计算和存储器的访问都发生在那里
通过按照数据对象存储在存储器中的顺序、以步长为1的来读数据,从而使得你程序中的空间局部性最大
一旦从存储器中读入了一个数据对象,仅尽可能多地使用它,从而使得程序中的时间局部性最大

p455
函数和已初始化的全局变量为强符号,未初始化的全局变量为弱符号
unix链接器使用下面规则来处理多重定义的符号:
规则1:不允许有多个强符号
规则2:如果有一个强符号和多个弱符号,那么就选择强符号
规则3:如果有多个弱符号,那么就从这些弱符号中任意选择一个

p492-522
进程函数
pid_t getpid(void) //返回调用进程的PID
pid_t getppid(void) //返回父进程PID
void exit(int status) //终止进程
pid_t fork(void) //父进程通过此函数创建子进程,父进程中fork返回子进程PID,在子进程中返回0
pid_t waitpid(pid_t pid, int *status, int options)//父进程等待子进程终止或停止 pid>0等待单独子进程, pid=-1为全部
pid_t wait(int *status) //等待所有子进程
unsigned int sleep(unsigned int secs)//将一个进程挂起一段指定的时间
int pause(void) //让调用函数休眠,直到该进程收到一个信号
int execve(const char *filename, const char *agrv[], const char *envp[])//函数加载运行一个新程序
char *getenv(const char *name)//在环境数组中搜索字符串name=value,找到返回一个指向value指针
int setenv(const char *name, const char *newvalue, int overwrite)//用newvalue代替oldvalue
void unsetenv(const char *name)//删除name=value

信号
pid_t getpgrp(void)//返回当前进程的进程组ID(每个进程都只属于一个进程组)
int setpgid(pid_t pid,pid_t,pgid)//改变自己或其它进程的进程组
int kill(pid_t pid, int sig)//终止进程,发送信号sig给进程pid
unsigned int alarm(unsigned int secs)//进程在secs秒内向自身发sigalam信号,
sighandler_t signal(int signum, sighandler_t handler)//进程接收信号
int sigaction(int signum,struct sigaction *act,struct sigaction *oldact)//信号处理

非本地跳转
int setjmp(jum_buf env) //在env缓冲区中保存当前调用环境,为longjmp使用
int sigsetjmp(sigjmp_buf env,int savesigs)//信号处理使用版本
void longjmp(jum_buf env,int retval)//从env缓冲区中恢复调用环境
void siglongjmp(sigjmp_buf env,int retval)//信号处理使用版本

p582-585
C程序中常见的与存储器有关的错误

A-间接引用坏指针
例如:scanf("%d",val)

B-读未初始化的存储器
例如:假设堆存储器被初始化为零
int *y=(int *)malloc(n*sizeof(int))
其实这里并未初始化,使用calloc才能实现

C-允许栈缓冲区溢出
例如:char buf[64]; gets(buf)

D-假设指针和它们指向的对象是相同大小的
例如:int **A=(int **)malloc(n*sizeof(int));  //应该为sizeof(int *)
... A[i]=(int *)malloc(m*sizeof(int))
程序目的创建一个由n个指针组成的数组,每个指针都指向一个包含m个int的数组,但是代码实际创建的是一个int数组

E-造成错位错误
例如:for(int i=0;i<=m;i++) //考虑=号是否取到

F-引用指针,而不是它指向的对象
例如:binheap[0]=binheap[*size-1];
*size--; //应该为(*size)--

G-误解指针运算
例如: p为指针
p+=sizeof(int) //应该为p++

H-引用不存在的变量
例如: int val;
return &val; //程序使用一次后,本地变量不再合法

I-引用空闲堆块中的数据
例如: free(x);
y=x;

J-引起存储器泄露
例如: int *x=(int *)malloc (n*sizeof(int)); //使用后没有free

p597-608
UNIX系统级I/O
int open(char *filename,int flags, mode_t mode)//打开文件或创建一个新文件
int close(int fd)// 关闭文件
ssize_t read(int fd,void *buf, size_t n)//从描述符fd的文件位置拷贝最多n个字节到存储器buf
ssize_t write(int fd,const void *buf, size_t n)//从存储器拷贝最多n个字符到文件
int stat(const char *filename, struct stat *buf)//读取文件元数据
int fstat(int fd,struct stat *buf)//同上
int dup2(int oldfd,int newfd)//I/O重定向,拷贝描述符表项oldfd到描述符表项newfd

p606
UNIX内核用三个相关的数据结构来表示打开的文件
描述符表:每个进程都有自己独立的描述符表,表项由进程打开的文件描述符来索引
文件表:打开文件的集合有一张文件表来表示,所有的进程共享这张表
v-node表:同文件表一样,所有进程共享这张v-node表,每个表项包含stat结构中的大多数信息

p619-629
UNIX网络编程函数
unsigned long int htonl(unsigned long int hostlong)//将32位整数由主机字节顺序转换为网络字节顺序
unsigned short int htons(unsigned short int hostshort)//将16位整数由主机字节顺序转换为网络字节顺序
unsigned long int ntohl(unsigned long int netlong)//将32位整数由网络字节顺序转换为主机字节顺序
unsigned short int ntohs(unsigned short int netshort)//将16位整数由网络字节顺序转换为主机字节顺序

int inet_aton(const char *cp,struct in_addr *inp)//将一个点分十进制串cp转换为一个网络字节顺序的IP地址inp
char *inet_ntoa(struct in_addr_in)//相逆操作,这里传递的是结构本身,不是指向结构的指针

struct hostent *gethostbyname(const char *name)//返回和域名name相关的主机条目
struct hostent *gethostbyaddr(const char *addr, int len,0)//返回和IP地址addr相关联的主机条目

int socket(int domain, int type, int protocol)//创建一个套接字描述符
int connect(int sockfd,struct sockaddr *serv_addr, int addrlen)//试图与套接字地址为serv_addr的服务器建立一个因特网连接
int bind(int sockfd,struct sockaddr *my_addr, int addrlen)//告诉内核将my_addr中的服务器套接字地址和套接字描述符sockfd联系起来
int listen(int sockfd, int backlog)//将sockfd从一个主动的套接字转化为一个监听套接字,接收来自客户端的连接请求
int accept(int listenfd,struct sockaddr *addr,int *addrlen)//服务器通过此函数等待客户端的连接请求

p659-660
线程函数
int pthread_create(pthread_t *tid,pthread_attr_t *attr,func *f,void *arg)//创建一个新线程
pthread_t pthread_self(void) //获得自己线程的ID
void pthread_exit(void *thread_return) //线程显示终止,主线程调用等待对等线程终止
int pthread_cancel(pthread_t tid)//终止当前线程
int pthread_join(pthread_t tid,void **thread_return)//等待其他线程终止
int pthread_detach(pthread_t tid)//线程调用此函数分离可结合线程tid
int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))//初始化与线程相关的状态

后记:

只能说这本书可能并没有像吹的那么牛叉,不知道是不是我能力还未到家的缘故,不过这本书讲解的倒是很清晰,其中也有很多编程忠告,在我看来有把计算机组成原理和操作系统结合的因素,不过显然无法将那两大块都包括其中,只能算是一个铺垫,后续深入的学习还是应该阅读更专业的书籍,例如《操作系统-精髓与设计原理》《计算机体系结构》这些。

不知道自己现在看这本书算不算迟了,不过既然能学到东西,我是欣然接受的,多读书,读好书,那肯定是程序员必须要学会的。

深入理解计算机系统(第二版)读书笔记相关推荐

  1. 《深入理解计算机系统》chapter2读书笔记

    2.1 2.1.6 bool代数简介 not ~ and & or | exclusive-or ^ 我们可以将四个bool运算扩展到位相量的运算 `a = [a_w-1, a_w-2, a_ ...

  2. 深入理解JVM(第二版读书笔记)

    一  开始前 HotSpot:http://xiaomogui.iteye.com/blog/857821 http://blog.csdn.net/u011521890/article/detail ...

  3. 【我的JS第三本】JavaScript_DOM编程艺术第二版读书笔记

    经过前一段时间HTML&CSS的学习,感觉视频加读书是一个比较不错的学习方法,两者相辅相成,互相补充,所以也准备看看关于JavaScript的书. 2015年12月14日,之前使用韩顺平老师的 ...

  4. Python核心教程(第二版)读书笔记(三)

    第三章Python基础 2010-04-09 换行  一行过长的语句可以使用反斜杠'\'分解成几行.有两种例外情况一个语句不使用反斜线也可以跨行. 1.在使用闭合操作符时,单一语句可以跨多行.例如:在 ...

  5. 《细说PHP》第二版--读书笔记

    第五章 PHP的基本语法 5.2.4 在程序中使用空白的处理 5.3 变量 5.3.1 变量的声明 在php中变量的声明必须是使用一个$符号,后面跟变量名来表示 unset()函数释放指定变量 iss ...

  6. 刘鹏老师和王超老师的计算广告第二版读书笔记

    广告的定义与目的 广告的基本概念 广告的分类 在线广告的表现形式 横幅广告 文字链广告 富媒体广告 视频广告 交互式广告 社交广告 移动广告 邮件营销广告 广告的基本概念 需求方:可以是广告主.代表广 ...

  7. 《计算广告》第二版 读书笔记

    在线广告创意类型: 横幅广告 文字链广告 富媒体广告 视频广告 社交广告 移动广告 邮件定向营销广告. 广告发展历程: 合约广告->定向广告->竞价广告 (上下文广告) 术语解释: ADN ...

  8. sql注入攻击与防御第二版读书笔记二——SQL盲注利用

    寻找并确认SQL盲注 强制产生通用错误 注入带副作用的查询 如 mssql waitfor delay '0:0:5' mysql sleep() 拆分与平衡 5 -> 7-2 常见SQL盲注场 ...

  9. Effective Java 英文 第二版 读书笔记 Item 14:In public classes,use accessor methods,not public fields...

    本章主要分析 公开属性与私有属性提供公开get.set方法两种方式对比 // Degenerate classes like this should not be public! class Poin ...

  10. Think in Java第四版 读书笔记10 第16章 数组

    Think in Java第四版 读书笔记10 第16章 数组 数组和容器很像 但他们有一些差别 16.1 数组为什么特殊 数组与容器的区别主要在效率和存储类型 效率:数组是简单的线性序列 使得数组的 ...

最新文章

  1. C++中STL中的大、小、相等概念
  2. C语言函数指针 和 OC-Block
  3. 1.1.3 以Self Host方式寄宿Web API
  4. Java之杨辉三角的实现
  5. 【洛谷 - P1231 】教辅的组成(网络流最大流,拆点)
  6. MySQL主从数据同步延时分析
  7. 计算机图形学完整笔记(三):裁剪
  8. entrez检索系统要服务器吗,Entrez 系统
  9. 华为3COM正式更名为『杭州华三通信技术有限公司(H3C)』
  10. android语音识别sdk接入收费吗,百度语音识别开放平台SDK使用方法
  11. macbook双系统怎么装mysql_mac装win10双系统的方法_如何安装macos苹果和win10双系统...
  12. n918st能刷Android5吗?,中兴 N918st(V5S 双4G版)获取Root权限服务含精简系统方案
  13. 华容道html源码,华容道(项目源代码)
  14. 虚幻四蓝图实战(下车减速人物加速蓝图接口通信)
  15. 关于 RestTemplate 中文乱码和List接收
  16. 使用Auto.js实现蚂蚁森林自动收取能量
  17. printf和println和print区别
  18. 什么叫逐行扫描和隔行扫描
  19. 我的世界未能从服务器注册表数据,【经验之谈】“User Profile Service 服务未能登录,无法加载用户配置文件”实战历程...
  20. 模拟实现ps aux | grep xxx

热门文章

  1. Windows Server 2008开启IIS
  2. 手游破解手段介绍及易盾保护方案
  3. 智能家居与SmartConfig技术,WI-FI直连
  4. linux c语言录音程序,windows C语言录音
  5. APPserver安装教程(手把手教你搭建)
  6. RocketMQ 的优缺点
  7. OSSIM架构与组成综述
  8. 新年换新手机,等等等!
  9. 新版Discuz仿今日头条新闻资讯商业版模板源码
  10. Android中使用MediaCodec视频编码异步实现