抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Abstract

single cache line问题

现代CPU一般都会有三级缓存L1, L2, L3。L1缓存的每个CPU独立的,L2L3是CPU间共享的。cache的存在读时可以提高读取速度,写时可以防止直接写到内存(write back, write through)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──────┐ ┌──────┐ ┌──────┐
│ │ │ │ │ │
│ cpu1 │ │ cpu2 │ │ cpu3 │
│ ┌──┐ │ │ ┌──┐ │ │ ┌──┐ │
│ │L1│ │ │ │L1│ │ │ │L1│ │
│ └▲─┘ │ │ └▲─┘ │ │ └▲─┘ │
│ │ │ │ │ │ │ │ │
└──┼───┘ └──┼───┘ └──┼───┘
│ │ │
┌──┴────────┴────────┴──┐
│ L2 │
└─────────▲─────────────┘

┌─────────┴─────────────┐
│ L3 │
└───────────────────────┘

这样一来,CPU间的L1缓存就有可能保存有各自不同的数据,从而导致一致性问题。那么就就有了缓存一致性协议

Q: 为什么L1缓存是CPU间独立的?

  1. 因为L1已经很小了,如果时CPU间共享的很容易就因为单点竞争成为瓶颈节点
  2. 如果是像L2在CPU外,CPU间共享的,那么就会导致硬件不好分布,里核心远(NUCA(非一致缓存访问)问题)

MSI

MSI分别表示”Modified”, “Shared”, “Invalid”,用于标识当前缓存的状态,cpu间需要通过内部总线(缓存总线)相互通信来达成共识。

  • 当状态为”I”时表示缓存失效,需要(通过L2)去其他状态为”S”或”M”的CPU处拿去数据
  • 当状态为”M”时表示缓存被当前CPU修改了,是独占的
  • 当状态为”S”时表示当前CPU已经从另一个”M”的CPU获取到了数据,那么这两个U都变为了”S”态

CPU需要一种类数据结构: 目录项(directory协议)来实现缓存一致性。这个目录项会记录全局的一个bit vector,用于指示哪个CPU是持有数据的(S或M)。所以一共是两个结构:

  1. 全局目录项
  2. CPU状态记录
1
2
3
4
5
6
7
8
9
CPU 0 状态记录的大致结构
| state | value |
| S | 233 |

全局目录项的大致结构
| addr | dirty | bit vector |
| x | 0 | 111 |

111就表示cpu123都是持有数据的,而能共同持有数据就说明他们的S态

为了方便期间,下面的说明就把CPU的状态直接写道bit vector里了

1
2
| addr | dirty | CPU1 | CPU2 | CPU3 |
| x | | S | S | S |

假设刚开始3个CPU都是”S”态,共享缓存。这时CPU1修改了数据,则缓存也发生了修改,那么通过短暂的”沟通”(cycle)其他CPU缓存的状态就变为了”I”

1
2
| CPU1 | CPU2 | CPU3 |
| M | I | I |

这时CPU2再对相同的数据进行了修改,那么CPU2变为M,其他变为I。

1
2
| CPU1 | CPU2 | CPU3 |
| I | M | I |

值得注意的是,虽然CPU1之前修改了数据,但是CPU2的修改并不需要”取回再该”,因为同一份数据修改是覆盖的嘛。这就是缓存带来的一个优点。

这时,CPU3需要读取数据,通过缓存发现该数据的cache的”I”的,那么它就会去其他”M”或”S”态的CPU获取缓存。之后变为

1
2
| CPU1 | CPU2 | CPU3 |
| I | S | S |

缓存一致性带来的问题

可以看到,引入缓存一致性导致了通信成本的提高,如果CPU数量再多点,那么”查表”将不是一件非常简单是事。本来一个cycle可以执行完成的操作需要”遍历所有”才能继续。

所以会发现随着CPU(core)的增加,并发程序的性能反而下降的现象。这就是no-scalable问题

导致这个问题的原因就是single cache line

评论