计算机的基本组成、性能和功耗

275 阅读7分钟

本系列文章是对极客时间徐文浩老师的"深入浅出计算机组成原理"课程的笔记,主要是对课程内容的总结和扩展,如有侵权行为,请联系本人删除。

参考:

深入浅出计算机组成原理,计算机组成与设计-硬件/软件接口,深入理解计算机系统

计算机的基本组成

这部分内容主要包括四个方面,硬件设备组成、冯·诺依曼体系结构、计算机的性能和功耗。

硬件设备

一台我们日常生活中使用的计算机,主要由CPU、主板、内存、硬盘、鼠标、键盘和显示器组成。其中最为核心的三个组件分别是CPU、主板和内存。

CPU,全称为中央处理器(Central Processing Unit)。主要负责控制计算机中各种指令的执行,以及各种 "计算" 任务。

内存。我们使用的各种应用以及数据,都需要加载到内存中才能运行。

主板,主要包括芯片组和总线。众所周知,CPU和内存不能直接通信,都是需要插在主板上才能正常工作。其中芯片组负责控制数据的流转,总线决定了数据能传输的多快。

还有一个特殊的设备,就是显卡。其主要是用于图形渲染和深度学习等领域,我们后续在进行介绍。

冯·诺依曼体系结构

目前我们日常使用的设备包括,个人计算机、手机、switch和xbox等。虽然,硬件组成方式都不太一样,但是,我们的开发过程都遵循着,编程语言撰写、编译之后,把代码和数据加载到内存中执行的方式。这是为什么呢?其实是因为,我们都依照同一个"计算机"的抽象,即冯·诺依曼体系结构。

冯·诺依曼体系结构规定了一台计算由如下几个部分组成:

运算器:包含算术逻辑单元(Arithmetic Logic Unit, ALU)和处理器寄存器(Processor Register)。主要负责算术和逻辑运算。

控制单元:包含指令寄存器(Instruction Register)和程序计数器(Program Counter)。控制程序的流程。

存储设备:内存、硬盘等等。

输入和输出设备:鼠标、键盘和显示器等等。

所有的计算机程序都可以抽象为,从输入设备中读取信息,通过运算器和控制器来执行存储在存储设备中的程序,最终把结果输出到输出设备中。

计算机的性能

计算机的性能主要通过两个指标来进行衡量。

第一个是响应时间(Response time)或者叫执行时间(Execution time)。是计算机完成某任务所需的总时间。

第二个是吞吐率(Throughput)或者带宽(BandWidth)。可以理解为,单位时间内完成的任务数量。

我们一般把性能定义为响应时间的倒数,即:

性能=1/响应时间性能 = 1 / 响应时间

响应时间越短,性能的数值就越大。

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

当我们使用"掐秒表"的方式来进行性能的衡量时,会出现两个问题。

  • 时间"不准"

当我们对一段程序运行的时间进行统计,每次都可能会得到不同的结果。这是因为,计算机可能同时运行着好多个程序,CPU实际上不停地在各个程序之间进行切换。在这些走掉的时间里面,很可能CPU切换去运行别的程序了。而且,有些程序在运行的时候,可能要从网络、硬盘去读取数据。所以说,要想准确统计某个程序运行时间,进而去比较两个程序的实际性能,我们得把这些时间刨除掉。

  • 降频

即使在同一台计算机上,CPU 可能满载运行也可能降频运行。

于是,我们把"时间"变成以下的公式:

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

由于时钟频率和时钟周期时间互为倒数,故

程序的CPU执行时间=CPU时钟周期数/时钟频率程序的 CPU 执行时间 = CPU 时钟周期数 / 时钟频率

这个时钟频率就是我们买电脑时经常看到的参数,CPU主频,例如我自己的笔记本是 i7-10750H 2.60GHz。主频越高,意味着程序的 CPU 执行时间越短。但是,这也意味着散热的压力也就越大,超过极限,CPU 就会崩溃。

对于 CPU 时钟周期数,可以进一步分解成如下公式:

CPU时钟周期数=程序的指令数×每条指令的平均时钟周期数CPU 时钟周期数 = 程序的指令数 \times 每条指令的平均时钟周期数

术语 CPI(Clock cycle Per Instruction,每条指令的平均时钟周期数),表示每条指令所需的时钟周期数的平均值。不同的指令需要的时间可能不同,CPI 是一个程序全部指令所用时钟周期数的平均值。

