本系列文章全部摘选自“码农翻身”公众号,仅供个人学习和分享之用。文章会给出原文的链接地址,希望不会涉及到版权问题。

个人感言:真正的知识是深入浅出的,码农翻身” 公共号将苦涩难懂的计算机知识,用形象有趣的生活中实例呈现给我们,让我们更好地理解。感谢“码农翻身” 公共号,感谢你们的成果,谢谢你们的分享。

本文源地址:http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513017&idx=1&sn=5550ee714abd36d0b580713f673e670b&scene=21#wechat_redirect

在本篇文章的基础上,本人增加了CPU的内部结构方面的介绍,以及CPU流水线的工作原理等,并给出相关图解,希望原作者能够包含。

CPU的内部结构如下图所示:

CPU阿甘-LMLPHP

图1 cpu内部结构框图

前言

上帝为你关闭了一扇门,就一定会为你打开一扇窗。这句话用来形容我最合适不过了。首先,自我介绍一下:我是CPU,计算机里的小伙伴都叫我阿甘。因为我和《阿甘正传》里的阿甘一样, 有点傻里傻气的。上帝把我制造出来, 给我了一个很小的脑容量, 为数不多的寄存器能临时的记一点东西, 但是上帝给我打开了一扇特别的窗户, 那就是像阿甘一样,跑的飞快。到底有多快呢?  我这么比喻一下吧,  我的工作都是以纳秒为单位的, 你们人间的一秒, 我可能已经做了1000,000,000 (10亿)次动作了。相比而言, 内存比我慢100倍, 硬盘比我慢1000多万倍, 你说我快不快?

启动

我住在一个机箱里,每天早上一阵电流把我叫醒, 还夹杂着嗡嗡的声音, 我知道我忠实的护卫电风扇又开始工作了, 我特别怕热,又运行的飞快, 如果没有电风扇给我降温,我很快就会中暑的,中暑的后果很严重,那就是我的伙伴们像内存了,硬盘了...,全部都要罢工了。没有我,这个系统就会陷入的一片死寂。
我听说有些CPU的福利很好,竟然待在恒温恒湿,一尘不染的托管机房里,让我好生羡慕。
我的脑容量很小, 所以醒来后只想起了我的创造者告诉我的几件事情 :

  1. 你的工作就是运行指令;
  2. 你不能保存指令, 你的指令全在内存里;
  3. 你的第一条指令在内存的最顶端处0xFFFFFFF0

CPU阿甘-LMLPHP

图2 CPU工作流程图

启动操作系统

那还有什么可说的, 赶紧打电话给内存要指令,电话通过系统总线,还得通过I/O桥电话局需要转接一下, 再通过存储总线接通内存。 
"哥们, 把这个地址处的指令给我说一下吧"
"你是谁?" 内存竟然把我忘了,当然,他断了电和我一样,失忆了。
"我是阿甘啊, 我们经常聊天来着, 你忘了?"
内存磨磨唧唧半天才把数据发了过来(比我慢100倍啊),这是一条跳转指令,  我立刻回忆起来了, 这是我的老朋友BIOS 等着我去运行他那一堆指令呢。
我给BIOS打电话:  “老弟,今天干点啥?”
“阿甘,早上好 "   BIOS从不失忆,把所有人都记得清清楚楚 “ 还不是老一套啊,无非做一下系统的自检, 看看内存,硬盘,显卡等这些老伙计们有没有问题, 有问题的话用小喇叭提示一下主人 ”
这些过程我已经轻车熟路了, 很快搞定, 像往常一样,没有问题, 我还把一个叫做中断向量表的东西给弄好了, 我知道一会而要用
这些东西都搞完了,BIOS果然告诉: "阿甘, int 0x19"
我赶紧去刚弄好的中断向量表中去查第19号, 顺藤摸瓜又找到对应0x19的一大堆指令。
执行吧,这堆指令把将磁盘的第一扇区(磁盘最开始的512字节)运到内存的0X0000:0X7C00处,然后我就从此处接着执行。
我想起来了, 接下来有一大堆精巧的指令把迷迷糊糊的操作系统从硬盘中唤醒, 运输到内存中来。(此处实在是复杂, 略去10万字。。。。)
你看这就是为啥他们叫我阿甘, 我做事飞快,但非得别人告诉去哪里执行才行, 要不然我就只会坐在那里无所适从。

