由于cpu cache line机制在共享原子数据操作上带来的硬件干扰对多线程机制的性能影响

由于cpu cache line机制在共享原子数据操作上带来的硬件干扰会对对多线程性能造成影响。例如不同的原子数据,位于同一个cpu cache line,这时候一个处理器读取这个cpu cache line这段数据的时候,就会控制这段数据的所有权,其他想要读写这段数据的处理器就会处于等等状态。这种情况就是通常说的数据伪共享。因为等待阻塞,所以影响性能。再延伸到cpu cache硬件的数据存取机制,这种影响会导致严重中的并行性能下降,大幅削弱多核优势。

cppreference中的相关代码如下:

namespace hardware_p01
{

#ifdef __cpp_lib_hardware_interference_size
using std::hardware_constructive_interference_size;
using std::hardware_destructive_interference_size;
#else
// 在 x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ... 上为 64 字节
constexpr std::size_t hardware_constructive_interference_size = 64;
constexpr std::size_t hardware_destructive_interference_size  = 64;
#endif

std::mutex cout_mutex;

constexpr int max_write_iterations{10'000'000}; // 性能评估时间调节

struct alignas(hardware_constructive_interference_size)
    OneCacheLiner
{   // 两个原子变量总共占据一条缓存线(cpu cache line)
    std::atomic_uint64_t x{};
    std::atomic_uint64_t y{};
} oneCacheLiner;

struct TwoCacheLiner
{ // 两个原子变量各自独立占据一条缓存线,总共使用了两条缓存线(cpu cache line)
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t x{};
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t y{};
} twoCacheLiner;

inline auto now() noexcept { return std::chrono::high_resolution_clock::now(); }

template <bool xy>
void oneCacheLinerThread()
{
    const auto start{now()};

    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
            oneCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else
            oneCacheLiner.y.fetch_add(1, std::memory_order_relaxed);

    const std::chrono::duration<double, std::milli> elapsed{now() - start};
    std::lock_guard                                 lk{cout_mutex};
    std::cout << "oneCacheLinerThread() spent " << elapsed.count() << " ms\n";
    if constexpr (xy)
        oneCacheLiner.x = elapsed.count();
    else
        oneCacheLiner.y = elapsed.count();
}

template <bool xy>
void twoCacheLinerThread()
{
    const auto start{now()};

    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
            twoCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else
            twoCacheLiner.y.fetch_add(1, std::memory_order_relaxed);

    const std::chrono::duration<double, std::milli> elapsed{now() - start};
    std::lock_guard                                 lk{cout_mutex};
    std::cout << "twoCacheLinerThread() spent " << elapsed.count() << " ms\n";
    if constexpr (xy)
        twoCacheLiner.x = elapsed.count();
    else
        twoCacheLiner.y = elapsed.count();
}

void testMain()
{
    std::atomic_uint64_t ap_01{};
    std::cout << "sizeof(int): " << sizeof(int) << " bytes\n";
    std::cout << "sizeof(long): " << sizeof(long) << " bytes\n";
    std::cout << "sizeof(long long): " << sizeof(long long) << " bytes\n";
    std::cout << "sizeof(std::atomic_uint64_t): " << sizeof(std::atomic_uint64_t) << " bytes\n";
    std::cout << "\n";
    std::cout << "sizeof(oneCacheLiner.x): " << sizeof(oneCacheLiner.x) << " bytes\n";
    std::cout << "sizeof(oneCacheLiner.y): " << sizeof(oneCacheLiner.y) << " bytes\n";
    std::cout << "sizeof(oneCacheLiner): " << sizeof(oneCacheLiner) << " bytes\n";
    std::cout << "\n";
    std::cout << "sizeof(twoCacheLiner.x): " << sizeof(twoCacheLiner.x) << " bytes\n";
    std::cout << "sizeof(twoCacheLiner.y): " << sizeof(twoCacheLiner.y) << " bytes\n";
    std::cout << "sizeof(twoCacheLiner): " << sizeof(twoCacheLiner) << " bytes\n";
    std::cout << "\n";
    // 获得当前系统cpu核心数量
    auto cupCount = std::thread::hardware_concurrency();
    std::cout << "cpu核心数量: " << cupCount << "\n";
    std::cout << "\n";

    std::cout << "__cpp_lib_hardware_interference_size "
#ifdef __cpp_lib_hardware_interference_size
                 " = "
              << __cpp_lib_hardware_interference_size << "\n";
#else
                 "is not defined, use 64 as fallback\n";
#endif

    std::cout
        << "hardware_destructive_interference_size == "
        << hardware_destructive_interference_size << '\n'
        << "hardware_constructive_interference_size == "
        << hardware_constructive_interference_size << "\n\n";

    std::cout
        << std::fixed << std::setprecision(2)
        << "sizeof( OneCacheLiner ) == " << sizeof(OneCacheLiner) << '\n'
        << "sizeof( TwoCacheLiner ) == " << sizeof(TwoCacheLiner) << "\n\n";

    constexpr int max_runs{4};

    int oneCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i)
    {
        std::thread th1{oneCacheLinerThread<0>};
        std::thread th2{oneCacheLinerThread<1>};
        th1.join();
        th2.join();
        oneCacheLiner_average += oneCacheLiner.x + oneCacheLiner.y;
    }
    std::cout << "Average time: " << (oneCacheLiner_average / max_runs / 2) << " ms\n\n";

