CPU Cache原理与示例 (2)

CPU Cache原理与示例

对于 N-Way 组关联,可能有点不好理解,这里个例子,并多说一些细节(不然后面的代码会不能理解),Intel 大多数处理器的 L1 Cache 都是 32KB,8-Way 组相联,Cache Line 是 64 Bytes。这意味着,

Ÿ   32KB的可以分成,32KB / 64 = 512 条 Cache Line。

Ÿ   因为有8 Way,于是会每一Way 有 512 / 8 = 64 条 Cache Line。

Ÿ   每一路就有 64 x 64 = 4096 Byts 的内存。

Ÿ   为了方便索引内存地址,

Ÿ   Tag:每条 Cache Line 前都会有一个独立分配的 24 bits来存的 tag,其就是内存地址的前24bits

Ÿ   Index:内存地址后续的 6 个 bits 则是在这一 Way 的是Cache Line 索引,2^6 = 64 刚好可以索引64条Cache Line

Ÿ   Offset:再往后的 6bits 用于表示在 Cache Line 里的偏移量

如下图所示:(图片来自《Cache: a place for concealment and safekeeping》)

当拿到一个内存地址的时候,先拿出中间的 6bits,找到是哪组。

CPU Cache原理与示例

然后,在这一个 8 组的 cache line 中,再进行 O(n) n=8 的遍历,主是要匹配前 24bits 的 tag。如果匹配中了,就算命中,如果没有匹配到,那就是 cache miss,如果是读操作,就需要进向后面的缓存进行访问了。

L2/L3 同样是这样的算法。淘汰算法有两种,一种是随机一种是 LRU。现在一般都是以 LRU 的算法(通过增加一个访问计数器实现)。

CPU Cache原理与示例

这也意味着:

Ÿ   L1 Cache 可映射 36bits 的内存地址,一共 2^36 = 64GB 的内存

Ÿ   当 CPU 要访问一个内存的时候,通过这个内存中间的 6bits 定位是哪个 set,通过前 24bits 定位相应的Cache Line。

Ÿ   就像一个 hash Table 的数据结构一样,先是 O(1)的索引,然后进入冲突搜索。

Ÿ   因为中间的 6bits 决定了一个同一个 set,所以,对于一段连续的内存来说,每隔 4096 的内存会被放在同一个组内,导致缓存冲突。

此外,当有数据没有命中缓存的时候,CPU 就会以最小为 Cache Line 的单元向内存更新数据。当然,CPU 并不一定只是更新 64Bytes,因为访问主存实在是太慢了,所以,一般都会多更新一些。好的 CPU 会有一些预测的技术,如果找到一种 pattern 的话,就会预先加载更多的内存,包括指令也可以预加载。

这叫 Prefetching 技术 (参看,Wikipedia 的 Cache Prefetching 和 纽约州立大学的 Memory Prefetching)。比如,在for-loop访问一个连续的数组,步长是一个固定的数,内存就可以做到prefetching。(注:指令也是以预加载的方式执行)

了解这些细节,会有利于知道在什么情况下有可以导致缓存的失效。

缓存的一致性

对于主流的 CPU,缓存的写操作基本上是两种策略,

Ÿ   一种是 Write Back,写操作只要在 cache 上,然后再 flush 到内存上。

Ÿ   一种是 Write Through,写操作同时写到 cache 和内存上。

主流的 CPU(如:Intel Core i7/i9)采用的是 Write Back 的策略,因为直接写内存实在是太慢了。

如果有一个数据 x 在 CPU 第 0 核的缓存上被更新了,其它 CPU 核上对于这个数据 x 的值也要被更新,这就是缓存一致性的问题。(当然,对于上层的程序不用关心 CPU 多个核的缓存是怎么同步的,这对上层的代码来说都是透明的)

一般来说,在 CPU 硬件上,会有两种方法来解决这个问题。

Ÿ   Directory 协议。这种方法的典型实现是要设计一个集中式控制器,主存储器控制器的一部分。其中有一个目录存储在主存储器中,其中包含有关各种本地缓存内容的全局状态信息。当单个 CPU Cache 发出读写请求时,这个集中式控制器会检查并发出必要的命令,以在主存和 CPU Cache之间或在 CPU Cache自身之间进行数据同步和传输。

Ÿ   Snoopy 协议。这种协议更像是一种数据通知的总线型的技术。CPU Cache 通过这个协议可以识别其它Cache上的数据状态。如果有数据共享的话,可以通过广播机制将共享数据的状态通知给其它 CPU Cache。这个协议要求每个 CPU Cache 都可以窥探数据事件的通知并做出相应的反应。如下图所示,有一个 Snoopy Bus 的总线。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgypyx.html