计算机体系结构 初步 计算机就是一个傻子,所有的事都得一步一步告诉怎么做,先做什么,后做什么,做的过程中出现情况怎么办,所有的事情,都是设计好告诉怎么做;所以当感觉一个地方缺个什么东西的时候,应该会有那么个东西,可以抽象的先理解一下,便于整体的理解;计算机的每一个部分,基本上都是有个控制器去负责进行的操作虚拟化: 一点就通的描述 看起来是这样的,用起来是那样的逻辑上是这样的,物理上是那样的 寄居虚拟化 就是虚拟机在操作系统之上 裸机虚拟化 就是虚拟机直接在硬件之上,不过还是有个Hypervisor(虚拟机自带的),提供一个类似的元操作系统; 计算机的虚拟化:必须要给虚拟机一个假的独立的环境,让他误以为自己处在一个独立的环境当中,于是就需要模拟cpu、内存、硬盘、网络等资源,模拟一个独立完整的硬件环境。 指令系统结构 指令系统 RISC 最本质的特征 通过load/store结构简化指令间的关系,所有的运算指令都是对寄存器运算,所有的访存都通过专用的指令load/store进行 优点 简化了指令间相关性的判断的复杂度,因为CPU只需要寄存器号的比较就可以判断指令之间的相关性,而复杂指令系统需要对访存的物理地址进行比较自己的理解 复杂指令系统没有进行这么明确的分类处理,所以比较指令相关性,访存指令就需要访问物理地址;精简指令系统有明确的分类,对于运算类指令,只需要比较寄存器号就可以; 指令间的相关性判断简单,则流水线,乱序执行的性能就能提升,所以RISC也是一种提升性能的技术 存储管理 段式存储管理 段号+段内偏移是对物理地址进行逻辑上的划分,使用的时候要坚持地址的合法性,同时段内的地址仍需要连续,遇到程序占用内存较大时,还是会出现内存碎片; 页式存储虚拟管理 页号+页内偏移是将虚拟地址进行划分,然后用页表存储虚拟地址和物理地址的对应,通过硬件实现快速的地址转换;通过TLB(块表,页表缓冲器)实现地址转换的加速TLB(转换后援缓冲器) 由于页表在内存里存储,每次访问内存效率低,所以使用TLB利用局部性原理实现缓存,从而提高效率;位置相当于页表的cache 实现的功能 各个进程运行在各自独立的虚拟地址空间,提供内存映射,公平的物理地址内存分配,共享虚拟内存; 问题 怎么就对虚拟地址进行划分了?也是页号+页内偏移,看书里的描述页内的地址也是可以不连续的,怎么实现的?解决: 看了超标量处理器之后,自然就明白了;页内也是连续的,不过可以通过多级页表实现子页表之间的不连续; MMU(存储管理部件) 是一个硬件 指令系统的分类 堆栈型 就是默认操作数是栈顶,然后将结果保存回栈顶,省略操作数 累加器型 就是默认最终数据保存在累加器中,隐含一个操作数,累加器(隐含第一个操作数) 寄存器-存储器型 操作码+操作数都有,就是不对运算和访存进行分类限制 寄存器-寄存器型 操作码+操作数都有,对运算和访存进行分类限制运算指令的操作数只能来自寄存器,所有的访存都必须通过load/store指令进行优点 寄存器之间的操作速度快指令之间的相关性容易判断 访存地址需要关注的点 访存地址是否对齐,指令系统是否支持不对齐访问大尾端还是小尾端 访存方式 寄存器寻址 ADD R1, R2 regs[R1] = regs[R1] + regs[R2] 立即数寻址 ADD R1, #2 regs[R1] = regs[R1] + 2 偏移量寻址 ADD R1,100(R2) regs[R1] = regs[R1] + mem(100+regs[R2]) 中断异常 主要就是保证“走之前和回来之后必须一摸一样,好像什么都没发生过一样“中断需要保存的东西 中断之前的PC值,各种相关的寄存器的值(通用,状态,特殊) 原子操作 不可被中断的一个或一系列操作注: 物理上的原子性是一个事实,这里的原子性是人为定义的,需要用一些行为去保证原子性; 异常和中断的理解 其实有很多种,比如异常是程序执行产生的,中断是设备产生的; 软硬件协同 主要介绍了一些通用的规定 ABI规定,存储参数的寄存器,只能有8个; 程序执行过程中的堆栈 和C语言的内存管理一样 上下文切换场景 函数调用 RISC的典型做法:硬件仅仅是提供一个机制(如:bl)用于在改变指令流的同时保存一个返回地址到通用的寄存器,其余的都由软件来完成; 异常和中断 高配和非高频两种处理方式,就是希望处理效率提高 系统调用 就是操作系统为用户态实现的子程序;比如:mkdir rmdir(,和函数调用差不多,就是多了一个特权等级的切换(root,普通用户)尽可能的在寄存器之间进行传递,这样可以避免核心态空间和用户态空间之间进行不必要的内容复制;即尽可能的避免访存的操作; 进程 虚拟化技术让每一个进程感觉自己拥有一个独立的CPU和内存空间(人要是能这么骗自己那可太好玩了,深深的满足自恋)虚拟化技术实现,然后方便实现CPU的分时复用 线程 是程序执行的最小单位,是进程的一个执行流线程之间共享内存空间和打开文件等资源,但在逻辑上拥有独立的寄存器和状态和栈注: 进程之间的内存空间是独立的,同一个进程里的所有线程是共享内存空间和打开文件等资源; 计算机硬件结构 初步 冯诺依曼结构(哈佛结构)人脑的计算方式 类人脑计算机结构 计算机组成原理和结构 计算机组成 运算器 各种运算部件+寄存器条件码寄存器:保存当前的运算结果的状态,如正数,复数,是否溢出复杂运算:乘法,浮点数可以用程序实现,也可以用专用的寄存器 控制器 控制指令流,每条指令的执行程序计数器(pc) 存放当前指令的地址 指令寄存器 存放当前正在执行的指令(整个进程的指令都在里面存着) 问题 他俩这个存是有什么意义?正在执行了,还存着地址干嘛?存接下来的地址不是更好吗?原因 指令寄存器需要根据PC里存储的指令地址进行指令的读取,他们俩是有一个先后顺序的; 存储器 这里其实就是指内存DRAM 动态随机访问存储器 SRAM 静态随机访问存储器 cache 高速缓存 cache一般用的时SRAM Cache是内存的一个映像,处理器访问Cache和访问内存用的是一样的地址 ROM read only memory(只读存储器)很小的,用来存储基本输入输出系统(BIOS) 注 数据和指令在cache和内存之间的调动是由硬件完成的数据和指令在内存和外存之间的调动是由操作系统完成的 存储层次 寄存器 寄存器是一种存储设备,既可以保存数据,也可以保存地址(地址本来就是一堆数) 一级缓存二级缓存三级缓存内存外存 存储器之间预先进行的数据交换 局部性原理 时间局部性空间局部性 注: 缓存之间基本差一个数量级,一级是几个~~,二级是几十个,内存就是几百个;存储器和寄存器的区别:地址编码,存储器是地址编码的,寄存器不是的; 输入输出设备(IO设备) GPU,硬盘,闪存(SD卡,U盘,SSD固态磁盘)注: X86处理器IO和內存分开;ARM是在一起的; 计算机硬件结构 CPUGPU北桥 离CPU最近的芯片,主要负责控制显卡,内存和CPU之间的通信,向上连接CPU,向下连接南桥;也就是负责对带宽要求高的IO接口和CPU的通信 南桥 主要负责硬盘,键盘以及各种对带宽要求比较低的IO接口和CPU之间的通信 结合上面的四个硬件,就衍生出很多的结构组成:四片,三片,两片,单片; GPU有时是独立的,有时就是集成在CPU或者北桥里;除了单片结构,其他结构都是有独立的南桥的;有北桥的时候,内存控制器是集成在北桥里的,CPU和内存之间的通信也是北桥负责,没有北桥,或者弱北桥的时候,内存控制器是直接在CPU里的; 处理器和IO设备之间的通信 存储设备和IO设备本质的物理结构就不一样,IO都是具有特定功能的部件,所以处理器和IO设备之间的通信需要特殊的处理方式;设备管理器进行一系列的控制,提供IO寄存器,处理器通过读写IO寄存器来访问设备,写入寄存器的数据会由设备管理器进行解析成命令,所以又称IO寄存器的访问称为命令字;IO寄存器的寻址 内存映射IO 寄存器和内存进行统一的编制,没啥区别,操作系统通过状态的设定,限制应用程序访问IO寄存器 特殊IO指令 使用特殊的IO指令进行IO操作,IO的地址空间和内存空间重叠,但是指向的地方不一样。操作系统通过不让应用程序访问这些专用指令进行限制; 问题: 为啥不让应用程序直接操作IO设备呢”?解决: 重点在于对“应用程序”这四个字的理解,废话木,当然不能让应用程序跳过操作系统直接操作IO设备了; 处理器和IO设备之间的同步 处理器通过向IO寄存器写入命令字操作IO设备,这个写入读取不是一次,而是一系列的;查询(轮询) 太浪费时间和资源,所以都用中断CPU是在一个时间片过来查一次; 中断 CPU在等待设备完成某个操作时继续去执行其他的进程,设备处理完成后,自行产生一个中断信号来中断CPU的执行,(相当于查询过程中,不停查询的状态值交给设备自己去完成)注意事项 CPU识别的中断位,需要在中断执行结束之前归位,不然又会被识别,这个一般都是自动实现的; 存储器和IO设备之间的数据传送 PIO 存储器和IO设备之间的数据传输需要通过通用寄存器 其实就是通过CPU 适用于对带宽要求较小的IO设备 DMA(直接存储器访问) 存储器和IO设备之间的数据传输直接进行,相当于IO设备直接读写内存适用于对带宽要求较高的IO设备:网卡,显卡 注: DMA其实是和CPU并行工作的,就是因为CPU处理IO的操作是高延时的,浪费CPU的资源,所以设计出来DMA和CPU并行工作,解放CPU去干别的事; 计算机总线接口技术 总线 本质作用就是完成数据交换;不过含义很广,包换整套的软件硬件架构;是一整套协议 分类 单向,双向单工,半双工,全双工并行,串行 片上总线 AXI架构 单向串行传输,双握手协议 内存总线系统总线I/O总线(设备总线) CPU微架构 运算器设计 二进制和逻辑电路 原码,反码,补码的理解 原码就是人们用来解决表示数据的一种二进制表示方法补码,就是人们用来解决原码存在的一些问题(减法实现复杂,+0,-0)而想出来的一种二进制表示方法;我们现在用的表示整数的方法,就是补码(所以还不如就叫他原码呢),所以忘记什么通过原码,反码计算原码的方法吧,记得他就是求模取余得来的就行; MOS晶体管 简单理解就是三个极,通过一个极的电压的变化,决定另外的两个极是通还是不通,从而实现动态的二值电路; 逻辑电路 就是所有基础门的组合; 指令流水线(控制器的设计) 时钟的作用 同步CPU需要时钟,MOS晶体管是有电阻,两级之间是有电容的,CMOS电路是有延迟的,两个输入端延迟不一样可以加一个触发器去处理;但是这个时延只是被隐藏了,还是存在的,那整个电路的时延都存在,还不一样,数据就没法处理;所以,需要时钟周期来容纳传播时延,并且时钟周期应当大到需要容纳所有逻辑门的传播时延。这个周期结束统一处理,下个周期开始再干别的,周期结束再次统一处理;为什么不用异步CPU:实现太复杂; CPU的数据通路 程序计数器(PC)指令寄存器(指令存储器)译码部件 他可不只是译码,译码以后,读写那些通用寄存器,执行那些运算,是否读写数据存储器,根据控制流指令来决定PC的更新,都是他负责的;控制器的核心部件; 通用寄存器运算器数据存储器 根据地址进行数据的存储,主要是访存指令 流水线处理器(超标量处理器) 流水线 划分一条指令的执行过程: 取码,译码,执行,访存,写回 指令相关 数据相关 如果两条指令,访问同一个寄存器或者内存单元,并且这两条指令中至少有1条是写该寄存器或者内存单元的指令; 控制相关 如果两条指令,一条是转移指令并且另一条指令是否被执行取决于该转移指令的执行结果 结构相关 如果两条指令同时使用用一份硬件资源 就是两条指令同时需要流水线中的同一个功能部件 转移预测 就是对正在运行的指令进行预测,预测接下来,会执行那些指令,提前进行取指,一般都是对转移和跳转指令进行预测,等转移和跳转指令执行后,在进行对预测结果的修正;预测算法总结一句话,就是怎么根据历史的经验预测这一次的结果。 乱序执行 就是当前的指令执行时间会有点长,可以把后面的对于当前指令的执行不影响的拿到前面执行乱序执行的指令需要有序的结束,提供了一个重排序缓冲(ROB),并且把执行的结果临时的存储在重命名寄存器,方便后续指令运行时的取用; 超标量 就是并行处理,允许指令流水线的每一个阶段同时处理多条指令,这个指令译码,那个取值,之类的检查相关性:不光是前后拍的指令,还包含同一拍中的多条指令 并行处理结构 并行编程 指令级并行 就是流水线的重叠执行多发射技术 允许一个时钟周期执行多条指令:多车道 动态调整 允许后续指令越过前面被阻塞的指令继续执行:超车 寄存器重命名 可以消除RAW,WAW,的假相关,并且支持猜测执行 数据级并行 对集合或者数组中的元素同时执行相同的操作 比如for循环使一个数组中的所有元素+2; 任务级并行 不同的进程和线程分配到不同的处理单元上执行需要程序员进行编程进行分配 多核处理器结构 多核处理器的访存结构 各级Cache是私有还有共享,内存的共享,共享之后怎么进行访问,怎么保证正确的操作;一般是最后一级Cache是片内共享,其他是私有;片间共享内存;正确的访存 存储一致性Cache一致性 具体作用是保证把某个处理器核新写的值传播给其他处理器核确保所有处理器核看到的是一致的共享存储那内容;注: 满足Cache一致性也不能保证数据处理和存储的正确,比如两个核同时更改一个值,所以好需要一些机制(同步机制); 多核处理器的互连结构 片上总线 数据总线,地址总线,控制总线易于实现广播只适用于核不多的情况 交叉开关 简单理解:就是一个开关集合,每一个点就是一个开关,点通则连通带宽高,可以实现并行(在互不相关的情况下)物理代价大只适用于核不多的情况 片上网络 类似TCP/IP协议的通信,竟然有路由器,路由算法,流量控制; 多核处理器的同步机制 锁操作 主要用于保护临界区 栅障操作 主要用于实现全局同步 事务内存 主要用于保护临界区 注: 整个多核处理器就是知道点概念,没有什么理解; 性能分析 性能分析的目的 计算机系统评价和性能分析就是采用测量、模拟、分析等方法和工具,获得计算机系统运行 预定任务时的性能特性,找出已有系统的性能瓶颈,然后进行改进和提高。说白了:就是通过一系列的手段,获取当前的性能特性,找出瓶颈,进行优化; 性能指标和相关参数 性能指标 性能最本质的定义 完成一个任务所需要的时间完成一个任务所需要的时间 = 完成该任务需要的指令数 * 完成每条指令需要的拍数 * 每拍需要的时间; 衡量指标 计算机系统的性能有许多衡量指标,如执行时间或者响应时间、吞吐率、加速比、每条指令的时钟周期数(CPI)、每秒执行百万条指令数(MIPS)、每秒执行百万浮点运算数(MFLOPS)、每秒执行的事务数(TPS)和归一化的执行时间等; CPI 执行的每个指令所用的时钟周期数 执行程序所用的时钟周期数/执行的指令数目; IPC(insts per cycle) 每周期运行的指令数;CPI的倒数; CPU时间 CPU时间=程序执行的指令数*CPI*时钟周期(一个周期的时间)CPU时间=程序执行的指令数*CPI/时钟频率通常所说的CPU时间,说的是CPU的计算时间,不包括等待IO的时间,或者执行其他程序的时间;CPU时间 = 用户CPU时间(CPU实际执行用户程序的时间)+ 系统CPU时间(CPU花在执行操作系统的时间) 并行系统 加速比(Speedup) 程序在单核系统运行的时间/程序在多核系统运行的时间 并行效率E 加速比/核数 程序执行时间的三个关键点 CPU执行程序员所需要的时间 = 程序这个的指令数 * cycles/指令数(CPI) * seconds/cycle(时钟频率);程序执行的指令数 算法编译器指令集架构 CPI/IPC 微体系结构设计指令集架构 时钟周期 微体系结构设计 周期大小的设计 物理设计电路和工艺 CPU的时钟频率 相关参数 CPU utilized(CPU利用率)frontend cycles idle(前端堵) 通常是分支预测失败和指令cache缺失stalled(堵)-cycles-frontend backend cycles idleLLC 三级cache 测试程序集 由于应用的多样性,不同的计算机对不同的应用有不同的适应性,很难建立一个统一的标准来比较不同计算机的性能,因此人们通过一系列基准程序集来评价计算机性能;说白了:就是硬件架构,系统,应用实在太多样了,实在没有一个测试程序集可以反应整体的性能,所以就搞了一堆;测试程序集分类 General Purpose Benchmarks Ceekbench 6.xSPEC CPU2006&CPU2017SVE Kernels Cloud & Server Benchmarks Cloud&Server BenchmarksDatabase BenchmarksSPECjbbtomcat HPC Benchmark HPC(High Performance Computing):高性能计算机群HPC Benchmark PC Benchmarks CinebenchPCMarkWINRAR压缩解压缩superπ,多线程圆周率计算wPRIME benchmarklzbenchsysbenchSPECjvm2008 性能分析方法 性能建模 主要用于设计的早期还没有实际系统阶段,又可以细分为基于模拟的建模和基于分析的建模; 性能测量 在原型系统出来之后,实际机器的测量提供了一个附加的反馈可以帮助验证设计阶段的分析模型; Perf工具 perf能够对CPU核操作系统性能相关是指标进行采样,开销较低;定位热点指令,热点函数; 硬件 提交的指令,执行的时钟周期,cache失效的次数,分支预测的次数(总的和失败的) 软件 进程的上下文切换,缺页,任务迁移,系统调用的次数 perf list 用来查看perf所支持的性能事件 perf top 对于一个指定的性能事件(默认是CPU周期),显示时间发生的次数最多的函数或者指令;定位热点函数和指令;-p<pid> 进分析目标进程极其创建的线程 -e<event> 指明要分析的性能事件,可以接很多个事件,用逗号隔开;事件就是一个项,比如分支预测,分支预测的失败,icache的load,等等,可以很细; -G 得到函数的调用关系图 perf stat(统计) 分支指定程序的性能概况:指令的指令数,所用的时钟周期;-r 重复执行命令,求平均值 -n 只显示任务执行的时间time ./exe这个命名也可以 -o file 指定输出文件 perf record 将性能数据记录到当前目录下的perf.data;随后可以使用perf report 或者 perf annotate进行性能的分析;是一个记录输出的功能; perf report 读取perf.data文件,是上面的配套的显示功能; perf annotate 读取perf.data文件,显示注释过的代码,比上面的好看一点; perf trace 监控特定线程或者进程使用的系统调用以及该应用程序接收的所有信号; perf命令的常用 产生perf perf record -g --call-graph lbr -o {path}/perf.data running-commandQA 如果报错: PMU Hardware doesn't support sampling/overflow-interrupts.报错原因:硬件太老,不支持更精确的函数调用栈的寻址模式。报错解决: 1. 使用fp帧指针寻址(可以接受有些函数统计不到): perf record -g --call-graph fp -o {path}/perf.data running-command2. 找个相对较新的硬件平台。 打开perf perf report -i perf.data