CPU的主频

透过CPU的主频,谈谈性能究竟是什么

计算机的性能衡量

于计算机的性能,我们需要有个标准来衡量。这个标准中主要有两个指标。

一、响应时间(Response time)或者叫执行时间(Execution time)。想要提升响应时间这个性能指标,可以理解为让计算机“跑得更快”。

二、吞吐率(Throughout)或者带宽(Bandwidth),想要理解这个指标,可以理解为让计算机“搬得更多”。

网络带宽通常就是一个吞吐率的性能指标


响应时间指的就是,我们执行一个程序,到底需要花多少时间。花的时间越少,自然性能就越好。而吞吐率是指我们在一定的时间范围内,到底能处理多少事情。这里的“事情”,在计算机里就是处理的数据或者执行的程序指令。和搬东西来做对比,如果我们的响应时间短,跑得快,我们可以来回多跑几趟多搬几趟。所以说,缩短程序的响应时间,一般来说都会提升吞吐率。

除了缩短响应时间,我们还有别的方法吗?当然有,比如说,我们还可以多找几个人一起来搬,这就类似现代的服务器都是 8 核、16 核的。人多力量大,同时处理数据,在单位时间内就可以处理更多数据,吞吐率自然也就上去了。

提升吞吐率的办法有很多。大部分时候,我们只要多加一些机器,多堆一些硬件就好了。但是响应时间的提升却没有那么容易。

一般把性能,定义成响应时间的倒数,也就是:

性能 = 1/ 响应时间

响应时间

在业界,各大 CPU 和服务器厂商组织了一个叫作 SPEC(Standard Performance Evaluation Corporation)的第三方机构,专门用来指定各种“跑分”的规则。

