话说人们在1870年左右开始应用黄色火药,在1900年左右开始大量普及电动地铁,并建成了埃菲尔铁塔(1898)等伟大工程,但是军事技术的发展、革新最多的仅是二战前后的1936到1945的这几年时间,现在的军事技术也大都仅是对二战时的军事技术体系的深化,如自动步枪,喷气引擎,潜艇,坦克和反坦克等等。所以我们认为,高强度的行业竞争,带来其领域技术的深入发展,而因其深入的发展,其中的许多设计理念和产出,往往惠及了很多的民用领域,如复杂的涡轮增压技术是二战战斗机的标配,现在也经过简化,惠及到民用汽车领域。
而现在信息技术领域中白热化的竞争莫过于Intel和AMD之间的蓝红之争,其竞争让CPU的设计和架构经过千锤百炼,是一个现代人类设计和实践的结晶。因此我们探究一下CPU底层的实现,其中的思路和理念,特别是现在多核心CPU的设计,也会对我们的高性能系统,以及分布式系统的设计和使用有很多借鉴和帮助。
另外其实人们也发现往往一些带有分形的东西,其不仅广泛存在,而且也代表着很多我们未知的合理结构,如人们所说的黄金分割,宇宙及黑洞等,其也都和分形有关联,分形可以简单理解为不断深入的底层构成,和其上层构成有结构上的相似。因此我们探究底层的设计,也对我们上层系统的设计有一定的参考和指导作用。
如下图所示是Intel的Skylake的CPU架构,我们可以看到缓存被分为L1、L2、L3这3层,CPU在运行中首先使用自己的寄存器,然后使用速度更快的L1缓存,其中:L1D缓存数据;L1I缓存指令;L1缓存和次快的L2同步数据;L2缓存和L3缓存同步数据(这里L2和L3按照内核数量做了等分,分给各个内核使用),我们可以简单地认为L3和内存同步数据。
Intel的PPT 中Skylake的缓存示意图的截图
为什么会有这么多级的缓存呢?因为每级缓存的速度差异很大,越快的缓存容量越小,因此CPU把缓存分成多级,每一级作为上一级的缓存。(其实在多核的情况下访问缓存会有一些同步问题,我们在下文讨论)
而我们可以认为目前CPU的缓存性能差异如表所示(参考了卡耐基梅隆大学在2014年的教案等)。
缓存性能表
在上表中要注意以下内容:
1. L1、L2、L3的最小读写单位是64bit(8字节)。
2. L2的周期已包含L1(miss)的周期,L3的周期已包含L2(miss)的周期。
4. 其实CPU的寄存器的整体大小为2KB左右,在64位下除了RAX、RBX、RCX、RDX、RSI、RDI、RSP、RBP、R8-R15这16个通用寄存器,如Intel还大概有:MMX:80bit X 8,ZMM(YMM,XMM):512bit X 32等寄存器,还有控制:64bit X 16,调试:64bit X 16,以及其他零散分类下及系统自用的若干。
因为这些缓存和内存在性能上的差异,所以对CPU的密集运算则是越少访问内存越好,比如在发生一次CAS操作时,如果这个内存访问能命中L2缓存,则还是比较高效的;但是如果L2 miss 连同 L3 miss ,则会变成一次读内存的重操作,影响并发的性能(约100ns的耗时),同理,对于正常的锁的操作,缓存miss时会耗时较多(约200ns的耗时)。
下面是Intel的Skylake 的架构图,与Sandy Bridge 的架构图,和AMD的ZEN 的架构图。
Intel的Skylake的架构图
Intel的Sandy Bridge 的架构图
AMD的ZEN 的架构图
Intel和AMD的CPU的架构图虽然看着差异挺大,但它们的大结构其实是一样的,大概都分为3个模块。
1. 前端执行(front end):对应Intel图的上面及对应AMD图上面;这个是L1指令cache处理指令解码(DECODE),分支预测,执行队列,调度器,等这些指令功能。
2. 计算:对应INTEL图的左下及对应AMD图的中间;这个就是整数计算单元和浮点计算单元。
从这些图上我们可以看出,L1命令缓存AMD的Zen是64KB,而Intel是32KB;L2缓存AMD的Zen是512KB,Intel是256KB,这个和CPU型号也有关系,但还是说明同一代下AMD的CPU在一些配置上更优一些。
这里也说下,网上流传说,在AMD的Zen之前Intel的CPU的强大的浮点功能(以及除法器),是Intel在跑分上胜利的其中一个重要因素,AMD认为都有显卡了,显卡浮点计算的能力非常强大,因此CPU不需要太强的浮点功能了……。
再有我们在看AMD的PPT时会发现,除了L1数据缓存到寄存器堆(register
AMD的缓存/内存部分的展开图
上面介绍了CPU整体的架构图,以及缓存在CPU架构图中的位置,这里先介绍下CPU在单核环境下的多级缓存的架构。
现在CPU都流行多核芯的架构,而我们先看其中的一个核心对缓存操作的流程,我们可以整体认为:当核心(Core)访问(读或写)L1缓存时没有命中(miss)则访问L2缓存和L3缓存,在L3缓存也没有命中时才操作内存。多级缓存在独占(exclusive)模式下,L1缓存中通过LRU策略逐出的数据会到L2,在L2中逐出的会到L3,在L3中逐出的有写入/修改的数据则同步到内存。
AMD文档中的缓存操作示意
缓存单元因其一次必须操作连续的8Byte的数据,但是我们不希望类似下面这样的情况,如两个相邻的整型(4Byte)数据会同时被多个CPU核心进行频繁修改,而其都在一个缓存单元内,其每次修改都会触发我们后面讲的核心的缓存到内存的同步问题。
我们先看看具体读写命中和未命中的情况:
1. 缓存没有命中的情况:
a). 对于单核心的读,读操作会先检查缓存,在缓存中没有数据时会载入数据到缓存(cache line fill)中。
b). 对于单核心的写,其同读操作,会先检查缓存,在缓存中没有数据时会载入数据到缓存中,然后执行写操作,这里写操作只是简单的写了载入过来的缓存,并不同步到内存(这里需要注意,按照Intel的开发文档,老的Pentium默认的情况是在缓存miss后写操作直接写内存,而不是载入数据到缓存后写缓存)。
2. 缓存命中的情况:
a). 如果读命中(cache hit),则直接使用数据;
b). 如果这里是写操命(write hit)时则也是直接操作缓存,而不主动同步到内存。
我们也看看CPU的缓存的使用流程:
1. CPU的前端解析L1命令缓存中的指令进行预测和乱序执行等
2. 通过这些指令,计算单元具体处理从L1数据缓存到寄存器中的数据的计算
3. 将计算的结果更新到L1数据缓存,若要同步缓存中的数据到内存,则通过硬件实现的写缓存逻辑(write buffers)可靠地异步刷新数据到系统总线及内存(可理解为通过一个消息队列写)。
这里可以看参考下图所示。
缓存相关流程,取自AMD技术文档
这里则是整个单核心的的流程,我们注意到,CPU通过缓存提高性能的一个关键要点是在写的情况下只写缓存,不同步缓存数据到内存。
推荐一起学习《分布式服务架构:原理、设计与实战》一书,它是一本不可多得的理论与实践相结合的架构秘籍,是作者多年工作经验积累的结晶。京东购买请扫描下方二维码。
如果你想成为优秀的架构师
在【云时代架构】精品群免费进!
我在【云时代架构】技术社区,你在哪里?
还等什么,赶快加入【云时代架构】技术社区!
请猛扫下面二维码。
云时代架构
做互联网时代最适合的架构
开放、分享、协作
快速关注,请猛扫下面二维码!
简书博客 云时代架构
版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《探索CPU的缓存架构,及引申到缓存系统的设计(一)》的版权归原作者「云时代架构」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458
文章来源: 阅读原文