高级CPU设计
上个笔记我们做了一个做除法的程序,给CPU执行,方法是做一连串减法,比如16除4会变成16-4-4-4,碰到0或负数才停下。但这种方法要多个时钟周期,很低效,所以现代CPU直接在硬件层面设计了除法,可以直接给ALU除法指令。
现代处理器有上千条指令和各种巧妙复杂的电路,超高的时钟速度带来另一个问题,如何快速传递数据给CPU?就像有强大的蒸汽机,但无法快速加煤
RAM是CPU之外的独立组件,意味着数据要用线来传递,叫“总线”,总线可能只有几厘米。
电信号的传输接近光速,但CPU每秒可以处理上亿条指令,很小的延迟也会造成问题,RAM还需要时间找地址,取数据,配置,输出数据,一条“从内存读数据”的指令可能要多个时钟周期,CPU空等数据,解决延迟的方法之一是:给CPU加一点RAM,叫“缓存”(CACHE)
因为处理器里空间不大,所以缓存一般只有KB或MB,而RAM都是GB起步,缓存提高了速度,CPU从RAM拿数据时,RAM不用传一个,可以传一批
虽然花的时间久一点,但数据可以存在缓存,这很实用,因为数据常常是一个个按顺序处理
举个例子,算餐厅的当日收入,先取RAM地址100的交易额,RAM与其只给1个值,直接给一批值,把地址100到200都复制到缓存,当处理器要下一个交易额时,地址101的数据刚好已经在缓存里有了
因为缓存离CPU近,一个时钟周期就能给数据,CPU不用空等,比反复去RAM拿数据快得多,如果想要的数据已经在缓存,叫“缓存命中”,如果想要的数据不在缓存,叫“缓存未命中”
缓存也可以当临时空间,存一些中间值,适合长/复杂的运算。继续餐馆的例子,假设CPU算完了一天的销售额,想把结果存到地址150,就像之前,数据不是直接存到RAM,而是存在缓存,这样不但存起来快一些,如果还要接着算,取值也快一些。
但这样有一个问题,缓存和RAM不一致了,这种不一致必须记录下来,之后要同步,因此缓存里每块空间有一个特殊标记,叫“脏位”
同步一般发生在,当缓存满了而CPU又要缓存时,在清理缓存腾出空间之前,会先检查“脏位”,如果是“脏”的,在加载新内容之前,会把数据写回RAM。
另一种提升性能的方法叫“指令流水线”,即使用并行处理。“执行”一个指令时,同时“解码”下一个指令,“读取”下下个指令,不同任务重叠进行,同时用上CPU里所有部分
这样的流水线,每个时钟周期执行1个指令,吞吐量×3
和缓存一样,这会带来一些问题,
第一,指令之间的依赖关系。举个例子,你在读某个数据,而正在执行的指令会改这个数据,也就是说拿的是旧数据,因此流水线处理器,要先弄清数据依赖性,必要时停止流水线,避免出问题
高端CPU,比如笔记本和手机里那种,会更进一步,动态排序有依赖关系的指令,最小化流水线的停工时间,这叫“乱序执行”
第二,“条件跳转”,比如上个笔记中的JUMP NEGATIVE,这些指令会改变程序的执行流,简单的流水线处理器,看到JUMP指令会停一会,等待条件值确定下来,一旦JUMP的结果出了,处理器就继续流水线,因为空等会造成延迟,所以高端处理器会用一些技巧,可以把JUMP想成是“岔路口”,高端CPU会猜哪条路的可能性大一些,然后提前把指令放进流水线,这叫“推测执行”,当JUMP的结果出了,如果CPU猜对了,流水线已经塞满正确指令,可以马上运行,否则就要清空流水线,就像走错路掉头
为了尽可能减少清空流水线的次数,CPU厂商开发了复杂的方法,来猜测哪条分支更有可能,叫“分支预测”