store buffer对程序的影响 #
当存在store buffer的情况下。针对写操作,CPU直接把数据扔给store buffer。后续store buffer负责以FIFO次序写回L1 Cache。这会对我们的程序产生什么影响呢?我们来看个例子。
static int x = 0, y = 0;
static int r1, r2;
static void int thread_cpu0(void)
{
x = 1; /* 1) */
r1 = y; /* 2) */
}
static void int thread_cpu1(void)
{
y = 1; /* 3) */
r2 = x; /* 4) */
}
static void check_after_assign(void)
{
printk("r1 = %d, r2 = %d\n", r1, r2);
}
假设thread_cpu0在CPU0上执行,thread_cpu1在CPU1上执行。在多核系统上,我们知道两个函数4条操作执行可以互相交错。理论上来我们有以下6种排列组合。
当我们确保thread_cpu0和thread_cpu1执行完成后,调用check_after_assign() 会打印什么提示信息呢?根据以上6种组合,我们可能会得到如下3种结果。 r1 = 1, r2 = 1 r1 = 0, r2 = 1 r1 = 1, r2 = 0 这个结果是符合我们的认知的。不过,当考虑store buffer时,有可能会出现如下结果: r1 = 0, r2 = 0
我们就以1) 3) 2) 4)的执行次序说明问题。
- 当CPU0执行x = 1时,x的值会被写入CPU0的store buffer。
- CPU1指令y = 1操作,同样y的值会被写入CPU1的store buffer。
- r1 = y执行时,CPU0读取y的值,由于y的新值依然在CPU1的store buffer里面,所以CPU0看到y的值依然是0。所以r1的值是0。
- 同样的道理,r2的值也会是0。
为什么CPU0看到r1的值是0呢?因为硬件MESI协议只会保证Cache一致性,只要值没有被写入Cache(依然躺在 store buffer里面),MESI就管不着。由于store buffer的存在,CPU0对一个地址数据的操作,其他CPU并不能及时看见。
这里有个注意点,虽然store buffer主要是用来缓存CPU的写操作,但是CPU读取数据时也会检查私有store buffer是否命中,如果没有命中才会查找L1 Cache。这主要是为了CPU自己看到自己写进store buffer的值。所以CPU0是可以看到x值更新,但是CPU1不能及时看到x。同样,CPU1可以看到y值更新,但是CPU0不能及时看到y。
单核乱序对程序员是透明的,只有其他核才会受到乱序影响。
Viewpoint #
From #
https://zhuanlan.zhihu.com/p/141655129