0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

CPU Cache伪共享问题

程序喵大人 来源:程序喵大人 作者:程序喵大人 2022-12-12 09:17 次阅读

先看下这两段代码:

代码段1:

const int row = 10240;
const int col = 10240;
int matrix[row][col];
int TestRow() {
  //按行遍历
  int sum_row = 0;
  for (int r = 0; r < row; r++) {
    for (int c = 0; c < col; c++) {
      sum_row += matrix[r][c];
    }
  }
  return sum_row;
}

代码段2:

int TestCol() {
  //按列遍历
  int sum_col = 0;
  for (int c = 0; c < col; c++) {
    for (int r = 0; r < row; r++) {
      sum_col += matrix[r][c];
    }
  }
  return sum_col;
}

两段代码的目的相同,都是为了计算矩阵中所有元素的总和。

但有些区别:一个是按行遍历元素做计算,一个是按列遍历元素做计算。

它俩的运行速度有什么区别吗?

如图:

3234ccf4-79ba-11ed-8abf-dac502259ad0.png

32460802-79ba-11ed-8abf-dac502259ad0.png

图中可以看到,行遍历的代码速度比列遍历的代码速度快很多。

为什么按行遍历的代码比按列遍历的代码速度快?这里就是CPU Cache在起作用。

什么是CPU Cache?

可以先看下这个存储器相关的金字塔图:

325369fc-79ba-11ed-8abf-dac502259ad0.png

从下到上,空间虽然越来越小,但是处理速度越来越快,相应的,设备价格也越来越贵。

图中的寄存器和主存估计大家都知道,那中间的L1 、L2、L3是什么?它们起到了什么作用?

它们就是CPU 的Cache,如下图:

32630e66-79ba-11ed-8abf-dac502259ad0.png

可以理解为CPU Cache就是CPU与主存之间的桥梁。

当CPU想要访问主存中的元素时,会先查看Cache中是否存在,如果存在(称为Cache Hit),直接从Cache中获取,如果不存在(称为Cache Miss),才会从主存中获取。Cache的处理速度比主存快得多。

所以,如果每次访问数据时,都能直接从Cache中获取,整个程序的性能肯定会更高。

那,如何提高CPU Cache的命中率?

这里我不多介绍,感兴趣的直接移步到我这篇文章:https://mp.weixin.qq.com/s/iKWQZxn6XYKU9KnlBRynfg

但CPU Cache这里还有个小问题,看下这两段代码:

代码段1:

struct Point {
  std::atomic<int> x;
  // char a[128];
  std::atomic<int> y;
};
void Test() {
  Point point;
  std::thread t1(
      [](Point *point) {
        for (int i = 0; i < 100000000; ++i) {
          point->x += 1;
        }
      },
      &point);
  std::thread t2(
      [](Point *point) {
        for (int i = 0; i < 100000000; ++i) {
          point->y += 1;
        }
      },
      &point);
  t1.join();
  t2.join();
}

代码段2:

struct Point {
  std::atomic<int> x;
  char a[128];
  std::atomic<int> y;
};
void Test() {
  Point point;
  std::thread t1(
      [](Point *point) {
        for (int i = 0; i < 100000000; ++i) {
          point->x += 1;
        }
      },
      &point);
  std::thread t2(
      [](Point *point) {
        for (int i = 0; i < 100000000; ++i) {
          point->y += 1;
        }
      },
      &point);
  t1.join();
  t2.join();
}

两端代码的核心逻辑都是对Point结构体中的x和y不停+1。只有一点区别就是在中间塞了128字节的数组。

它们的执行速度却相差很大。

328d20a2-79ba-11ed-8abf-dac502259ad0.png

32a70d0a-79ba-11ed-8abf-dac502259ad0.png

带128的比不带128的代码,执行速度快很多。

为什么?

看过我上面文章的同学应该就知道,每个CPU都有自己的L1和L2 Cache,而Cache line的大小一般是64字节,如果x和y之间没有128字节的填充,它俩就会在同一个Cache line上。

代码中开了两个线程,两个线程大概率会运行在不同的CPU上,每个CPU有自己的Cache。

当CPU1操作x时,会把y装载到Cache中,其他CPU对应的的Cache line失效。

然后CPU2加载y,会触发Cache Miss,它后面又把x装载到了自己的Cache中,其他CPU对应的Cache line失效。

然后CPU1操作x时,又触发Cache Miss。

它俩就会是大体这个流程:

32b498b2-79ba-11ed-8abf-dac502259ad0.png

繁的触发Cache Miss,导致程序的性能相当差。

而如果x和y中间加了128字节的填充,x和y不在同一个Cache line上,不同CPU之前不会影响,它俩都会频繁的命中自己的Cache,整个程序性能就会很高,这就是传说中的False Sharing问题。

所以我们写代码时,可以基于此做深一层思考,如果我们写单线程程序,最好保证访问的数据能够相邻,在一个Cache line上,可以尽可能的命中Cache。

如果写多线程程序,最好保证访问的数据有间隔,让它们不在一个Cache line上,减少False Sharing的频率。