运行

操作系统一旦进入内存,立刻就是老大, 所有人都得听他指挥。
我也发现我的周围出现了一个屋子:进程屋。屋里堆着一大堆东西, 什么进程描述信息包裹了,进程控制信息包裹了,我都不太关心, 我只关心最最重要的两件东西:

  1. 工作必备的寄存器, 就放在我面前的工作台上;
  2. 程序计数器, 我用它记住我要执行的下一条指令地址。

"阿甘, 别来无恙啊" ,操作系统对我还是挺不错的,先给我打招呼。
"Linux老大, 今天有什么活啊",我每次都表现的积极主动。
"来,把这个hello world 程序给运行了"
Hello world 程序还在硬盘上睡着呢,得先把他也装载到内存里, 要不然我怎么执行啊。
于是我就拿起电话打给硬盘, 电话通过系统总线来到IO桥电话局, 再转接到IO总线,这才来到硬盘这里。 
我在电话里请他把数据给我运过来,然后我就无所事事的坐在那里等。
Linux 老大立刻就怒了:阿甘, 告诉你多少次了,你小子怎么还在等硬盘给你发数据!
是的, 我忘了一件事,硬盘比我慢太多了, 我执行一条指令大概是1ns  ,在用来读磁盘的16ms里, 我能潜在的执行1600多万条指令啊。
我感到深深的愧疚, 赶紧拿起电话打给硬盘:哥们,按我们之前商量好的,用直接内存访问(DMA)啊, 你直接把数据装载到内存吧,不用经过我了,  装载完成以后给我发个信号。
"这还差不多"  Linux 老大心情好了些 “阿甘,数据还没来, 别闲着, 这有一个菲波那切数列数列, 来算一下吧”
"肥波纳妾数列?  这名字好古怪,老大, 其实你也知道, 我脑子小,懒得去理解那是啥意思, 你把进程屋切换下,把程序计数器设置好,指向下一条指令, 我一条条指令执行就得了“  我挺没追求的。
"真是个阿甘啊!”老大感慨到。
我所处的进程屋立刻发生了变化(当然,这也是我辅助Linux老大干的), 各种包裹的信息都变了,尤其是寄存器和程序计数器。
于是我就开始计算这个什么纳妾数列 ,但是这个数列似乎无穷无尽, 哪个无脑子的程序员写了个无限循环吧。
正在这时, 我便收到了一个电话, 说是Helloworld的数据已经装载到内存了,让我去处理。
我放下手中的活,保存好现场,就去处理那个Helloworld,  果然数据已经都好了,那就切换过去运行吧。
其实老大并不知道,任何人,只要你运行了相当多的数量的指令以后, 你都能悟到这些程序的秘密。 我CPU阿甘虽然傻傻的, 但也架不住执行这数以万万亿的指令给我的熏陶啊。
这个秘密就是:程序都是由顺序,分支,循环来组成的。  其实分支和循环在我看来都是跳转而已。
所以我的工作就是打电话问内存要一条指令, 执行这个指令, 如果是个跳转指令的话,我就问内存要跳转的目标地址的那一条指令, 继续执行, 生活就是这么简单。
对了, 当然也有复杂的, 就是函数调用, 我得和内存紧密配合才能完成。这个咱下回再说。

新装备:缓存

