Open ysh329 opened 4 years ago
表:时间单位的换算
单位 | 英文缩写 | 与1秒的比例 |
---|---|---|
分 | m | 60 |
秒 | s | 1 |
毫秒 | ms | 0.001、1/1000、$1 * 10^{-3}$ |
微秒 | μ s | 0.000001、1/1000000、$1*10^{-6}$ |
纳秒 | n s | 0.000000001、1/1000000000、$1*10^{-9}$ |
皮秒 | p s | 0.000000000001、1/1000000000000、$1*10^{-12}$ |
等待的过程就会给程序运行带来延时,使得性能下降,为了能感受到延时的影响。下面我们以访问3.3GHz的CPU寄存器的延时为例,下表阐述这些过程的时间量级差别,表中是发生单词操作的时间均值,并等比例放大为我们能感受到的时间(见表格相对时间比例),即假设一次寄存器访问的0.3ns,相当于现实生活中的1秒。
表:系统的各种延时
事件 | 延时 | 相对时间比例 |
---|---|---|
1个CPU周期 | 0.3ns | 1s |
L1缓存访问 | 0.9ns | 3s |
L2缓存访问 | 2.8ns | 9s |
L3缓存访问 | 12.9ns | 43s |
主存访问(从CPU访问DRAM) | 120ns | 6分钟 |
固态硬盘I/O(闪存) | 50-150μs | 2-6天 |
旋转磁盘I/O | 1-10ms | 1-12月 |
互联网:从旧金山到纽约 | 40ms | 4年 |
互联网:从旧金山到英国 | 81ms | 8年 |
互联网:从旧金山到澳大利亚 | 183ms | 19年 |
TCP包重传 | 1-3s | 105-317年 |
OS虚拟化系统重启 | 4s | 423年 |
SCSI命令超时 | 30s | 3000年 |
硬件虚拟化系统重启 | 40s | 4000年 |
物理系统重启 | 5m | 32000年 |
在剖析检查CPU的使用情况,找性能改进空间时,从不同角度可以获取不同的信息:
处理器:插到系统插槽或者处理器板上的物理芯片,以核或者硬件线程的方式包含一块或者多块CPU。
核:一颗多核处理器上的一个独立CPU实例。核的使用是处理器扩展的方式。又称为芯片级多处理(chip-level multiprocessing,CMP)。
硬件线程:一种支持在一个核上同时执行多个线程(包括Intel的超线程技术)的CPU架构,每个线程是一个独立的CPU实例。这种扩展的方法又称为多线程。
超线程技术
超线程技术把多线程处理器内部的两个逻辑内核模拟成两个物理芯片,让单个处理器就能使用线程级的并行计算,进而兼容多线程操作系统和软件。超线程技术充分利用空闲CPU资源,在相同时间内完成更多工作。
虽然采用超线程技术能够同时执行两个线程,当两个线程同时需要某个资源时,其中一个线程必须让出资源暂时挂起,直到这些资源空闲以后才能继续。因此,超线程的性能并不等于两个CPU的性能。而且,超线程技术的CPU需要芯片组、操作系统和应用软件的支持,才能比较理想地发挥该项技术的优势。
超线程与多核心区别
- 超线程技术是通过延迟隐藏的方法,提高了处理器的性能,本质上,就是多个线程共享一个处理单元。因此,采用超线程技术所获得的性能并不是真正意义上的并行。从而采用超线程技术获得的性能提升,将会随着应用程序以及硬件平台的不同而参差不齐;
- 多核处理器是将两个甚至更多的独立执行单元,嵌入到一个处理器内部。每个指令序列(线程),都具有一个完整的硬件执行环境,所以各线程之间就实现了真正意义上的并行。
CPU指令:单个CPU操作,来源于它的指令集。指令用于算术操作、内存I/O,以及逻辑控制器。指令集的类型包括不限于x86、MIPS、Sparc、Alpha、ARM等;
- 指令集的先进与否,也关系到CPU的性能发挥,它也是CPU性能体现的一个重要标志。
- 每款CPU在设计时就规定了一系列与其硬件电路相配合的指令系统。
- 指令的强弱也是CPU的重要指标,指令集是提高微处理器效率的最有效的工具之一。
- 从现阶段的主流体系结构讲,指令集可分为复杂指令集和精简指令集两部分。
逻辑CPU:又称为虚拟处理器(有时也称为虚拟CPU),一个操作系统CPU的实例(一个可调度的CPU实体)。处理器可以通过硬件线程(这种情况又称为虚拟核)、一个核,或者一个单核的处理器实现。
调度器:把CPU分配给线程运行的内核子系统。
【线程调度器】
操作系统的核心,它实际就是一个常驻内存的程序,不断地对线程队列进行扫描,利用特定的算法(时间片轮转法、优先级调度法、多级反馈队列调度法等)找出比当前占有CPU的线程更有CPU使用权的线程,并从之前的线程中收回处理器,再使待运行的线程占用处理器。
【Linux 调度器】
Linux 调度器(BFS) 是一个进程调度器,其一般原理是, 按所需分配的CPU计算能力, 向系统中每个进程提供最大的公正性, 或者从另外一个角度上说, 他试图确保没有进程被亏待。BFS构造简单,但性能出色。它让用户的桌面环境达到了前所未有的流畅。2010 年,Android 使用 BFS 作为其操作系统的标准调度器。
【CPU调度器】
又称为虚拟处理器,一个操作系统CPU的实例(一个可调度的CPU实体)。处理器可以通过硬件线程(这种情况又称为虚拟核)、一个核,或者一个单核的处理器实现。
以上三个概念,应该是一个东西。一般是一个内核线程对应一个内核轻量级进程对应一个用户线程。导致说法有些混乱。
【问题】那调度器是对于所有核来说的嘛,还是说,每个逻辑CPU有各自的调度器?是针对所有核的。
运行队列:一个等待CPU服务的可运行线程队列。在Solaris上常被称为分发器队列。
队列机制
队列是一种数据结构,它具有先进先出的特点,是一种应用很广泛的结构。在计算机或计算机之间,为了提高计算机或计算机之间的工作效率,常采用队列机制。
下面,将用简单模型演示CPU和CPU的基本原理,首先从CPU架构开始。
下图是一个CPU架构的示例,单个处理器内共有四个核和八个硬件线程。
硬件线程:前面介绍概念的时候说过,它是一种支持在一个核上同时执行多个线程(包括Intel的超线程技术)的CPU架构,每个线程是一个独立的CPU实例。这种扩展的方法又称为多线程。
图:CPU架构
该图左侧显示物理架构,右边是从操作系统角度看到的景象。
每个硬件线程可按逻辑CPU寻址(即操作系统看来的角度),因此这个处理器看上去有八块CPU。因为本身物理上的拓补结构,操作系统还会根据额外的这些信息,如哪些CPU在同一个核上,来提高调度器(把CPU分配给线程运行的内核子系统)的调度质量。
为提高I/O性能,处理器提供多种硬件缓存。下图展示缓存大小的关系,越小则速度越快(平衡),且越靠近CPU。
图:CPU缓存大小
当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据;如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。
缓存之所以有效,主要是因为程序运行时对内存的访问呈现局部性(Locality)特征。这种局部性既包括空间局部性(Spatial Locality),也包括时间局部性(Temporal Locality)。有效利用这种局部性,缓存可以达到极高的命中率。
在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。
此外,缓存存在与否,以及是在处理器里集成还是在处理器外,取决于处理器的类型。早期的处理器集成的缓存层次较少。
图:CPU缓存架构
一级缓存(Level 1 Cache)简称L1 Cache,位于CPU内核的旁边,是与CPU结合最为紧密的CPU缓存,也是历史上最早出现的CPU缓存。由于一级缓存的技术难度和制造成本最高,提高容量所带来的技术难度增加和成本增加非常大,所带来的性能提升却不明显,性价比很低,而且现有的一级缓存的命中率已经很高,所以一级缓存是所有缓存中容量最小的,比二级缓存要小得多。
通常一级缓存分为一级数据缓存(Data Cache,D-Cache)和一级指令缓存(Instruction Cache,I-Cache)。二者分别用来存放数据以及对执行这些数据的指令进行即时解码,而且两者可以同时被CPU访问,减少了争用Cache所造成的冲突,提高了处理器效能。大多数CPU的一级数据缓存和一级指令缓存具有相同的容量,
二级缓存是CPU性能表现的关键之一,在CPU核心不变化的情况下,增加二级缓存容量能使性能大幅度提高。而同一核心的CPU高低端之分往往也是在二级缓存上有差异,由此可见二级缓存对于CPU的重要性。
从理论上讲,在一颗拥有二级缓存的CPU中,读取一级缓存的命中率为80%。也就是说CPU一级缓存中找到的有用数据占数据总量的80%,剩下的20%从二级缓存中读取。由于不能准确预测将要执行的数据,读取二级缓存的命中率也在80%左右(从二级缓存读到有用的数据占总数据的16%)。那么还有的数据就不得不从内存调用,但这已经是一个相当小的比例了。较高端的CPU中,还会带有三级缓存,它是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。
LRU算法
为了保证CPU访问时有较高的命中率,缓存中的内容应该按一定的算法替换。一种较常用的算法是“最近最少使用算法”(LRU算法,Least recently used),它是将最近一段时间内最少被访问过的行淘汰出局。因此需要为每个被访问内容行设置一个计数器,LRU算法是把命中行的计数器清零,其他各行计数器加1。当需要替换时淘汰行计数器计数值最大的数据行出局,其计数器清零过程可以把一些频繁调用后再不需要的数据淘汰出缓存,提高缓存的利用率。
三级缓存是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。
L3 Cache(三级缓存),分为两种,早期的是外置,截止2012年都是内置的。而它的实际作用即是,L3缓存的应用可以进一步降低内存延迟,同时提升大数据量计算时处理器的性能。而在服务器领域增加L3缓存在性能方面仍然有显著的提升。
比方具有较大L3缓存的配置利用物理内存会更有效,故它比较慢的磁盘I/O子系统可以处理更多的数据请求。具有较大L3缓存的处理器提供更有效的文件系统缓存行为及较短消息和处理器队列长度(前面提到的概念运行队列:一个等待CPU服务的可运行线程队列)。
前文在术语部分,介绍了CPU运行队列的概念,即一个等待CPU服务的可运行线程队列。不过在讲述运行队列概念前,我们先看一下进程生命周期。
下图展示简化的进程生命周期示意图,其中包含的状态有:
图:进程生命周期
根据上面的状态概念,下图展示了一个内核调度器管理的CPU运行队列。
图:CPU运行队列
其中,正在排队的R状态和就绪运行的软件线程数量是一个表示CPU饱和度的性能指标。在这一瞬间,有4个排队线程,加上一个在CPU上运行的线程。其中,花在等待CPU运行上的时间又被称为运行时延或者分发器队列延时。
对于多处理器系统,系统内核为每个CPU都提供了各自的运行队列,并尽量使线程被放到同一队列中,这意味着线程更有可能在同一个CPU上运行,因为CPU缓存保存了他们的数据。且这些缓存也被称为热缓存,这种选择运行CPU的方法称为CPU关联。
在NUMA系统中,这会提高内存局部或者本地性(Locality),通过有效利用这种局部性(CPU访问内存的速度与节点的距离有关,CPU访问本地节点的内存速度最快),缓存可以达到极高的命中率。
NUMA架构
也称非一致存储访问结构(NUMA:Non-Uniform Memory Access),把一台计算机分成多个节点,每个节点内部拥有多个CPU,节点内部使用共有的内存控制器,节点之间是通过互联模块进行连接和信息交互。
因此节点的所有内存对于本节点所有的CPU都是等同的,对于其他节点中的所有CPU都不同。
因此每个CPU可以访问整个系统内存,但是访问本地节点的内存速度最快(不经过互联模块),访问非本地节点的内存速度较慢(需要经过互联模块),即CPU访问内存的速度与节点的距离有关。
在NUMA系统中,通过提高CPU对本地内存的使用,从而提高系统性能。这也避免了队列操作的线程同步开销如mutex锁。若运行队列是全局的且被所有CPU共享,这种开销会影响扩展性。
线程同步
当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态。
互斥锁mutex
Linux中提供一把互斥锁mutex(也称之为互斥量)。每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁。但通过“锁”就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了。
应注意:同一时刻,只能有一个线程持有该锁。
所以,互斥锁实质上是操作系统提供的一把“建议锁”(又称“协同锁”),建议程序中有多线程访问共享资源的时候使用该机制。但,并没有强制限定。 因此,即使有了mutex,如果有线程不按规则来访问数据,依然会造成数据混乱。
本文将会介绍CPU相关背景、CPU术语、基本模型。并在该过程补充相关概念与内容。
中央处理器 (英语:Central Processing Unit,缩写:CPU)是计算机的主要设备之一,功能主要是解释计算机指令以及处理计算机软件中的数据。
CPU推动软件运行,因而通常是系统性能分析的首要目标,现代系统一般都为多颗CPU组成,通过内核调度器共享给所有运行软件。当需要的CPU资源超过系统力所能及的范围,进程里的线程或任务将会排队,等待轮候自己运行的机会。(这其中有几个关键词,后面会一一展开)