所以,经典的 CPU 性能公式:

程序的CPU执行时间=指令数×CPI×时钟周期时间程序的CPU执行时间=指令数×CPI/时钟频率程序的 CPU 执行时间 = 指令数 \times CPI \times 时钟周期时间 \\ 程序的 CPU 执行时间 = 指令数 \times CPI / 时钟频率

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

  1. 时钟频率。这是由硬件决定的,我们无能为力。
  2. CPI。现代 CPU 通过流水线技术(Pipeline),让一条指令需要的 CPU Cycle 尽可能减少,这在后续的文章中进行讲解。
  3. 指令数,代表执行我们的程序到底需要多少条指令、用哪些指令。这个任务就交给了编译器和我们程序员编写的程序了。

计算机的功耗

通过性能公式程序的CPU执行时间=指令数×CPI/时钟频率程序的 CPU 执行时间 = 指令数 \times CPI / 时钟频率可以看出,只要我们多放一些晶体管,不断提升 CPU 的时钟频率,就能让 CPU 变得更快,程序的执行时间就会缩短。但是,另一方面,增加了时钟频率,也增加了功耗,带来了耗电和散热问题。

捕获.PNG

图展示了30年间 Intel 八代微处理器的时钟频率和功耗的增长趋势。可以看出在2004年以后,就开始缓和下来了。其原因在于功耗已经到达了极限,无法再将处理器冷却下来了。

虽然功耗提供了能够冷却的极限,然而在后PC时代,能量是真正关键的资源。对于个人移动设备来说,电池寿命比性能更为关键。

一个 CPU 的功耗,可以用这样一个公式来表示:

功耗 =12×负载电容×电压平方×开关频率×晶体管数量功耗 ~= \frac{1}{2} \times 负载电容 \times 电压平方 \times 开关频率 \times 晶体管数量

目前,个人计算机在提升主频的过程,往往会通过降低电压的方式来减少功耗,但是降低电压也会带来新的问题,这里就不展开叙述,功耗这部分简单了解即可。

并行优化和阿姆达尔定律

如今,通过提升主频已经很难提升性能了,厂商们开始把目光投向多核 CPU,通过提升"吞吐率"而不是"响应时间",来达到目的。即,通过并行来提升程序的性能。简单地说,就是把任务拆解开,放到不同的 CPU 核心去处理,后续如果有机会写写并发编程的内容再来详细介绍一下。

阿姆达尔定律

S=ToldTnew=1(1α)+α/kS = \frac{T_{old}}{T_{new}} = \frac{1}{(1 - \alpha) + \alpha/k}

当我们对系统的某一部分进行加速时,被加速部分的重要性和加速程度是影响整个系统性能的关键因素。

在加速前,假设一个应用程序的执行所需要的全部时间表示为 ToldT_{old}。为了方便描述,我们可以笼统的将这个程序分为两部分。一部分是不可加速的,另一部分是可加速的。其中可以加速的部分执行花费的时间为αToldα ∗ T_{old},不可加速部分的执行时间为 ToldαToldT_{old} - \alpha * T_{old}。程序经过优化后,可加速部分性能提升比例为k。那么经过加速后,这个可加速部分所花费的时间就是 (aTold)/k(a∗T_{old})/k。即:

Tnew=(1α)Told+(αTold)/k=Told[(1α)+α/k]S=Told/Tnew=1(1α)+α/kT_{new} = (1-\alpha)T_{old} + ({\alpha}T_{old})/k = T_{old}[(1 - \alpha) + \alpha/k] \\ S = T_{old}/T_{new} = \frac{1}{(1-\alpha) + {\alpha}/k}

α=0.6\alpha = 0.6k=3k = 3时,S=1(10.6)+0.63=1.67S = \frac{1}{(1-0.6) + \frac{0.6}{3}} = 1.67。当k趋于无穷大时,S=11α=2.5S = \frac{1}{1-\alpha}=2.5

因此,我们需要把系统的性能提高2倍或者更多,只有通过优化大部分的组件才能获得。

延展

除了提高主频和并行计算,在整个计算机组成层面,还有这样几个原则性的性能提方法。

  • 加大概率事件。典型就是,将向量和矩阵计算,交给GPU。

  • 通过流水线提高性能。就是把 CPU 指令进行拆分,细化运行,这个后续在说明。

  • 通过预测提高性能。通过预测下一步该干什么,提前进行运算。"分支和冒险"、"局部性原理",这些也后续在说明。