    int twoCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i)
    {
        std::thread th1{twoCacheLinerThread<0>};
        std::thread th2{twoCacheLinerThread<1>};
        th1.join();
        th2.join();
        twoCacheLiner_average += twoCacheLiner.x + twoCacheLiner.y;
    }
    std::cout << "Average time: " << (twoCacheLiner_average / max_runs / 2) << " ms\n\n";
}
} // namespace hardware_p01

运行上述代码中的 testMain函数,控制台输出如下:

sizeof(int): 4 bytes
sizeof(long): 4 bytes
sizeof(long long): 8 bytes
sizeof(std::atomic_uint64_t): 8 bytes

sizeof(oneCacheLiner.x): 8 bytes
sizeof(oneCacheLiner.y): 8 bytes
sizeof(oneCacheLiner): 64 bytes

sizeof(twoCacheLiner.x): 8 bytes
sizeof(twoCacheLiner.y): 8 bytes
sizeof(twoCacheLiner): 128 bytes

cpu核心数量: 16

__cpp_lib_hardware_interference_size  = 201703
hardware_destructive_interference_size == 64
hardware_constructive_interference_size == 64

sizeof( OneCacheLiner ) == 64
sizeof( TwoCacheLiner ) == 128

oneCacheLinerThread() spent 206.88 ms
oneCacheLinerThread() spent 208.91 ms
oneCacheLinerThread() spent 256.23 ms
oneCacheLinerThread() spent 264.54 ms
oneCacheLinerThread() spent 167.86 ms
oneCacheLinerThread() spent 173.16 ms
oneCacheLinerThread() spent 198.84 ms
oneCacheLinerThread() spent 207.99 ms
Average time: 209 ms

twoCacheLinerThread() spent 59.24 ms
twoCacheLinerThread() spent 59.37 ms
twoCacheLinerThread() spent 61.98 ms
twoCacheLinerThread() spent 66.52 ms
twoCacheLinerThread() spent 65.99 ms
twoCacheLinerThread() spent 68.66 ms
twoCacheLinerThread() spent 59.04 ms
twoCacheLinerThread() spent 63.32 ms
Average time: 62 ms

由上述代码可以看出,当两个原子变量的数据位于同一个cpu cache line的时候(oneCacheLiner中的x和y)访问耗时,是位于各自独立的cpu cache line的数据(twoCacheLiner中的x和y)访问耗时的3倍多。