提到内存, 这真是我的好哥们, 没有他,我几乎什么事儿都干不成, 更重要的是他比硬盘快的多, 读取一次数据, 只需要 100 纳秒左右。 这样我们俩说起话来就轻松多了。
每次他都说: "阿甘, 幸亏有你给我聊天, 要不然我肯定被活活的闷死不可, 那个硬盘说话是在太慢了"
"它为啥那么慢?"  我每次都问
"硬盘是个机械是的玩意, 一个磁头在一碟高速旋转的磁片上挪来挪去,光定位就慢死了"
"那主人为什么要用硬盘?"
"人家虽然慢, 但是不怕停电, 哪像你和我,一停电全部都失去记忆了。"
确实是, 人不能把好事都占全了啊。
我的指令中有些完全用我的寄存器就能完成, 但是有很多都需要读写内存的数据, 再加上所有的指令都在内存中存着,  虽然它只比我慢个100倍, 但指令多了我还是有点受不了。
我给内存说:"哥们, 你能不能再快点!"
内存说: 拜托, 这已经是我的极限了, 阿甘, 你自己再想想办法吧 ! 我给你说啊, 我留意了你最近访问的指令和数据, 我发现了个规律“
"啥规律?"
"比如说吧, 你访问了我一个内存位置以后过不多久还会多次访问, 还有,一个内存位置被访问了, 附近的位置很快也会访问到"(码农翻身注: 这其实叫程序的局部性原理
我还以为是啥规律, 其实我早就注意到了。
"这有啥用啊?”
"既然你经常访问同一块区域的东西, 你想想如果把这些东西缓存在你那里会怎么样.... "
我一想有道理啊!加个缓存试试!
从此以后,我每次读写指令和数据, 都问缓存要, 缓存没有才给内存打电话。
果然, 由于局部性原理的存在, 我发现的确是快了不少啊。
当然也有缺点, 那就是Linux老大在做程序切换的时候,缓存就会失效,因为两个程序之间没什么联系,局部性原理不起作用,所以需要重建缓存。

自我提升:流水线

缓存让我的工作更有效率,得到了Linux老大的表扬:"阿甘, 我看你很聪明嘛!都会用缓存了"。
"我哪有那么聪明,都是内存的点子。老大,不过我学会了一个重要的东西 :"当你改变不了别人的话,抱怨也没用, 还是先改变一下自己吧"。
"挺有哲理的吗, 希望你明天重启后还能想起来" Linux老大笑话我。
"我最近又发现了一个问题, 正苦恼着呢, 你看我有四只手, 第一只手负责打电话问内存要指令, 第二只手翻译指令, 第三只手真正执行, 第四只手有时候还得把结果写回内存。  问题是, 我发现经常只有一只手在忙活, 其他都在闲着, 你看第一只手取指令, 其他手只能等着。  第二只手翻译指令的时候,其他三只也得等“
"看来以后我们不能叫你阿甘了,你已经开始思考了" Linux老大笑了 
“这问题好解决, 给你举个例子,你听说过洗车没有?  和你差不多, 也是先喷水, 再打洗洁剂, 再擦洗, 最后烘干,  但人家的工作方式和你不一样,人家是流水线作业, 你想想, 一辆车在烘干的时候, 后边是不是还有三辆车,分别在喷水, 打清洁剂 和擦洗 , 每个步骤都不会空闲。 ”
"这么简单的道理我怎么都没有想到呢? 我也可以搞个流水线啊, 这样每只手都利用起来了"
别人都说我们高科技, 但其实原理都蕴含在生活之中啊。 
有了缓存和流水线的帮助, 让我的工作大大的加快了,大家都对我刮目相看。

他们想给我起个新名字:超人,不过我还是更喜欢 他们叫我“阿甘”, 多亲切。

--------------------------------------------------------------------------------------------------------------------个人添加-----------------------------------------------------------------------------------------------------------

现在剖析一下CPU的四只手,其实也就是一条指令的执行需要经历的四个阶段:取指令、译码、执行、写回。假设每一个阶段都要花费一个时钟周期,如果没有采用流水线技术,那么N条这样的指令需要4N个时钟周期,如下图所示:

CPU阿甘-LMLPHP

图3 没有采用流水线技术的时钟周期

而采用流水线技术时,N条指令需要N+3个时钟周期,如下图所示:

CPU阿甘-LMLPHP

图4 指令流水线示意图

那么N+3是如何算出来的呢?请往下看:

从图4可以看出,第一条指令执行完需要4个时钟周期,以后都是每一个时钟周期执行完一条指令。所以需要总的时钟周期数为:

1*4+(N-1)*1 = N+3。

可见流水线技术大大地提高了CPU的工作效率。

--------------------------------------------------------------------------------------------------------------------个人添加-----------------------------------------------------------------------------------------------------------

尾声

我一丝不苟,兢兢业业的运行指令, 时不时和伙伴们聊天, 很快一天就过去了, 又到了晚上,我知道关机的时刻到了, 赶紧挨个给他们道别。 
很快那些让我兴奋的电流消失了,风扇的嗡嗡声也没有了, 我再也无法打出电话,整个世界沉寂了。
明天将会是新的一天。

“码农翻身” 公共号 : 由工作15年的前IBM架构师创建,分享编程和职场的经验教训。

长按二维码, 关注码农翻身

CPU阿甘-LMLPHP

04-20 17:55