查看缓存:
三级缓存
ls /sys/devices/system/cpu/cpu0/cache/
index0 index1 index2
64组
cat /sys/devices/system/cpu/cpu0/cache/index1/number_of_sets
64
每组8个cache line
cat /sys/devices/system/cpu/cpu0/cache/index1/ways_of_associativity
8
每个cache line 64字节
cat /sys/devices/system/cpu/cpu1/cache/index0/coherency_line_size
64
设置对齐方式并多线程测试:
41 #pragma pack (1)
42 struct Data{
43 int32_t c[15];
44 int64_t v;
45 };
46 #pragma pack ()
当前字节数,68字节;
如果去掉#pragma pack,72字节;
声明全局变量,Data g_data;
开多个线程,每个线程修改g_data.v,出现一半0,一半f的可能;
打印格式:
int64_t v;
printf("%016lx\n", v);
注意 lx 不是x;
cache line:
cache line是缓存最小单元,一致性也是以该单位保证的;
因此,如果字节出现问题,比如自定义68,就会导致变量 v,存在于不同的cache line中,无法保证数据计算的原子性,性能降低;
比如,取反操作,本来是一步缓存操作,正常结果应该是,0000000000000000或全f,但是,我们改变对齐方式后,变成两步缓存操作,发现可能出现一半0一般f的情况;
当然,如果我们加锁,会发现,又恢复正常了;
因此,如果我们自己设置字节对齐,就要考虑cache line造成的问题,以及性能问题,即使该结构体在64字节以内,不对其也会出现该问题;
perf比较:
perf stat -e cache-misses ./a.out
Performance counter stats for './a.out':
1,319,787 cache-misses
1.276630791 seconds time elapsed
2.300531000 seconds user
0.054351000 seconds sys
Performance counter stats for './a.out':
203,949 cache-misses
0.788336163 seconds time elapsed
0.370216000 seconds user
0.023443000 seconds sys
前面是非对齐,后面时对齐的,对比耗时和cache碰撞;性能下降碰撞提高;
汇编:
i++,++i,i=2,i = ~i,都是一条指令;
虽说是原子操作,但是,这里涉及到内存,cache等问题,导致了数据不一致;
数组测试累加操作:
仍然多线程,奇数修改g_data1[0],否则修改另一个;
48 struct Data1{
49 int64_t v = 0;
50 //int64_t v1[7];
51 };
48 struct Data2{
49 int64_t v = 0;
50 int64_t v1[7];
51 };
48 struct Data3{
49 int64_t v = 0;
51 } __attribute__((aligned(64)));
Data1 g_data1[2];
三种数据测试发现,第一和第二性能一样,第三个低下
Performance counter stats for './a.out':
206,134 cache-misses
1.164900225 seconds time elapsed
0.232928000 seconds user
0.019443000 seconds sys
Performance counter stats for './a.out':
605,687 cache-misses
1.162921806 seconds time elapsed
0.958455000 seconds user
0.030287000 seconds sys
为什么拆分64对齐后,性能反而差了?