在做一些关于无锁/无等待算法的研究时,我偶然发现了错误的共享问题.挖掘更多的东西让我得到了Folly的源代码(Facebook的C++库),更具体地说是这个头文件和FOLLY_ALIGN_TO_AVOID_FALSE_SHARING宏的定义(目前在第130行).乍一看最令我惊讶的是价值:128(即:而不是64)......
/// An attribute that will cause a variable or field to be aligned so that
/// it doesn't have false sharing with anything at a smaller memory address.
#define FOLLY_ALIGN_TO_AVOID_FALSE_SHARING __attribute__((__aligned__(128)))
Run Code Online (Sandbox Code Playgroud)
AFAIK,现代CPU上的缓存块长度为64字节,实际上,到目前为止,我发现的每一项资源,包括英特尔的这篇文章,都讨论了64字节对齐和填充,以帮助解决错误共享问题.
尽管如此,Facebook的人们在需要时将他们的班级成员对齐并填充为128字节.然后我在上面FOLLY_ALIGN_TO_AVOID_FALSE_SHARING的定义中找到了解释的开头:
enum {
/// Memory locations on the same cache line are subject to false
/// sharing, which is very bad for performance. Microbenchmarks
/// indicate that pairs of cache lines also see …Run Code Online (Sandbox Code Playgroud) 对于我的学士论文,我必须评估多核系统的常见问题.
在一些书中,我读到了关于虚假共享的内容以及其他有关缓存行乒乓的书籍.具体问题听起来很熟悉,这些问题是否同样存在,但还有其他名称?有人可以给我详细讨论这些主题的书名吗?(我已经有Darry Glove,Tanenbaum的文献......)
caching multicore processor computer-architecture false-sharing
我发现了一条来自 的评论crossbeam。
从 Intel 的 Sandy Bridge 开始,空间预取器现在一次提取成对的 64 字节缓存线,因此我们必须对齐到 128 字节而不是 64。
资料来源:
我在英特尔的手册中没有找到这样的说法。但直到最新的提交,folly仍然使用 128 字节填充,这让我很有说服力。所以我开始编写代码来看看是否可以观察到这种行为。这是我的代码。
#include <thread>
int counter[1024]{};
void update(int idx) {
for (int j = 0; j < 100000000; j++) ++counter[idx];
}
int main() {
std::thread t1(update, 0);
std::thread t2(update, 1);
std::thread t3(update, 2);
std::thread t4(update, 3);
t1.join();
t2.join();
t3.join();
t4.join();
}
Run Code Online (Sandbox Code Playgroud)
我的CPU是锐龙3700X。当索引为0、1、2、3时,大约需要 1.2 秒才能完成。当索引为0, 16, 32,时 …
最近,我回答了一个关于优化可能的可并行化方法来生成任意基数的每个排列的问题.我发布了类似于Parallelized,糟糕的实现代码块列表的答案,有人几乎立即指出了这一点:
这几乎可以保证为您提供错误的共享,并且可能会慢很多倍.(信用gjvdkamp)
他们是对的,死亡很慢.也就是说,我研究了这个主题,并找到了一些有趣的材料和建议(仅存档的MSDN杂志,.NET Matters:False Sharing)来对抗它.如果我理解正确,当线程访问连续的内存(例如,可能支持该数组的数组ConcurrentStack)时,可能会发生错误共享.
对于横向规则下面的代码,a Bytes是:
struct Bytes {
public byte A; public byte B; public byte C; public byte D;
public byte E; public byte F; public byte G; public byte H;
}
Run Code Online (Sandbox Code Playgroud)
对于我自己的测试,我想获得这个运行的并行版本并且真正更快,所以我创建了一个基于原始代码的简单示例.6因为limits[0]是我的一个懒惰的选择-我的电脑有6个核心.
单线程块 平均运行时间:10s0059ms
var data = new List<Bytes>();
var limits = new byte[] { 6, 16, 16, 16, 32, 8, 8, 8 };
for (byte a = 0; …Run Code Online (Sandbox Code Playgroud) 编辑:ST不允许为新手发布两个以上的链接.很抱歉找不到引用.
我正在尝试减少C应用程序中的锁定开销,其中检测全局状态的变化与性能相关.虽然我最近在这个主题上已经阅读了很多(例如H. Sutter的很多内容,还有更多)我对我的实现没有信心.我想结合使用类似CAS的操作和DCL来检查Cache-Line Aligned全局变量,从而避免错误共享,从多个线程之间共享的数据中更新线程本地数据.我缺乏信心主要是由于
我的问题:
Type-Attributes文档说明:
此属性指定指定类型的变量的最小对齐(以字节为单位).例如,声明:
(请参阅Type-Attributes文档以进行声明)
强制编译器确保(尽可能)每个变量的类型是
struct S或more_aligned_int将被分配并至少在8-byte边界上对齐.在SPARC上,将所有类型的变量struct S对齐到8-byte边界允许编译器在将struct S类型的一个变量复制到另一个变量时使用ldd和std(双字加载和存储)指令,从而提高运行时效率.
这是否意味着开始struct S或more_aligned_int将始终与8-byte边界对齐?这并不意味着数据将被填充以正好使用64个字节,对吗?
假设1.的确是每个实例struct cache_line_aligned(参见下面的代码示例1)在64-byte边界上对齐并且只使用一个缓存行(假设缓存行的64 bytes长度)
使用typedef该类型的声明不改变的语义__attribute__ ((aligned (64)))(见代码实施例2下面)
aligned_malloc如果使用struct声明struct,则在实例化struct时不需要使用__attribute__ ...
// Example 1
struct cache_line_aligned {
int version;
char …Run Code Online (Sandbox Code Playgroud) 我已经开始学习如何使用OpenMP作为大学课程的一部分.作为实验练习,我们获得了一个需要并行化的系列程序.
我们首先了解了False Sharing的危险性,尤其是在为循环并行更新数组时.
但是,我发现很难将以下代码片段转换为可并行执行的任务,而不会导致错误共享:
int ii,kk;
double *uk = malloc(sizeof(double) * NX);
double *ukp1 = malloc(sizeof(double) * NX);
double *temp;
double dx = 1.0/(double)NX;
double dt = 0.5*dx*dx;
// Initialise both arrays with values
init(uk, ukp1);
for(kk=0; kk<NSTEPS; kk++) {
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] = uk[ii] + (dt/(dx*dx))*(uk[ii+1]-2*uk[ii]+uk[ii-1]);
}
temp = ukp1;
ukp1 = uk;
uk = temp;
printValues(uk,kk);
}
Run Code Online (Sandbox Code Playgroud)
我的第一反应是尝试分享ukp1:
for(kk=0; kk<NSTEPS; kk++) {
#pragma omp parallel for shared(ukp1)
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] …Run Code Online (Sandbox Code Playgroud) 对于我的学士论文,我必须分析虚假共享对多核系统的影响.因此,我在维基百科上看到了不同的缓存一致性协议类型,英特尔已经开发出MESIF缓存一致性协议,但英特尔也没有使用此信息.
查看手册英特尔®64和IA-32架构开发人员手册:Vol.3A我找不到任何关于MESIF但是MESI协议的内容.所以问题是,英特尔不使用自己的缓存一致性协议.或者我在错误的文件中搜索它.
multithreading caching multicore state-machine false-sharing
我有以下任务来演示虚假共享并编写了一个简单的程序:
#include <sys/times.h>
#include <time.h>
#include <stdio.h>
#include <pthread.h>
long long int tmsBegin1,tmsEnd1,tmsBegin2,tmsEnd2,tmsBegin3,tmsEnd3;
int array[100];
void *heavy_loop(void *param) {
int index = *((int*)param);
int i;
for (i = 0; i < 100000000; i++)
array[index]+=3;
}
int main(int argc, char *argv[]) {
int first_elem = 0;
int bad_elem = 1;
int good_elem = 32;
long long time1;
long long time2;
long long time3;
pthread_t thread_1;
pthread_t thread_2;
tmsBegin3 = clock();
heavy_loop((void*)&first_elem);
heavy_loop((void*)&bad_elem);
tmsEnd3 = clock();
tmsBegin1 = clock();
pthread_create(&thread_1, NULL, heavy_loop, …Run Code Online (Sandbox Code Playgroud) 今天我和我的教授在并行编程课上有了不同的理解,关于什么是"虚假共享".我的教授所说的没什么意义,所以我立即指出了.她认为"虚假分享"会导致程序结果出错.
我说,"错误共享"发生在将不同的内存地址分配给同一个缓存行时,将数据写入其中一个会导致另一个被踢出缓存.如果处理器在两个错误共享地址之间写入转向和转向,则它们都不能停留在高速缓存上,因此所有操作都将导致DRAM的访问.
到目前为止,这是我的意见.事实上,我不确定我说的是什么......如果我有误解,请指出.
所以有一些问题.假设缓存为64字节对齐,4路组关联.
parallel-processing optimization caching computer-architecture false-sharing