SPEC基准测试 SPEC 提供的 CPU 基准测试程序,就好像 CPU 届的“高考”,通过数十个不同的计算程序,对于 CPU 的性能给出一个最终评分。[链接🔗](https://www.spec.org/cpu2017/results/cpu2017.html)

计算机的计时单位:CPU 时钟

虽然时间是一个很自然的用来衡量性能的指标,但是用时间来衡量时,有两个问题。

第一个就是时间不“准”。如果用你自己随便写的一个程序,来统计程序运行的时间,每一次统计结果不会完全一样。有可能这一次花了 45ms,下一次变成了 53ms。为什么会不准呢?这里面有好几个原因。首先,我们统计时间是用类似于“掐秒表”一样,记录程序运行结束的时间减去程序开始运行的时间。这个时间也叫 Wall Clock Time 或者 Elapsed Time,就是在运行程序期间,挂在墙上的钟走掉的时间。

但是,计算机可能同时运行着好多个程序,CPU 实际上不停地在各个程序之间进行切换。在这些走掉的时间里面,很可能 CPU 切换去运行别的程序了。而且,有些程序在运行的时候,可能要从网络、硬盘去读取数据,要等网络和硬盘把数据读出来,给到内存和 CPU。所以说,要想准确统计某个程序运行时间,进而去比较两个程序的实际性能,我们得把这些时间给刨除掉。

Linux 下有一个叫 time 的命令,可以帮我们统计出来,同样的 Wall Clock Time 下,程序实际在 CPU 上到底花了多少时间。

运行一下 time 命令。它会返回三个值,第一个是 real time,也就是我们说的 Wall Clock Time,也就是运行程序整个过程中流逝掉的时间;第二个是 user time,也就是 CPU 在运行你的程序,在用户态运行指令的时间;第三个是 sys time,是 CPU 在运行你的程序,在操作系统内核里运行指令的时间。而程序实际花费的 CPU 执行时间(CPU Time),就是 user time 加上 sys time。

1
2
3
4
5
6
7

$ time seq 1000000 | wc -l
1000000

real 0m0.101s
user 0m0.031s
sys 0m0.016s

即使我们已经拿到了 CPU 时间,我们也不一定可以直接“比较”出两个程序的性能差异。因为同一台计算机上,CPU 可能满载运行也可能降频运行,降频运行的时候自然花的时间会多一些。 除了 CPU 之外,时间这个性能指标还会受到主板、内存这些其他相关硬件的影响。

我们把程序的 CPU 执行时间变成 CPU 时钟周期数(CPU Cycles)和 时钟周期时间(Clock Cycle)的乘积。

​ 程序的 CPU 执行时间 =CPU 时钟周期数×时钟周期时间

什么是时钟周期时间。你在买电脑的时候,一定关注过 CPU 的主频。比如这台电脑是 Intel Core-i7-7700HQ 2.8GHz,这里的 2.8GHz 就是电脑的主频(Frequency/Clock Rate)。这个 2.8GHz,我们可以先粗浅地认为,CPU 在 1 秒时间内,可以执行的简单指令的数量是 2.8G 条。准确一点描述就是,这个主频就是我们 CPU 的一个“钟表”能够识别出来的最小的时间间隔

在 CPU 内部,和我们平时戴的电子石英表类似,有一个叫晶体振荡器(Oscillator Crystal)的东西,简称为晶振。我们把晶振当成 CPU 内部的电子表来使用。晶振带来的每一次“滴答”,就是时钟周期时间。 (如果组装过台式机的话,可能听说过“超频”这个概念,这说的其实就相当于把买回来的 CPU 内部的钟给调快了,于是 CPU 的计算跟着这个时钟的节奏,也就自然变快了。当然这个快不是没有代价的,CPU 跑得越快,散热的压力也就越大。就和人一样,超过生理极限,CPU 就会崩溃了。)

CPU 时钟周期数

对于 CPU 时钟周期数,我们可以再做一个分解,把它变成“指令数×每条指令的平均时钟周期数(Cycles Per Instruction,简称 CPI)”

不同的指令需要的 Cycles 是不同的,加法和乘法都对应着一条 CPU 指令,但是乘法需要的 Cycles 就比加法要多,自然也就慢。

拆分了之后,我们的程序的 CPU 执行时间就可以变成这样三个部分的乘积。

程序的 CPU 执行时间 = 指令数 × CPI × Clock Cycle Time 

因此,想要解决性能问题,其实就是要优化这三者。

  1. 时钟周期时间,就是计算机主频,这个取决于计算机硬件。我们所熟知的 摩尔定律 就一直在不停地提高我们计算机的主频。比如说,我最早使用的 80386 主频只有 33MHz,现在手头的笔记本电脑就有 2.8GHz,在主频层面,就提升了将近 100 倍。

  2. 每条指令的平均时钟周期数 CPI,就是一条指令到底需要多少 CPU Cycle。在后面讲解 CPU 结构的时候,我们会看到,现代的 CPU 通过流水线技术(Pipeline),让一条指令需要的 CPU Cycle 尽可能地少。因此,对于 CPI 的优化,也是计算机组成和体系结构中的重要一环。

  3. 指令数,代表执行我们的程序到底需要多少条指令、用哪些指令。这个很多时候就把挑战交给了编译器。同样的代码,编译成计算机指令时候,就有各种不同的表示方式。

形象比喻:

  • 我们可以把自己想象成一个 CPU,坐在那里写程序。计算机主频就好像是你的打字速度,打字越快,你自然可以多写一点程序。CPI 相当于你在写程序的时候,熟悉各种快捷键,越是打同样的内容,需要敲击键盘的次数就越少。指令数相当于你的程序设计得够合理,同样的程序要写的代码行数就少。如果三者皆能实现,你自然可以很快地写出一个优秀的程序,你的“性能”从外面来看就是好的。

延伸

每次有新手机发布的时候,总会有一些对于手机的跑分结果的议论。乃至于有“作弊”跑分或者“针对跑分优化”的说法。我们能针对“跑分”作弊么?怎么做到呢?

  • 当检测到跑分程序运行的时候,降低系统调用,提高跑分程序优先级。关闭热管理系统(防止过热关核降频),手机CPU核心全开,超频到最高等。不顾一切,全心全意为跑分程序服务
  • 提高跑分,无非是优化CPU的执行时间,可以从两个方面入手,一是提高CPI,可以采取超频运行的模式;二是优化指令数,单独针对特定的CPU进行代码优化。
-------------本文结束感谢您的阅读-------------
作者水平有限,文中难免存在一些错误,欢迎邮件@交流讨论~
Zongpeng Lin 微信 微信
Zongpeng Lin 支付宝 支付宝