顺带提一下阿姆达尔定律(Amdahl's law,Amdahl's argument),这是一个计算机科学界的经验法则,因吉恩·阿姆达尔而得名。它代表了处理器并行运算之后效率提升的能力。

上图公式的含义是: 当程序“串行”部分的耗时用fs来表示的时候,那么性能增益(P)就可以通过处理器数量(N)进行估计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/99406.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ASUS华硕VivoBook15笔记本V5200EA_X515EA原装出厂Win11预装OEM系统

华硕11代酷睿笔记本电脑VivoBook_ASUSLaptop X515EA_V5200EA原厂Windows11系统 自带显卡、声卡、网卡、蓝牙等所有驱动、出厂主题壁纸、Office办公软件、华硕电脑管家MyASUS、迈克菲等预装程序 链接&#xff1a;https://pan.baidu.com/s/1yAEdA7aiuHK4CTdGLlSOKw?pwdo45a …

ShardingJDBC——分库分表实践

摘要 本文主要介绍分表分库&#xff0c;以及SpringBoot集成基于ShardingJDBC的单库分表实践。 一、Sharding-JDBC Sharding-JDBC是ShardingSphere的第一个产品&#xff0c;也是ShardingSphere的前身。 它定位为轻量级Java框架&#xff0c;在Java的JDBC层提供的额外服务。它使…

汽车服务门店小程序模板制作指南

在数字化时代&#xff0c;一个小程序的力量不可忽视。它不仅是展示品牌形象和提供用户服务的重要工具&#xff0c;更是扩大客户群体和提高营收的关键手段。对于汽车服务门店来说&#xff0c;拥有一个精美且功能齐全的小程序&#xff0c;更将成为你在竞争激烈的市场中的重要武器…

排序算法的稳定性

稳定性&#xff1a;对于一个数&#xff0c;经过多次排序&#xff0c;保留一个数之间的相对次序 在基础类型数据上&#xff0c;稳定性用处不大 在非基础类型上&#xff0c;可以做到对于相同元素来说&#xff0c;排完序相同元素之间的相对次序不变 归并排序在merge的过程中先拷贝…

django/CVE-2017-12794XSS漏洞复现

docker搭建漏洞复现环境 漏洞原理看帮助文档 # Django debug page XSS漏洞&#xff08;CVE-2017-12794&#xff09;分析Django发布了新版本1.11.5&#xff0c;修复了500页面中可能存在的一个XSS漏洞&#xff0c;这篇文章说明一下该漏洞的原理和复现&#xff0c;和我的一点点评…

ssm星空游戏购买下载平台源码和论文PPT

ssm星空游戏购买下载平台的设计与实现112 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优…

【注册岩土】Python土力学与基础工程计算.PDF-土中的应力

Python 求解代码如下&#xff1a; 1&#xff0e;&#xff03;计算竖向有效自重应力2.h12#m3.h21.5#m4.h31#m5.gamma1 19# kN/m^36.gamma218# kN/m^37.gamma317# kN/m^38.sigma_c gammal * h1 gamma2*h2 gamma3 *h39&#xff0e;print&#xff08;&#xff02;竖向有效自重应力…

9.1 消息 字体 颜色 文件对话框 发布软件

