首页 > 其他分享 >CPU缓存伪共享

CPU缓存伪共享

时间:2023-11-01 22:45:50浏览次数:31  
标签:缓存 int cache CPU tl 共享 line

CPU缓存什么东西?当然这个问题很多人有可能觉得比较傻,CPU缓存什么,肯定是缓存数据(代码)啊,要不然还能缓存啥,这个确实没问题,但是CPU到底缓存什么样的数据呢?因为对CPU来说,无论是指令,还是数据,都是数据,他如果要缓存,缓存的单位是啥?要缓存的内容是啥呢?

接下来咱们一点点解析这部分的内容,首先看一个比较有意思的代码

#include <thread>
#include <iostream>
#include <sys/time.h>

//设置一个10亿的执行次数
#define MAX_NUM  1000000000

struct TestLine {
  int x;
  int y;
};
int GetTimeCost(const timeval &beg,const timeval &end) {
  return (end.tv_sec-beg.tv_sec) * 1000 + (end.tv_usec-beg.tv_usec)/1000;
}
void T1Func(TestLine* tl){
  for( int it = 0; it< MAX_NUM ; ++it) {
    tl->x +=1;
  }
  return;
}
void T2Func(TestLine *tl) {
  for ( int it = 0;it < MAX_NUM ; ++it) {
    tl->y +=1;
  }
  return ;
}
int main(){
  timeval beg,end;
  gettimeofday(&beg,NULL);
  TestLine tl = {0,0};
  std::thread t1(T1Func,&tl);
  std::thread t2(T2Func,&tl);
  t1.join();
  t2.join();
  gettimeofday(&end,NULL);
  std::cout << "cost = "<< GetTimeCost(beg,end) << "ms ,x="<< tl.x << ",y="<< tl.y << std::endl;
  return 0;
}

这是一段很简单的程序,启动两个线程,分别对结构体中的x变量与y变量进行操作,循环10亿次,在大家看来,这段代码是两个线程分别对两个变量进行操作,其实是两者毫无关联的动作,我们执行一下这段代码,看下耗时

image
线程执行耗时

接下来咱们再看一下下面的代码

#include <thread>
#include <iostream>
#include <sys/time.h>

//设置一个10亿的执行次数
#define MAX_NUM  1000000000

struct TestLine {
  int x;
  long long buf[8]; // 新增一个8个long long 类型的数组
  int y;
};
int GetTimeCost(const timeval &beg,const timeval &end) {
  return (end.tv_sec-beg.tv_sec) * 1000 + (end.tv_usec-beg.tv_usec)/1000;
}
void T1Func(TestLine* tl){
  for( int it = 0; it< MAX_NUM ; ++it) {
    tl->x +=1;
  }
  return;
}
void T2Func(TestLine *tl) {
  for ( int it = 0;it < MAX_NUM ; ++it) {
    tl->y +=1;
  }
  return ;
}
int main(){
  timeval beg,end;
  gettimeofday(&beg,NULL);
  TestLine tl = {0,0};
  std::thread t1(T1Func,&tl);
  std::thread t2(T2Func,&tl);
  t1.join();
  t2.join();
  gettimeofday(&end,NULL);
  std::cout << "cost = "<< GetTimeCost(beg,end) << "ms ,x="<< tl.x << ",y="<< tl.y << std::endl;
  return 0;
}

这段代码与上面的那段代码最大的区别就是:在结构体中增加了一个8个long long类型的数组,接下来我们看下这段代码的执行情况:

image

注:以上代码是在C++11环境下进行编译运行,大家可以通过 g++ -lpthread -std=c++11 http://xxx.cc方式进行编译

大家可以看到,这段代码与上段代码最终x与y的输出是一致的,但是耗时上,这段代码要比第一段代码执行时间降低50%以上,为啥?

为什么我已经把数据缓存到本地了,通过增加一个数组,就可以提升程序的运行时间呢?

cache line(缓存行)

通过上面的一个小程序,大家是不是会存在很多疑惑,为啥只是增加了一个数组,整个程序的运行时间就大幅度提高了,下面我们来简单解释一下这里面的原因。

通过上文我们知道,CPU为了提升运行速度,是存在缓存的,但是CPU的缓存,到底缓存了啥呢?数据+指令

CPU的缓存单位是啥呢?cache line,cache line 到底是个啥东西呢?cache line 就是CPU执行时,从内存中读取内容的最小单位,那cache line大小是多少呢?一般是64个字节(当然不同的体系结构及厂商设定的cache line大小是不一样的),为啥是64个字节,不是其他值呢?哈哈,我也不知道,大概率就是测试出来64的性价比+性能是最优的吧。

典型的cache line结构如下:

image

tag用于标识这个缓存行,data字段用于存储实际的内容数据(这就是我们所说的64字节大小的部分),flag用于标记这个缓存行的状态

如何获取到系统的缓存行大小信息呢?

getconf -a | grep CACHE

上述可以看到,计算机有三层缓存,并且每层缓存中的cache line都是64字节。

现在我们来解释一下上两段代码的差异吧。我们知道CPU缓存数据是以cache line为单位,并且每个cache line的大小大概是64个字节,我们就可以看出,在第一段代码中,结构体中的x成员与y成员,大概率会在同一个cache line 中,如果这两个线程分别对这个cache line进行操作,那么很有可能会造成读写这段cache line临界区的程序变成串行,因为两个线程同时操作一个cache line,肯定会存在覆盖写的问题,为了解决覆盖写,所以这段数据只能是串行(你写完之后,我在读取,然后我在写)这种模式

