分享

计算机底层学习笔记:CPU

 gfergfer 2023-09-25

前言

最近在看计算机底层相关的知识。一方面补基础,帮助理解工作、学习中遇到的相关概念,另一方面是学习相关的设计思想,之后设计技术方案、系统构建的时候也有一些参考借鉴。

图片

计算机架构

1949年,一本叫《大众机械》的书里做出了一个“大胆”的预言:“将来,计算机重量也许不超过1.5吨。”今天的我们看到这句话也许会哑然失笑。毕竟如今我们的手提电脑早已可以做到2,3公斤的重量。但是要知道,当年的电脑,像ENIAC,是一个占地170平米,重量达30吨的庞然大物,而随着信息革命的浪潮,从电子管到晶体管到集成电路,在摩尔定律的支配下,计算机的功能、性能、便携性早已发生天翻地覆,远超前人想象的变化。

图片

摩尔定律是英特尔创始人戈登.摩尔曾做出的预言,其核心内容为:集成电路上可以容纳的晶体管数目在大约每经过18个月到24个月便会增加一倍。换言之,处理器的性能大约每两年翻一倍,同时价格下降为之前的一半。这并不是什么物理定律,而是一种半导体产业界的自实现的预言(可以理解为KPI),但也揭示了信息产业进步的速度。怎么更形象化地理解这个速度?有个很好的例子:“如果汽车的进步周期能同步计算机的发展周期的话,今天一辆劳斯莱斯仅值100美金,每加仑汽油可以跑100万英里。”

从第一台计算机问世(ENIAC)以来,已经70多年了。70年沧海桑田,计算机这只王谢堂前燕,早已飞入寻常百姓家。如今几乎是人手一台,用途也从军事变为娱乐、科研、医疗等等。这样的变化也许是当初谁也料想不到的。然而即使历经了如此巨大的变化,现代计算机的架构却依然没有背离过近80年前提出的冯诺依曼架构。这不得不令人称奇。接下来我们就介绍一下冯诺依曼架构:

图片

这个架构有5个组成部分,分别是:控制器、运算器、存储器、输入设备和输出设备,其中运算器和控制器合称CPU,各组成部分通过通信线路互相连接

这个架构的运行流程如下:

  1. 要运行的程序保存在存储器中,以连续排列的指令为单位组成,每条指令包含了一项计算操作

  2. 控制器从存储器中依次读取指令,将指令包含的信息传送到运算器中,由运算器解析指令功能,执行数值计算。

  3. 执行指令时,若需要从外界读取要加工的数据,则由控制器向输入设备发出消息,由输入设备将数据传送到计算机的内部。

  4. 指令执行结束后,控制器可以把运算器的计算结果传入存储器,或向输出设备发出消息,由输出设备将结果传到计算机外部。

  5. 控制器再从存储器中读取下一条指令并送入到运算器。

  6. 取指令-执行指令-保存结果的过程多次重复执行,直至程序最后一条指令执行完成。

可以说无论什么程序,微信也好,淘宝也好,facebook也好,在计算机中都是以这个逻辑执行。

CPU

如果要说冯诺依曼架构最核心的组成部件是哪个,那必然非CPU莫属。我们编写的代码最终也都要变成机器指令供CPU执行,所以我们先从CPU说起。

指令集

图片

所有我们计算机上的程序:QQ、微信、Chrome、记事本等等,都会经过编译器或者汇编器转换为底层机器指令,而CPU最终执行的也是这个机器指令。

比如我们在java中写下 “int i = 1;”

这句话就等价于mov eax, 1。

进而等价于一条类似于100111101这样的机器指令,这条指令可以拆分为操作和操作数几个部分,告诉CPU,需要把1存储到eax寄存器中。

这些各式100011这样的底层机器指令的集合就是CPU指令集,CPU指令集可以说是软件与硬件交互的媒介,或者说是硬件提供给软件的接口集合。这个指令集规定了CPU的功能,决定了我们能做什么。

在计算机发展过程中,指令集形成了两种风格,即CISC(Complex Instruction Set Computer)和RISC(Reduced Instruction Set Computer)。

CISC(复杂指令集)

