当前位置: 首页 > news >正文

[性能分析与优化]伪共享问题(perf + cpp)

伪共享问题的主要来源有两件事

  1. 每次cache读入一个数据时实际上读入整个数据行
  2. 多个线程可能会读入相同的数据行

由于cache写回内存时也是按照数据行进行写入的,导致了写回内存时并不能做到真正的共享,而是需要等待。

解决方案有两种

  1. 将需要并行计算的数据使用alignas等方法隔离在不同的cacheline
  2. 使用thread_local进行数据隔离

Perf

由上述分析可知,伪共享主要导致的是Cache Miss,故使用相关事件

perf stat -e cache-misses ./benchmark

用例代码

原代码
#include <iostream>
#include <thread>
#include <vector>struct SharedData {int x;int y;
};
const int epoch = 1000000000;
void incrementX(SharedData &data) {for (int i = 0; i < epoch; ++i) {data.x++;}
}void incrementY(SharedData &data) {for (int i = 0; i < epoch; ++i) {data.y++;}
}int main() {SharedData data{0, 0};std::thread t1(incrementX, std::ref(data));std::thread t2(incrementY, std::ref(data));t1.join();t2.join();std::cout << "x: " << data.x << ", y: " << data.y << std::endl;return 0;
}
threadlocal
#include <iostream>
#include <thread>
#include <vector>struct ThreadData {int x;int y;
};thread_local ThreadData threadData = {0, 0};const int epoch = 1000000000;void incrementX() {for (int i = 0; i < epoch; ++i) {threadData.x++;}
}void incrementY() {for (int i = 0; i < epoch; ++i) {threadData.y++;}
}int main() {int totalX = 0, totalY = 0;std::thread t1([&totalX]() {incrementX();totalX = threadData.x; // 将线程1的结果保存到主线程变量});std::thread t2([&totalY]() {incrementY();totalY = threadData.y; // 将线程2的结果保存到主线程变量});t1.join();t2.join();std::cout << "x: " << totalX << ", y: " << totalY << std::endl;return 0;
}
padding 
#include <iostream>
#include <thread>
#include <vector>struct SharedData {int x;char padding[60];int y;
};
const int epoch = 1000000000;
void incrementX(SharedData &data) {for (int i = 0; i < epoch; ++i) {data.x++;}
}void incrementY(SharedData &data) {for (int i = 0; i < epoch; ++i) {data.y++;}
}int main() {SharedData data{0, 0};std::thread t1(incrementX, std::ref(data));std::thread t2(incrementY, std::ref(data));t1.join();t2.join();std::cout << "x: " << data.x << ", y: " << data.y << std::endl;return 0;
}

执行结果

-O0 -gbenchmarkthreadlocalpadding
cahce-misses111727010422532208243
time(s)2.531533641.5173043140.63421379

可以发现 threadlocal方案得到的cache-misses数量几乎是padding方案的两倍,通过perf查询cpu的prefecth数据可以证明是由CPU的预取机制导致的

若使用O3,则三者性能几乎无差异


文章转载自:

http://nsZcGisC.cybch.cn
http://4wrZoaBg.cybch.cn
http://mMfWCxzD.cybch.cn
http://9npeKs3M.cybch.cn
http://hHa3CMVH.cybch.cn
http://6A0K6uO4.cybch.cn
http://GeB3wEOw.cybch.cn
http://XJOQCERw.cybch.cn
http://1HNOalv2.cybch.cn
http://yav5agJC.cybch.cn
http://hOpQWQzv.cybch.cn
http://915GaF1U.cybch.cn
http://xv09DQWh.cybch.cn
http://q0QljJpb.cybch.cn
http://7OMaDjHt.cybch.cn
http://VsfuPwqo.cybch.cn
http://zoHw7YOG.cybch.cn
http://Ac0gIZoK.cybch.cn
http://Fil3pg16.cybch.cn
http://eDsgUwyZ.cybch.cn
http://vwGFnA3d.cybch.cn
http://gdK3qPAS.cybch.cn
http://Ps73X5Ne.cybch.cn
http://bL3kZPmg.cybch.cn
http://CIeo8lpl.cybch.cn
http://KySHiRe9.cybch.cn
http://CvXljXGz.cybch.cn
http://PpQS2Elu.cybch.cn
http://RvZiM6Gx.cybch.cn
http://P4U3gEG8.cybch.cn
http://www.dtcms.com/a/388425.html

相关文章:

  • OC-动画实现折叠cell
  • 关于层级问题
  • Linux基础命令汇总
  • getchar 和 putchar
  • 【序列晋升】35 Spring Data Envers 轻量级集成数据审计
  • 快速入门HarmonyOS应用开发(二)
  • 绿联、极空间、飞牛NAS无需安装,实现快速远程访问
  • Datawhale 理工科-大模型入门实训课程 202509 第1次作业
  • 城市治理综合管理平台
  • 《嵌入式硬件(十三):基于IMX6ULL的增强型中断周期定时器(EPIT)操作》
  • PM2 入门指南与常用命令(含 开机自启、Node.js 及 Java 服务部署)
  • 汽车多核架构中内存系统故障检测的改进算法
  • C++真的比Python更快吗?
  • 【实操分享】使用 SeeDream 4.0 进行 AI 修图——开启专属“AI 云旅拍”
  • 不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
  • Python中正则的三个基础方法
  • 最外层的项目没有父pom配置文件,有很多子模块(maven项目)导入idea中,左侧模块显示不全问题解决
  • 前端将一个 DOM 元素滚动到视口顶部
  • 前端-防重复点击/防抖的方案
  • doris数据库问题
  • PyQt5中实现只读QLineEdit控件的完整指南
  • 金融工程vs金融数学:谁更贴近量化交易?
  • LeetCode 167.两数之和 II - 输入有序数组
  • 小杰机器学习高级(one)——激活函数——sigmoid、tanh、Relu、Leaky Relu、Prelu、ELU、softmax
  • OpenAI原生调用 vs LangChain调用方式的关系
  • [Token剪枝]Token Cropr: 针对众多任务的更快ViT, CVPR2025
  • NW725NW743美光固态闪存NW727NW734
  • 【Linux】归档、压缩、用户管理
  • Lattice FPGA 开发流程(以 ECP5 为例)
  • 大模型实战应用指南:从GPT-4.5到LLaMA的行业解决方案