在计算机组成原理乃至体系结构中,“性能”都是最重要的一个主题。学习和研究计算机组成原理,就是在理解计算机是怎么运作的,以及为什么要这么运作。“为什么”所要究竟的事情,很多时候就是提升“性能”
什么是性能?时间的倒数
计算机的性能,主要以如下两个指标来衡量:
- 响应时间,或者叫做执行时间:
- 响应时间是指,我们执行一个程序,到底需要花多少时间。花的时间越少,性能越好
- 提升性能就是让计算机“跑的更快”
- 吞吐率,或者叫做带宽:
- 吞吐率就是指我们在一定的时间范围内,到底能处理多少事情。能够处理的事情越多,性能越好(这里的事情指的是处理的数据或者执行的程序指令)
- 提升性能就是让计算机“搬得更多”
如果响应时间短,在相同时间内就能多处理一些请求。所以,缩短程序的响应时间,通常会提升吞吐率。
除了缩短响应时间,还可以通过并行的方式来提升吞吐率,譬如现在的8核、16核处理器。(人多力量大)
提升吞吐率的办法有很多,通常只要堆硬件、加机器就能实现。但响应时间的提升则没那么容易,CPU的性能发展已经遇到瓶颈了。
一般我们把性能,定义成响应的倒数,也就是:
性能
=
1
/
响应时间
性能=1/响应时间
性能=1/响应时间
由此,响应时间越短,性能的数值越大。譬如:同样一个程序,在 Coffee Lake 上,仅需 30s 即可运行完成。在 Sandy Bridge 上,需要 1min 才能完成。那么我们说 Coffee Lake 的性能是 1/30,Sandy Bridge 的性能是 1/60,它们的性能比为 2。于是我们可以说,Coffee Lake 的性能是 Sandy Bridge 的 2 倍。
计算机的计时单位—CPU时钟
为什么不直接用时间来衡量
虽然时间是一个很自然的用来衡量性能的指标,但是用时间来衡量是,有两个问题
时间不准
我们自己写个程序,记录程序开始运行的时间和程序停止运行的时间(这个时间叫做 Wall Clock Time 或 Elapsed Time),计算其差值,会发现每次的结果都不尽相同。其原因有很多。
- 首先,计算机中同时运行很多程序,CPU不停地在各程序之间进行切换。在这段时间差内,CPU很可能被切换去运行其他程序了
- 其次,程序运行时,可能要从网络、硬盘读取数据,才能给到内存和CPU,这也是耗时操作
综上,想准确统计某个程序的运行时间,进而比较实际性能,就要把这些时间刨除掉。Linux 下的 time 命令,就可以帮我们统计出来,程序实际在 CPU 上花了多少时间。运行 time 命令,会返回三个数值。
- 第一个是 real time,即我们说的 Wall Clock Time。
- 第二个是 user time,即 CPU 运行程序时,用户态所占时间。
- 第三个是 sys time,即 CPU 运行程序时,内核态所占时间。
程序实际的 CPU 执行时间(CPU Time),就是 user time 与 sys time 之和。
[root@nfs ~]# time seq 1000000 | wc -l
1000000
real 0m0.101s #Wall Clock Time 也就是运行程序整个过程中流失的时间
user 0m0.031s #CPU在运行你的程序,在用户态运行指令的时间,
sys 0m0.016s #CPU在运行你的程序,在操作系统内核里运行指令的时间
在我给的这个例子里,你可以看到,实际上程序用了0.101s,但是CPU Time只有0.031+0.016=0.047s。运行程序的时间里,只有不到一半是是花在这个程序上的
拿到CPU时间,也不一定可以直接“比较”出两个程序的性能差役
即使在同一台计算机上,CPU可能满载运行也可以降频运行,降频运行的时候自然花的时间会多一些。
即使在同一台计算机上,CPU 可能满载运行也可能降频运行,降频运行的时候自然花的时间会多一些。此外,时间这个性能指标还会受到主板、内存这些其他相关硬件的影响。
更合理的衡量
所以我们需要对"时间"这个我们可以感知的指标进行拆解
程序的 C P U 执行时间 = C P U 时钟周期数 ∗ 时间周期时间 程序的CPU执行时间=CPU时钟周期数*时间周期时间 程序的CPU执行时间=CPU时钟周期数∗时间周期时间
时钟周期时间
Intel Core-i7-7700HQ 2.8GHz,这里2.8GHz就是电脑的主频,可以先粗浅地认为cpu1秒时间内,可以执行的简单指令的数量是2.8G条
准确一点描述2.8GHz就代表CPU的一个“钟表”能识别出来的最小的时间间隔,就像我们挂在墙上的挂钟的最小能够识别单位就是秒
在这个的CPU上,这个时钟周期时间,就是1/2.8G。我们的 CPU,是按照这个“时钟”提示的时间来进行自己的操作。主频越高,意味着这个表走得越快
超频
就相当于把买回来的CPU内部的钟给调快了,于是CPU的计算跟着这个时钟的节奏,也就自然快了,
当然这个快不是没有代价的,CPU跑得越快,散热的压力也就越大,就和人一样,超过生理极限,CPU就会崩溃了
根据公式 程序的 C P U 执行时间 = C P U 时钟周期数 ∗ 时间周期时间 程序的CPU执行时间=CPU时钟周期数*时间周期时间 程序的CPU执行时间=CPU时钟周期数∗时间周期时间,可以推导,时间周期时间变小了,CPU执行时间也会变小;那怎么缩短时间周期时间呢?那就是提升主频。换句话说,就是换一块好一点的CPU
CPU时间周期数
从上述公式可知,提升主频即可缩短时钟周期时间,从而提升性能。但硬件的发展是有瓶颈的,这就要从另一个因子,即 CPU 时钟周期数入手。如果能减少程序所需的 CPU 时钟周期数,也能提升性能。
进一步拆解 CPU 时钟周期数: 指令数 × 每条指令的平均时钟周期数( C y c l e s P e r I n s t r u c t i o n , C P I ) 指令数 × 每条指令的平均时钟周期数(Cycles Per Instruction,CPI) 指令数×每条指令的平均时钟周期数(CyclesPerInstruction,CPI)
不同的指令需要的 Cycles 是不同的,加法和乘法都对应着一条 CPU 指令,但是乘法需要的 Cycles 就比加法要多,自然也就慢。
在这样拆分了之后,我们的程序的 CPU 执行时间就可以变成这样三个部分的乘积: 程序的 C P U 执行时间 = 指令数 × C P I × C l o c k C y c l e T i m e 程序的 CPU 执行时间 = 指令数 × CPI × Clock Cycle Time 程序的CPU执行时间=指令数×CPI×ClockCycleTime
综上所述,解决性能问题,其实就是优化这三者。
- 时钟周期时间,取决于计算机的硬件主频
- CPI:每条指令的平均时钟周期数 CPI,就是一条指令到底需要多少 CPU Cycle。现代的 CPU 通过流水线技术(Pipeline),让一条指令需要的 CPU Cycle 尽可能地少。
- 指令数:执行我们的程序到底需要多少条指令、具体用哪些指令,这主要由编译器决定。同样的代码,编译成计算机指令时候,就有各种不同的表示方式。
小结
计算机的性能可以从两个方向看:
- 吞吐率:
- 提升吞吐率的办法有很多,通常只要堆硬件、加机器就能实现
- 响应时间
- 我们需要像办法把单个CPU的响应时间加快,就能靠堆机器的方法来加快吞吐率了
- 所以我们把性能,定义成响应的倒数,也就是: 性能 = 1 / 响应时间 性能=1/响应时间 性能=1/响应时间
那么响应时间由哪些东西决定呢?
- 程序的 C P U 执行时间 = 指令数 ∗ C P I ∗ C l o c k C y c l e T i m e 程序的CPU执行时间=指令数*CPI*Clock Cycle Time 程序的CPU执行时间=指令数∗CPI∗ClockCycleTime
可以看出,如果要提升计算机的性能,我们可以从指令数、CPI、CPU主频这三个地方入手。
CPU主频是什么?
- 说起CPU相关的性能数字,就必须先说CPU的时钟频率,也就是主频。主频反映了CPU工作节拍,也就直接决定了CPU周期大小。
- 比如基于英特尔 Skylake 微处理器架构的 i7 的一款,其主频为 4GHz,那么每一个时钟周期(Cycle)大约0.25 纳秒(ns)
- CPU执行程序时,最基本的执行单位是指令。而每一条指令的执行都需要经过四步:指令获取、指令解码、指令执行、数据存入。这些操作都是按照CPU周期来进行的,一般需要好几个周期。
CPI和IPC
- 每个指令周期数 CPI 和每个周期指令数 IPC 其实是孪生兄弟,衡量的是同一个东西。
- CPI(cycles per instruction)衡量平均每条指令的平均时钟周期个数。它的反面是IPC(instructions per cycle)。虽然一个指令的执行过程需要多个周期,但 IPC 是可以大于 1 的,因为现代 CPU 都采用流水线结构。一般来讲,测量应用程序运行时的 IPC,如果低于 1,这个运行的系统性能就不是太好,需要做些优化来提高 IPC。
MIPS
MIPS 就是每秒执行的百万指令数。
我们经常会需要比较不同 CPU 硬件的性能,MIPS 就是一个很好的指标,一般来讲,MIPS越高,CPU 性能越高。MIPS 可以通过主频和 IPC 相乘得到,也就是说 MIPS= 主频×IPC。这个很容易理解,比如一个 CPU 频率再高,IPC 是 0 的话,性能就是 0。假设一个CPU 的主频是 4GHz,IPC 是 1,那么这个 CPU 的 MIPS 就是 4000。注意的是,MIPS是理论值,实际运行环境数量一般小于这个值。