并行计算内存访问瓶颈
Parallel computing memory access bottleneck
以下算法在我的程序中迭代运行。运行它,如果没有下面指出的两条线,所需的时间是没有的1.5倍。这对我来说是非常令人惊讶的。然而,更糟糕的是,用运行这两行将完成度提高到没有它们运行的4.4X(6.6X没有运行整个算法(。此外,它还导致我的程序无法扩展到8个内核以上。事实上,当在单核上运行时,这两行只会将时间增加到1.7倍,考虑到它们的作用,这仍然太高了。我已经排除了这与程序中其他地方修改数据的影响有关。
所以我想知道是什么原因造成的。也许和缓存有关?
void NetClass::Age_Increment(vector <synapse> & synapses, int k)
{
int size = synapses.size();
int target = -1;
if(k > -1)
{
for(int q=0, x=0 ; q < size; q++)
{
if(synapses[q].active)
synapses[q].age++;
else
{
if(x==k)target=q;
x++;
}
}
/////////////////////////////////////Causing Bottleneck/////////////
synapses[target].active = true;
synapses[target].weight = .04 + (float (rand_r(seedp) % 17) / 100);
////////////////////////////////////////////////////////////////////
}
else
{
for(int q=0 ; q < size; q++)
if(synapses[q].active)
synapses[q].age++;
}
}
更新:将两个问题行更改为:
bool x = true;
float y = .04 + (float (rand_r(seedp) % 17) / 100);
删除问题。暗示这可能与内存访问有关?
每个线程修改内存,所有其他读取读取:
for(int q=0, x=0 ; q < size; q++)
if(synapses[q].active) ... // ALL threads read EVERY synapse.active
...
synapses[target].active = true; // EVERY thread writes at leas one synapse.active
这种从不同线程对同一地址的读取和写入会导致大量缓存失效,这将导致您所描述的症状。解决方案是避免在循环内写入,而将写入移动到局部变量的事实再次证明了问题是缓存无效。请注意,即使您不编写正在读取的sane字段(active
(,您也可能会由于错误共享而看到相同的症状,因为我怀疑active
、age
和weight
共享一条缓存线。
有关更多详细信息,请参阅CPU缓存和为什么关心
最后要注意的是,对active
和weight
的赋值,更不用说age++
的增量了,看起来都非常不安全。这种更新的互锁操作或锁/互斥保护是强制性的。
试着重新引入这两行,但不使用rand_r
,只是为了看看是否会出现同样的性能恶化。如果你不这样做,这可能是rand_r
在内部序列化的迹象(例如通过互斥(,所以你需要找到一种更并发地生成随机数的方法。
另一个潜在的关注领域是虚假分享(如果你有时间,可以看看赫伯·萨特关于这个主题的视频和幻灯片等(。从本质上讲,如果您的线程碰巧修改了不同的内存位置,这些位置足够近,以至于落入同一个缓存行,那么缓存一致性硬件可能会有效地串行化内存访问并破坏可扩展性。使这一点难以诊断的是,这些内存位置在逻辑上可能是独立的,而且在运行时它们可能不会靠得很近。如果您怀疑存在错误共享,请尝试添加一些填充以将这些内存位置分隔开。
如果size
相对较小,那么对PRNG、整数除法、浮点除法和加法的调用会大大增加程序执行量,这一点也不奇怪。您正在做相当多的工作,因此增加运行时间似乎是合乎逻辑的。此外,由于您告诉编译器按照float
而不是double
进行计算,这可能会在某些系统上进一步增加时间(其中本机浮点是双倍的(。你考虑过int
s的不动点表示吗?
我不能说为什么它会随着内核的增加而扩展得更糟,除非你超过了操作系统为你的程序提供的内核数量(或者如果你的系统的rand_r
是使用锁定或线程特定的数据来实现的,以保持额外的状态(。
还要注意,在将target
用作数组索引之前,您永远不会检查它是否有效,如果它退出了仍设置为-1的for
循环,则程序的所有赌注都将取消。
- 特里树.无法访问内存
- 如何使用 C/C++ 访问内存的内容?
- 指针可以用于访问内存中的任何任意区域吗?
- 分段错误:无法访问内存
- SIGABRT 在线程中访问内存时
- 访问内存以内联循环访问数组
- 如何从C或C 语言级别安全访问内存映射的硬件寄存器
- 在释放了所有作用域内指针之后仍然可访问内存
- 有什么快速访问内存的技巧吗
- CUDA非法访问内存
- C++ 访问内存冲突
- 悬空指针仍在访问内存值
- 当我尝试从结构列表中访问内存时出现错误:" Program received signal SIGSEGV, Segmentation fault."
- 如何访问内存映射的 USB 主控制器寄存器
- 访问内存时出现奇怪的崩溃
- 如何在C++读取块后访问内存中的文件数据
- 使用共享库时仍可访问内存
- 从 C++ 结构中包含的指针数组动态分配和访问内存
- Win32应用程序,可无限制地访问内存
- 强制两个线程直接访问内存中的全局变量