CISC,以Intel的X86架构为代表,指令集丰富,包含大量的复杂指令。晶体管和集成电路发展的日新月异使得CPU的功能也变得越来越强大,而CISC的思想中强调兼容性,每次迭代只在原有基础上拓展、增加指令,而绝不去改动原有的指令的功能。(类似我们说的“开闭原则”)。这样做的好处是兼容性非常强,即使是30多年前的程序也能在今天的X86架构上运行。但坏处则是指令越来越多,越来越复杂。尤其大量指令其实几乎不怎么被使用。

RISC(精简指令集)

RISC,以AMD的ARM架构为代表。RISC的设计指令时遵循“正交性”的思想,即每条指令都实现某一方面的独立功能(可以理解为是原子指令),指令之间没有重复和冗余的功能,所有指令组合起来实现CPU的全部功能。因此RISC的指令数量比CISC少的多,但是对于实现同一个功能,需要运行的指令数也会更多。

可以这样理解两者的差异:同样是去建造一个房子,假设CPU是建筑工人,指令集是提供指示的设计师。CISC风格的指示是“在那里砌个围墙,再搭个柱子”,而RISC风格的指示则是“把这块砖砌在那儿”。

可以看出RISC的风格有明显的极简主义。形式简单得多。对于完成同一功能,RISC实现方式的指令数会比CISC更多,但是因为每一条执行得更快,所以总体来说谁快谁慢还不好说。一般而言,如果任务相对简单且可以通过少量的指令完成,CISC架构的处理器可能会更快,因为它可以通过一个复杂的指令完成多项操作。而如果任务相对复杂或者需要大量的数据处理,RISC架构的处理器可能会更快,因为它可以通过更多的简单指令完成任务,并且每个指令的执行时间更短。

趋势

在PC的时代,WinTel联盟(Windows Intel)在个人用户市场上可以说是一路高歌猛进,形成了事实上的垄断地位,而相比之下,AMD只能靠着反垄断的保护才得以偏安一隅。但是进入移动互联网时代后,CISC由于指令复杂,始终无法解决CPU功耗高的问题。这个问题在有风扇、机箱空间大的PC场景还不突出,但是在手机设备上就暴露无遗了,而AMD代表的RISC则抓住机遇不断逆袭,到如今市值已经超过了Intel。不过在AI时代的大背景下,风头最盛的已经不是做CPU的Intel或AMD了,而是做GPU的Nvidia。与此同时,一种叫RISC-V的新架构也在悄然兴起。它是由USCB研究人员和开源社区共同开发,凭借开源、灵活等特点,在AIOT的场景下正在变得越来越流行,也许也会在将来成为主流架构之一。

图片

漫思

其实想想挺像我们写代码做项目的。有时候建项目的时候,因为设计水平、任务排期等原因,可能没做什么抽象,基本“所见即所写”,就类似CISC的风格,和业务耦合比较强,一开始迭代比较快。但是随着项目的发展,后面维护越来越慢,甚至对于一些功能,已经是无法实现。因此到了一定节点,衡量价值和成本后,就可能会进行重构。而对于那些在初期就进行了良好的抽象和设计的项目,系统各模块、功能间有一定的正交性,前期可能相对慢一些,但是在后续的维护成本、拓展性都更好一些。

不过项目的发展有很多技术以外的因素,也不可一概而论。比如机会窗口可能稍纵即逝,比如很多项目可能根本就到不了那个后面那个阶段。这就跟JVM垃圾回收机制类似的,现实是大部分对象(项目)都是朝生夕死的,那这也会反过来决定了他们的处理机制,而对于那些大对象(大力支持的明星项目)、存活了N代的新生代(顽强生存下来的仙人掌),则可以获得破格对待。

所以这也许也给我们一些启发,我们发展规划、前景、资源支持是怎样的,可以帮助我们决定是贴近CISC的风格,还是RISC风格。

效率

如今我们的手机的CPU的计算能力都比当年登月计划的计算机算力总和要高得多。这巨大的变化背后是各个环节比如CPU环节不断追求提效的结果。那么以CPU为例,都用了哪些提效的方式呢?

频率

