🌟🌟🌟博主主页:MuggleZero 🌟🌟🌟
《ARMv8架构初学者笔记》专栏地址:《ARMv8架构初学者笔记》
前文:
cache是以cache line为单位去内存中取数据并且缓存数据的,一般来说cache line的大小为64字节。当访问long类型数组中某个成员时,CPU会将临近的数组成员都加载到痛一个cache line中,这样可以加速访问。问题是,如果此时有另一个处理器也想访问临近的数组成员,这就回导致这个cache line被频繁的导入导出,造成很大的性能问题。所以这就是cache伪共享。
cache伪共享分析
假设,CPU0上的线程0想访问和更新x,CPU1上的线程1想访问和更新y,x和y都被加载到了一个cache line中。
现在我们根据MESI协议来分析cache line的使用情况:
-
CPU0第一次访问x,由于此时cache还没有数据x,所以此时cache line0为I。在CPU0将data放进cache line0后,此时cache line0的状态为E。
-
CPU1第一次访问y时,由于此时y已经缓存在了CPU0的cache line0中,并且此cache line0状态为E。CPU1向总线发起读请求,CPU0收到请求后,将这个cache line0的数据发到总线上。CPU1获取到数据后,经本地cache line1和远程的cache line0设置为S。此时所有的cache line都是S状态。
-
CPU0想更新x时,CPU0和CPU1的cache line都是S。CPU0发送BusUpgr到总线上,然后修改本地的cache line0数据,将其改成M状态。在CPU1收到BusUpgr信号后,必须将本地的cache line1副本设置为I。(更新数据必须关闭其他的副本)(这里只更新了x,y没有更新)
-
CPU1想更新y时,此时CPU1的cache line1为I。CPU0上的cache line0缓存了旧数据y,且cache line0状态为M。CPU1发起本地写请求,根据MESI协议,CPU1发送BusRdX到总线上(广播信号,人人都能听到)。CPU0在收到信号后,发出应答信号。由于此时CPU0上的cache line0缓存了旧数据y,且cache line0状态为M。CPU0会先将数据放到内存,将cache line0设置为I,然后CPU1才可以修改cache line1的数据y,cache line1改成M。
-
CPU0想修改x的过程和4类似。
两个CPU像4和5一样不断争夺cache line控制权,不断使对方的cache line失效,写数据回内存的行为导致性能下降。这种行为就叫做cache伪共享。
cache伪共享的解决
解决cache伪共享的思想是对于多线程操作的数据,使得数据处在不同的cache line。
例如采用cache line填充/cache line对齐,让数据结构按照cache line行的大小(例如64字节对齐)对齐。
欢迎关注我的个人微信公众号,一起交流学习嵌入式开发知识!
关注「求密勒实验室」