上述内容源于前一段的技术分享,完整PPT在一个优质的C++学习圈里,来一起钻研C++吧。


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10449

    浏览量

    206579
  • 程序
    +关注

    关注

    114

    文章

    3631

    浏览量

    79552
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66807
收藏 人收藏

    评论

    相关推荐

    CPU Cache是如何保证缓存一致性的?

    我们介绍`CPU Cache`的组织架构及其进行**读操作**时的寻址方式,但是缓存不仅仅只有读操作,还有 **写操作** ,这会带来一个新的问题
    的头像 发表于 12-04 15:05 571次阅读
    <b class='flag-5'>CPU</b> <b class='flag-5'>Cache</b>是如何保证缓存一致性的?

    Cache和Write Buffer一般性介绍

    Cache是位于CPU与主存储器即DRAM(Dynamic RAM,动态存储器)之间的少量超高速静态存储器SRAM(Static RAM)
    的头像 发表于 10-31 15:07 390次阅读
    <b class='flag-5'>Cache</b>和Write Buffer一般性介绍

    使用Cache的必要性与可行性

    使用Cache的必要性 所谓Cache即高速缓冲存储器,它位于CPU与主存即DRAM之间,是通常由SRAM构成的规模较小但存取速度很快的存储器。 目前计算机主要使用的内存为DRAM,它具有价格
    的头像 发表于 10-31 11:53 376次阅读

    Cache替换策略和Write-through介绍

    Cache和存储器一样具有两种基本操作,即读操作和写操作。当CPU发出读操作命令时,根据它产生的主存地址分为两种情形:一种是需要的数据已在Cache中,那么只需要直接访问Cache,从
    的头像 发表于 10-31 11:48 716次阅读

    Cache写入方式原理简介

    提高高速缓存命中率的最好方法是尽量使Cache存放CPU最近一直在使用的指令与数据,当Cache装满后,可将相对长期不用的数据删除,提高Cache的使用效率。 为保持
    的头像 发表于 10-31 11:43 631次阅读

    Cache工作原理是什么

    具有Cache的计算机,当CPU需要进行存储器存取时,首先检查所需数据是否在Cache中。如果存在,则可以直接存取其中的数据而不必插入任何等待状态,这是最佳情况,称为高速命中; 当CPU
    的头像 发表于 10-31 11:34 511次阅读
    <b class='flag-5'>Cache</b>工作原理是什么

    Cache内容锁定是什么

    “锁定”在cache中的块在常规的cache替换操作中不会被替换,但当通过C7控制cache中特定的块时,比如使某特定的块无效时,这些被“锁定”在cache中的块也将受到相应
    的头像 发表于 10-31 11:31 372次阅读

    Cache分类与替换算法

    根据不同的分类标准可以按以下3种方法对Cache进行分类。 •1)数据cache和指令cache •● 指令cache:指令预取时使用的cache
    的头像 发表于 10-31 11:26 469次阅读
    <b class='flag-5'>Cache</b>分类与替换算法

    Cache的原理和地址映射

    cache存储系统中,把cache和主存储器都划分成相同大小的块。 主存地址由块号B和块内地址W两部分组成,cache地址由块号b和块内地址w组成。 当CPU访问
    的头像 发表于 10-31 11:21 620次阅读

    Cache工作原理讲解 Cache写入方式原理简介

    Cache是位于CPU与主存储器即DRAM(Dynamic RAM,动态存储器)之间的少量超高速静态存储器SRAM(Static RAM),它是为了解决CPU与主存之间速度匹配问题而设置的,不能由用户直接寻址访问。
    的头像 发表于 10-17 10:37 504次阅读
    <b class='flag-5'>Cache</b>工作原理讲解 <b class='flag-5'>Cache</b>写入方式原理简介

    在组相联cache中,用于替换cache line的算法有哪些?

    LRU(Least Recently Used)算法:该算法会跟踪每个cache line的age(年龄)情况,并在需要时替换掉近期最少使用的cache line。
    的头像 发表于 10-08 11:10 478次阅读

    Linux性能优化:Cache对性能的影响

    Cache对性能的影响首先我们要知道,CPU访问内存时,不是直接去访问内存的,而是先访问缓存(cache)。 当缓存中已经有了我们要的数据时,CPU就会直接从缓存中读数据,而不是从内存
    的头像 发表于 10-04 15:31 481次阅读
    Linux性能优化:<b class='flag-5'>Cache</b>对性能的影响

    多个CPU各自的cache同步问题

      CACHE 的一致性 Cache的一致性有这么几个层面 1.     一个CPU的icache和dcache的同步问题 2.     多个CPU各自的
    的头像 发表于 06-17 10:38 1056次阅读
    多个<b class='flag-5'>CPU</b>各自的<b class='flag-5'>cache</b>同步问题

    CPU CACHE策略的初始化

    build_mem_type_table()函数的功能是获取当前CPUCACHE类型,据此初始化mem_type。
    的头像 发表于 06-05 15:03 891次阅读
    <b class='flag-5'>CPU</b> <b class='flag-5'>CACHE</b>策略的初始化

    深入理解Cache工作原理

    按照数据关系划分:Inclusive/exclusive Cache: 下级Cache包含上级的数据叫inclusive Cache。不包含叫exclusive Cache。举个例子,
    的头像 发表于 05-30 16:02 470次阅读
    深入理解<b class='flag-5'>Cache</b>工作原理