CPU缓存
CPU缓存是位于CPU与内存之间的临时存储器,它的容量比内存小的多,但是交换速度比内存快得多。高速缓存主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度比内存快得多,这样会使CPU花费很长时间等待数据或者将数据写入内存,当CPU调用大量数据时,可以先从缓存中调用,从而加快读取速度。
CPU多级缓存
在CPU缓存出现不久,随着系统越来越复杂,高速缓存和主内存之间的速度被拉大,直到加入了另一级缓存,新加入的这级缓存比第一缓存更大,并且更慢,而且经济上不合适,所以有了二级缓存,甚至是三级缓存。每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。一般来说,每级缓存的命中率大概都在80%左右,也就是说全部数据量的80%都可以在一级缓存中找到,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个CPU缓存架构中最为重要的部分。
CPU缓存一致性
多核CPU的情况下有多个一级缓存,如何保证缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。
CPU中每个缓存行使用四种状态进行标记
M(被修改,Modified):
该缓存行只缓存在该CPU缓存中,并 且是被修改过的,与主内存数据不一 致,缓 存行的数据需要在未来某个时 间点写回主内存。当被写回主内存 之后,该缓存行就会变成独享状态。
E(独享的,Exclusive)
该缓存行只被缓存在该CPU缓存中,并且与主存数据一致,可以在任何时刻当有其他CPU读取该内存时变成共享(shared)状态,同样的,当CPU修改该缓存内容时,该状态可以变成M状态。
S(共享的,Shared)
该状态意味着该缓存行可能被多个CPU缓存,并且各个缓存与主内存数据一致,当有一个CPU修改该缓存行时,其他CPU中该缓存行可以被作废(变成无效状态(Invalid))
I(无效的,Invalid)
该缓存是无效的(可能有其他CPU修改了 该缓存行)。
在一个典型系统中,可能会有几个缓存共享主存总线,每个相应的CPU会发出读写请求,而缓存的目的就是减少CPU读写共享主存的次数。
一个缓存除在I状态外都可以满足cpu的读请求,一个invalid的缓存行必须从主存中读取来满足该CPU的请求。
一个写请求必须是在M或E状态才能被执行,如果缓存行处于S状态,必须先将其它缓存中该缓存行变成Invalid状态(也即是不允许不同CPU同时修改同一缓存行,即使该缓存行中不同位置也不允许)。
一个处于M状态的缓存行必须时刻监控所有试图读取该缓存行相对主内存的操作,这种操作必须在缓存将该缓存行写回主内存并将状态变成S之前被延迟执行。
一个处于S状态的缓存行也必须时刻监听其他缓存行使该缓存行无效或者独享缓存行的请求,并将该缓存行变成无效。
一个处于E状态的缓存行也时刻监听其他缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S状态。
对于M和E状态而言总是精确的,他们在和该缓存行的真正状态是一致的。而s状态可能是非一致的,如果一个缓存将处于S状态的缓存行作废,而另一个缓存实际可能已经独享了该缓存,但是该缓存却不会将该缓存行升迁为E状态,这是因为其他缓存不会广播他们作废掉该缓存行的通知。
同样由于缓存并没有保存该缓存行的copy的数量,因此(即使有这种通知)也没有办法确定自己是否已经独享了该缓存行。
CPU乱序执行
处理器为提高运算速度而做出的违背代码原有顺序的优化。
例如:a=10,b=20,result=a+b,正常顺序先执行a,再执行b,最后执行a+b,但假如a不在缓存中,b在缓存中,因为a不在缓存中,需要从主内存读取,这样b=20的操作就需要等待a执行完,CPU为了提高效率,先执行b=20,再执行a=10,最后执行a+b,提高执行效率。
内存屏障
CPU乱序执行在单线程环境下是一种很好的优化手段,但是在多线程环境下,就会出现数据不一致的问题,因此就可以通过内存屏障这个机制来处理这个问题。
1.写内存屏障(Store Memory Barrier):在指令后插入Store Barrier,能让写入缓存中最新数据更新写入主内存中,让其他线程可见。强制写入主内存,这种显示调用,不会让CPU去进行指令重排序
2.读内存屏障(Load Memory Barrier):在指令后插入Load Barrier,可以让高速缓存中的数据失效,强制重新从主内存中加载数据。也是不会让CPU去进行指令重排。