想要提高CPU工作效率,提高频率应该是一个最直观的想法。这个频率指的是CPU内部时钟的振荡频率(一个晶体振荡器,由物理特性及电路参数决定频率)。这个频率决定了CPU每秒钟执行的指令数,比如一个CPU主频是1 GHZ,那就是这个CPU每秒可以执行1亿条指令。很直观地,如果我们增加到2 GHZ,那我们CPU的效率当然就提高了。

但是这个提高不是无上限的,因为指令执行本身就是需要时间的,如果你频率太高,1秒执行太多指令,就会出现说上一条指令还没执行完,新一条指令就开始执行了。那么计算机就会进入到一种不可控的状态,而且功耗也会大大增加,所以到今天,计算机的频率到了4,5 GHZ之后,也就不再继续提高了。

位数

上面说到频率的优化基本是到头了,也就是单位时间内做任务的数量已经定了,那还能怎么优化呢?那就是每次任务的任务量。就好比搬砖,一天只能搬10趟不能更多了,那每趟多搬几块转,搬的砖的总数就提高了。而怎么提高每次的任务量呢,那就可以提高CPU的位数。我们知道以前的CPU都是32位的,而现在很多都是64位的了,这个变化除了增大了内存寻址空间以外(内存越来越大,32位只能表示4GB),还有个好处就是每条指令的能力也越来越强了,比如原先32位指令我只能放2个操作数,现在64位指令能放4个操作数了,那在单位时间内处理任务数不变的情况下,我每次任务的任务量增加了,那我的总效率也提升了。

流水线

应该说以上两种都是比较直观想到的优化方向,那么还有没有什么别的办法优化呢?答案是有的,就是流水线的方式,相比较而言,前两者主要是硬件上的优化,而这一个则是软件上、算法上的优化,什么叫算法上的优化?我的定义是:在硬件条件并没有改变的情况下,只是通过改变做事情的方法,便提高了效率。接下来我们介绍一下这个方法。

流水线的思想实际上甚至早于计算机的发明。早在1913年,福特汽车公司就开发出了世界上第一条流水线,这一创举使得福特T型车一共达到了1500万辆,售价也从最初的850美元,降至240美元。大大推动了汽车产业的发展,亨利.福特也因此被称为“给世界安上轮子的人”。

图片

流水线的思想其实就是:将一个任务切分成不同的阶段,不同的阶段由不同的独立执行单元分别执行,以在宏观上实现多条指令同时执行。

那么在CPU里,也是一样的,就是将CPU指令拆分成多个不同阶段,比如一条显示某地址的内容的指令就可以分为下列多个阶段:

  1. 计算指令地址(AG)

  2. 取指令(IF)

  3. 执行指令(EX)

  4. 显示内容(DC)

可以看到我们其实没必要等第一条指令DC阶段结束了,再去做第二条指令的AG。我们完全可以第一条指令AG结束后,就开始第二条指令的AG了。最后这个流程会如下图所示:

图片

看完后我有点好奇这种方式能带来多大的效率提升。下面我们计算一下:

简单起见,假设每个阶段耗时相同。设每条指令被分为K个阶段,每个阶段耗时T秒,执行N条指令。

串行执行耗时:K * T * N

流水线执行耗时:K * T (N - 1) * T

比如4条指令,4个阶段,每个阶段各执行1秒,则流水线可将其执行时间从4 * 4 * 1 = 16 秒优化到7秒。

接下来我们将两式相减并化简:

图片

最后得到流水线比串行少耗时:(N-1)(K-1) * T的时间,通过这个式子可以看出:

  1. 当时阶段数K为1时,节约的时间为0,因为此时流水线和串行其实是一样的(这个应该很容易理解)

  2. 显然T必然大于0,当阶段数、指令数大于1时,节约的时间就会大于0,即流水线模式优于串行模式。

  3. 阶段数、指令数越多,节约的时间、提升的效率也就越明显。

其实在我们平时写业务代码的时候也可以参考流水线的思想。比如在复杂一些的业务中,任务往往是由多个阶段组成的。比如处理一个文件,他需要先下载,再做个什么解析,再调用一下A服务。这就可以视作是流水线的多个阶段。可以给这多个阶段都配置相应的线程池和rejectedExecutionHandler。这其实就是利用了流水线的思想,这种方式会比简单一个大池子串行执行效率更高。

至此,关于CPU的部分就结束了。下一篇会再介绍关于操作系统中进程管理的部分。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多