那再来分析一下第二段代码,第二段代码在两个变量中间增加了long long类型的数组,数组大小为8,为啥是这个数字内,因为上文中简单介绍了,一般cache line的大小是64个字节,当然大家也可以增加一个64个char型的数组,效果其实是一样的。当我们增加了这么第一段看似没有用的数据之后,我们就可以猜测出来,x与y,大概率不会再同一个cache line中了,所以这两个线程操作的是两个不同的cache line,完全可以实现线程的并行执行(因为已经不存在临界区的东西了),所以第二段代码的执行时间也是第一段代码的50%(可解释)

所以通过分析可以得出,CPU虽然把数据进行了缓存,但是这些缓存有时候并不能完全做到数据共享,而是有部分数据发生变化之后,其余CPU的数据也必须跟着发生变化,这就是所谓的CPU缓存的“伪共享”问题。

标签:缓存,int,cache,CPU,tl,共享,line
From: https://www.cnblogs.com/linhaostudy/p/17804316.html

相关文章

  • “共享书角”图书借还管理系统 小程序-计算机毕业设计源码+LW文档
    小程序框架:uniapp小程序开发软件:HBuilderX小程序运行软件:微信开发者数据库:DROPTABLEIFEXISTSchujiezhe;/*!40101SET@saved_cs_client=@@character_set_client/;/!40101SETcharacter_set_client=utf8/;CREATETABLEchujiezhe(idbigint(20)NOTNULLAUT......
  • [20231023]为什么刷新缓存后输出记录顺序发生变化6.txt
    [20231023]为什么刷新缓存后输出记录顺序发生变化6.txt--//前几天做了单表刷新缓存后输出记录顺序发生变化的情况,测试2个表的情况时遇到一个奇怪的现象。--//我前面的测试18c,如果使用10046跟踪看不到我遇到的情况,我想使用strace跟踪,发现该机器配置使用asm,strace跟踪无法看到一--/......
  • Linux【CPU100% 问题定位】
    一、场景     在我们项目部署上线的时候,我们是不是会经常去Linux服务器上查查服务器的CPU使用率,或者是运维经常会盯Linux的CPU使用率。如果CPU使用率一直100%,如何查找并解决问题?二、步骤    2.1、定位到进程        使用top和ps分析工具报告......
  • 【转载】 CPU漏洞 —— 一步一步理解CPU芯片漏洞:Meltdown与Spectre
    原文:https://www.freebuf.com/articles/system/159811.html 参考:https://blog.csdn.net/xy010902100449/article/details/128366616 ------------------------------------------------   ( 详细内容请访问原文地址:https://www.freebuf.com/articles/system/159811......
  • 两台电脑在相同网络下使用共享文件夹进行文件的传递
    如题,如何使用共享文件夹,实现两台电脑的文件传递。首先要保证两台电脑处于同一网络下(同一WIFI下)例如电脑A上有个share_file文件夹,我们的目的是,将其变成两台电脑共享的文件夹。电脑A和B都可以对其进行文件的增删改查。电脑A的操作: 右键点击文件夹,选择属性,出现对话框后点击共......
  • 电脑间共享文件夹传输(Win10和Win11皆可)
    电脑间共享文件夹传输笔者自己是在笔记本和台式之间传输,为了保证两台电脑处在同一局域网下,可以选择连接同一Wifi或使用手机热点更改所连Wifi网络类型为专用两台电脑的Wifi网络类型都要更改更改高级共享设置打开“控制面板”打开“网络和Internet”打开“网络与共......
  • 查看调整cpu频率及模式
    使用cpufrequtils查看调整cpu频率及模式cpufrequtils是一个查看和修改CPU频率GHz的工具有些物理服务器使用默认频率进行运行,这时可以使用该工具进行就该CPU的核心频率安装:aptinstallcpufrequtilsyuminstallcpufrequtils使用:#查看全部核心详细信息cpufreq-info#查......
  • 查看调整cpu频率及模式
    使用cpufrequtils查看调整cpu频率及模式cpufrequtils是一个查看和修改CPU频率GHz的工具有些物理服务器使用默认频率进行运行,这时可以使用该工具进行就该CPU的核心频率安装:aptinstallcpufrequtilsyuminstallcpufrequtils使用:#查看全部核心详细信息cpufreq-info#......
  • CPU 100%问题排查
    引用:https://blog.csdn.net/qq_37515544/article/details/123921604https://blog.csdn.net/yujing1314/article/details/114524668 一、定位哪个程序占用的CPU较高linux命令:top    二、jstack使用2.1栈信息输出命令格式:jstackpid>文件信息eg:jstack5115>a.tx......
  • 一文带你理解tcache缓存投毒
    tcache结构分析Tcache(ThreadCache)是glibc(GNUCLibrary)从2.26版本开始引入的一个特性,旨在提升内存分配性能。在tcache中,每个线程都有自己的缓存,可以减少线程间的互斥和锁的竞争。默认情况下,大小小于等于1032(0x408)字节的chunk会被放入tcache中。分配释放:当程序进行......