问题标签 [false-sharing]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
java - 为什么在 Disruptor 中有 7 个填充字段,但在 Mechanical Sympathy 中有 6 个字段 - 错误共享
在 LMAX-Exchange/Disruptor 3.4.3 中,RingBuffer在其实际字段之前放置了 7 个长填充字段(通过 extends RingBufferPad )
并在最后放置另外 7 个长填充字段以避免错误共享
问题是为什么要放置 7 个长填充字段,而不是Mechanical Sympathy - False Sharing中描述的 6 个字段。
parallel-processing - 写入单个向量时 OpenMP 中的错误共享
我是通过Tim Matterson 的讲义学习 OpenMP 的,他举了一个虚假共享的例子,如下所示。代码很简单,用于从 4.0/(1+x*x) 的数值积分计算 pi,x 范围为 0 到 1。代码使用向量来包含 4.0/(1+x*x) 的值对于从 0 到 1 的每个 x,然后对最后的向量求和:
我对这个示例中的虚假共享有一些疑问:
- 是不是因为写入数组的工作在两个线程(即[thread0, thread1, thread0, thread1, ...])之间间歇性地划分而导致的错误共享?如果我们使用
#pragma omp parallel for
,那么数组将被划分为 [thread0, thread0, thread0, ...., thread1, thread1, thread1, ...],那么我们是否仍然存在错误共享,现在每个地址都被访问线程彼此相距很远? - 如果我有一份工作用于
#pragma omp parallel for
写入与我的输入向量具有 1 对 1 对应关系的输出向量(例如,输入是预测变量矩阵,输出是预测向量),那么我什么时候需要担心虚假分享?
c++ - 多核虚假共享
下面的程序会不会发生虚假分享?
记忆
- 1个数组分成4个相等的区域:
[A1, A2, B1, B2]
- 整个数组可以放入实际程序中的 L1 缓存中。
- 每个区域被填充为 64 字节的倍数。
脚步
测试
结果
c++ - 编译器优化消除了错误共享的影响。如何?
正如Tim Mattson在 OpenMP 介绍中所解释的那样,我正在尝试使用 OpenMP 复制虚假共享的效果。
我的程序执行一个简单的数值积分(有关数学细节,请参阅链接),我已经实现了两个版本,第一个版本应该是缓存友好的,让每个线程保留一个局部变量来累积其索引空间的一部分,
而第二个版本让每个线程更新共享中的一个元素std::vector<double>
,导致每次写入都使所有其他线程上的缓存行无效
问题是我无法看到任何虚假共享的影响,除非我关闭优化。
使用没有优化 (-O0) 的 GCC 8.1 编译我的代码(它必须考虑比上面的代码片段更多的细节)会产生我天真的预期的结果,而使用完全优化 (-O3) 消除了性能方面的任何差异两个版本,如图所示。
对此有何解释?编译器是否真的消除了虚假共享?如果不是,为什么运行优化后的代码效果那么小?
我在使用 Fedora 的 Core-i7 机器上。该图显示平均值,其样本标准差不会向该问题添加任何信息。
rust - 无法在 Rust 中重现错误的缓存行共享问题
我正在尝试重现处理器缓存效果库的示例 6 。
文章以这个函数(在 C# 中)为例如何测试虚假共享:
如果我们创建传递给这个函数 0、1、2、3 个参数的线程,计算将需要很长时间才能完成(作者得到了 4.3 秒)。例如,如果我们通过 16、32、48、64,我们会得到更好的结果(0.28 秒)。
我在 Rust 中提出了以下函数:
用两组参数(0、1、2、3 和 0、16、32、48)对其进行基准测试,得到了几乎相同的结果:108.34 和 105.07 微秒。
我使用标准箱作为基准。我有一台配备 Intel i5-5257U CPU (2.70GHz) 的 MacBook Pro 2015。我的系统报告有64B
缓存行大小。
如果有人想查看我的完整基准测试代码,请点击以下链接:- lib.rs - cache_lines.rs
我想了解问题并找到重现文章中类似结果的方法。
c++ - 一次加载整个缓存行以避免争用它的多个元素
假设我需要从一个竞争激烈的缓存行中获取三条数据,有没有办法“原子地”加载所有三样东西,以避免多次往返于任何其他核心?
对于所有 3 个成员的快照,我实际上并不需要原子性的正确性保证,只是在正常情况下,所有三个项目都在同一个时钟周期内读取。我想避免缓存行到达的情况,但是在读取所有 3 个对象之前出现无效请求。这将导致第三次访问需要发送另一个请求来共享线路,从而使争用更加严重。
例如,
我能否以某种方式确保one
,two
并且three
在没有多个 RFO 的情况下在激烈的争用下全部加载在一起(假设f1
并且f2
正在同时运行)?
这个问题的目标架构/平台是 Intel x86 Broadwell,但是如果有一种技术或编译器内在允许做一些像这样的尽力而为的事情,那也很好。
c - 多线程应用程序中的静态常量变量是否应该声明为thread_local以避免错误共享?
有一段时间我认为const
在线程之间共享像上面那样的变量很好,但后来我突然想到,除非这些变量都在缓存线边界上开始和结束,否则任何相邻的非常量数据都可能导致错误共享,导致任何可能带来的性能损失。
我假设这种担忧是否有效取决于 C 语言和/或编译器如何确定为static
( const
) 变量分配空间的位置;但尽管如此,为了最大限度地减少错误共享的机会,我想最好将所有static
变量声明为thread_local
多线程上下文,即使它们是const
:
你能证实这一点吗?
@MichaelDorgan提到有些平台“与访问线程局部变量相关的额外成本以及可以声明的数量限制”。任何证实可能影响我上述假设的参考资料。
@ JonathanLeffler提到const
变量往往布置在只读内存区域中,这将消除错误共享问题。那么这方面的一个后续问题是:这是否严格依赖于平台,或者是否有更强有力的保证?
c++ - 什么是真正的分享?
在阅读这个问题时,我遇到了“虚假共享”和“真实共享”这两个术语。我读过什么是虚假分享,但我在真正的分享上找不到任何东西。尽管在提到的问题中,该术语被描述为“建设性干扰”,但我仍然不明白它的含义。
c++ - OpenMP 对数组的性能不佳
我有以下问题:我试图在 c++ 中使用 openMP 并行化一个非常简单的 PDE 求解器,但是如果我增加线程数,性能并没有提高。该方程是一个简单的一维对流热方程。由于我在每个时间步都需要解决方案,因此我决定使用 2D 数组
其中每一行包含特定时间步长的离散函数。更新是通过 for 循环完成的
使用值 iBefore 和 iAfter 是因为我基本上将数组视为环形缓冲区,因此 PDE 具有周期性边界条件,并且域被视为环形。无论如何,对 solution[t+1] 的每次更新都需要对 solution[t] 进行一些计算,就像上面代码中显示的那样。我知道可扩展性差的原因很可能是错误共享,因此我将 2D 矩阵转换为 3D 矩阵
这使我可以确保在共享缓存行上不执行任何写操作,因为我可以改变 PAD 的大小。代码发生了一些变化,因为现在每个值都将存储在
而下面的一个在
请注意,所需的内存是使用并行区域外的 new 运算符在堆上分配的。该代码运行良好,但不可扩展。我尝试过不同的时间表,例如静态,动态,自动,...我用它编译
我尝试删除或添加 -march 和 -O3 标志,但没有看到任何改进。我尝试了不同大小的 PAD 和环境变量,如 OMP_PROC_BIND,但没有任何改进。我不知道是什么导致了这一点上的性能损失。这是代码
还有表演
c++ - 避免 SPSC 队列索引的错误共享
让我们想象一个无锁并发 SPSC(单生产者/单消费者)队列。
- 生产者 线程读取
head
,tail
和写入cached_tail
, 。_head
cached_tail
- 消费者 线程读取
head
,tail
和写入cached_head
, 。_tail
cached head
注意,它cached_tail
只能被生产者线程访问,就像cached_head
只能被消费者线程访问一样。它们可以被认为是私有线程局部变量,因此它们是不同步的,因此没有定义为原子的。
队列的数据布局如下:
由于我想避免错误共享,因此我与head
L1tail
缓存行大小对齐。
push
/操作的伪代码实现pop
如下:
在初始化时(此处未列出),所有索引都设置为0
. 函数num_remaining_storage
和num_stored_elements
是const
基于传递的参数和不可变队列容量执行简单计算的函数 - 它们不执行任何原子读取或写入。
现在的问题是:我是否需要对齐cached_tail
以及cached_head
完全避免错误共享任何索引,或者它是可以的。由于cached_tail
生产者是私有的,并且cached_head
是消费者私有的,我认为cached_tail
可以与head
(生产者缓存行)cached_head
在同一缓存行中,就像与tail
(消费者缓存行)在同一缓存行中一样,不会发生错误共享。
我错过了什么吗?