游戏"Life"中发布和调试版本之间的加速比例奇怪

Strange ratio in speedup between release and debug builds in game "Life"

本文关键字:之间 加速比 版本 调试 Life 游戏      更新时间:2023-10-16

我与四面邻居一起写了经典游戏"生活"。当我在 debug 中运行它时,它说:

  • 连续版本:4.2S
  • 并行版本:1.5S

okey,很好。但是,如果我在版本中运行,它说:

  • 连续版本:0.46S
  • 并行版本: 1.23S

为什么?我用4个内核在计算机上运行它。我在并行部分中运行4个线程。答案是正确的。但是Somethere是泄漏的,我不知道那个地方。有人可以帮我吗?


我尝试在Visual Studio 2008和2012中运行它。结果是相同的。OMP已在项目设置中启用。

要重复我的问题,您可以找到定义的常数PARALLEL并将其设置为1或0,以相应地启用和禁用OMP。答案将在out.txt中(out.txt-正确的答案示例)。输入必须在in.txt中(我的输入 - in.txt)。有一些俄罗斯符号,您不需要理解它们,但是in.txt中的第一个数字是指在平行部分中运行的线程数(示例中是4)。

主要部分放置在StartSimulation功能中。如果运行该程序,您将在控制台中看到一些带有运行时间的俄罗斯文字。

程序代码足够大,所以我将其添加到文件托管-Main.cpp(L2为我表示"实验2")

有关StartSimulation功能的一些评论。我将用细胞切成小矩形的2D表面。它是由AdjustKernelsParameters函数完成的。

我没有发现比率那么奇怪。拥有多个线程合作是一项复杂的业务,并具有开销。

需要序列化对共享内存的访问,这通常涉及某种形式的锁定机制和线程之间必须等待锁定锁定的线程之间的争夺。这种共享变量需要在处理器内核之间同步,这可以带来重大放缓。同样,编译器需要将这些关键领域视为"序列点"。

所有这些都降低了处理器硬件中的每个线程优化的范围和每个线程与共享变量一起工作时的编译器。

在这种情况下,并行化的开销似乎超过了单线外壳的优化可能性。

如果每个线程在访问共享变量之前需要独立进行更多的工作,那么这些间接费用将不那么重要。

您正在使用guided循环时间表。考虑到您正在处理一个常规问题,这是一个非常糟糕的选择,如果将域简单地分为相等大小的块,则每个任务都可以轻松地完成与其他任何任务完全相同的工作。

schedule(static)替换schedule(guided)。还可以通过livingCount减少总和,而不是使用锁定增量:

#if PARALLEL == 1
#pragma omp parallel for schedule(static) num_threads(kernelsCount) 
                         reduction(+:livingCount)
#endif
for (int offsetI = 0; offsetI < n; offsetI += kernelPartSizeN)
{
  for (int offsetJ = 0; offsetJ < m; offsetJ += kernelPartSizeM)
  {
    int boundsN = min(kernelPartSizeN, n - offsetI), 
        boundsM = min(kernelPartSizeM, m - offsetJ);
    for (int kernelOffsetI = 0; kernelOffsetI < boundsN; ++kernelOffsetI)
    {
      for (int kernelOffsetJ = 0; kernelOffsetJ < boundsM; ++kernelOffsetJ)
      {
        if(BirthCell(offsetI + kernelOffsetI, offsetJ + kernelOffsetJ))
        {
          ++livingCount;
        }
      }
    }
  }
}