保存 void Widget::on_savebtn_clicked() {QString filename QFileDialog::getSaveFileName(this, "保存", "C:/Users/yc/Desktop/", "图片 (*.png *.xpm *.jpg);;文本 (*.txt);;所有文件 (*.*)");if(filename.isNull()){QMessageBox::informa…

Lvs+KeepAlived高可用高性能负载均衡

目录 1.环境介绍 2.配置keepalived 3.测试 1.测试负载均衡 2.测试RS高可用 3.测试LVS高可用 3.1测试lvs主服务宕机 3.2.测试lvs主服务器恢复 4.我在实验中遇到的错误 1.环境介绍 环境&#xff1a;centos7 RS1---RIP1:192.168.163.145 VIP 192.168.163.200 RS2---RIP2…

PlumeLog【lite模式】部署使用

一 简述 本文档记录PlumeLog【lite模式】模式安装使用 启动模式 优点 缺点 Lite 模式 不依赖任何外部中间件直接启动使用&#xff0c;部署简单 性能有限&#xff0c;一天10G内可以应付&#xff0c;最好是SSD硬盘,适合管理系统类小玩家 Plumelog: 一个简单易用的java日志…

无人机自主飞行实战入门-第一课(简介)

研究的意义&#xff1a;对人类操作的严重依赖&#xff0c;严重阻碍了泛无人机行业的发展。 飞行汽车&#xff08;UAM&#xff09;即将到来&#xff0c;不论是从成本还是安全考虑都需要自主飞行。 传统飞控基于STM32架构设计&#xff0c;无法满足更智能功能所需的计算量&#xf…

python评分卡模型

信用风险计量模型可以包括跟个人信用评级&#xff0c;企业信用评级和国家信用评级。人信用评级有一系列评级模型组成&#xff0c;常见是A卡&#xff08;申请评分卡&#xff09;、B卡&#xff08;行为模型&#xff09;、C卡&#xff08;催收模型&#xff09;和F卡&#xff08;反…

震动分析国标GB/T 19873.3-2019/ISO 13373-3:2015笔记

1.国家标准 1.1震动测量 现行国家标准是&#xff1a;GB/T 19873.2-2009 机器状态监测与诊断 振动状态监测 第2部分&#xff1a;振动数据处理、分析与描述 它的起草人&#xff1a; 郑州机械研究所。西安热工研究院有限公司。东南大学。 主要起草人 韩国明 、张学延 、傅行…

css学习7(盒子模型)

1、盒子模型图&#xff1a; Margin(外边距) - 清除边框外的区域&#xff0c;外边距是透明的。Border(边框) - 围绕在内边距和内容外的边框。Padding(内边距) - 清除内容周围的区域&#xff0c;内边距是透明的。Content(内容) - 盒子的内容&#xff0c;显示文本和图像。 <!DO…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十一:通用表单组件封装实现

一、本章内容 本章实现通用表单组件,根据实体配置识别实体属性,并自动生成编辑组件,实现对应数据填充、校验及保存等逻辑。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址:

Apollo领航官送福利啦

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f388;✨百度apollo介绍 全球智能驾驶产业领跑者 起源 百度…

达梦数据库分区表介绍

概述 本文将对达梦数据库分区表概念、创建、维护进行介绍。 1.分区表概念 1.1 分区表使用场景 近几年&#xff0c;随着移动支付快速发展&#xff0c;银行交易系统中【移动小微支付场景】使用越来越多&#xff0c;系统中流水账单表数据量巨大&#xff0c;往往上TB。 为了提高…

Error:Java:无效的源发行版:14

问题描述&#xff1a;项目拉下来&#xff0c;跑的时候发现版本有问题。这个问题可好解决了&#xff0c;只需要看下面几个方面&#xff0c;然后让他们保持一致就OK了 step1&#xff1a;查看本地的jdk版本 打开cmd窗口&#xff0c;输入命令 java -version就可以查看到本地的jdk版…

3.卷积层相关概念

3.1 卷积原理 ① Conv1d代表一维卷积&#xff0c;Conv2d代表二维卷积&#xff0c;Conv3d代表三维卷积。 ② kernel_size在训练过程中不断调整&#xff0c;定义为3就是3 * 3的卷积核&#xff0c;实际我们在训练神经网络过程中其实就是对kernel_size不断调整。 ③ 可以根据输入…

uniapp 布局(自定义导航栏加固定高度的主要内容)

不想让整体页面出现滚动条 页面大致分为三部分&#xff0c;导航栏、主题内容、tabbar&#xff0c;不想让整个页面出现滚动条&#xff0c;只想让主要内容滚动。 我这里是直接用了uni.getSystemInfoSync()&#xff0c;整体分为两部分&#xff0c;自定义头部和滚动内容&#xff…