【问题标题】:Why does CILK_NWORKERS affect program with only one cilk_spawn?为什么 CILK_NWORKERS 会影响只有一个 cilk_spawn 的程序?
【发布时间】:2014-09-23 20:11:45
【问题描述】:

我正在尝试并行化矩阵处理程序。使用 OpenMP 后,我决定还检查 CilkPlus,我注意到以下内容:

在我的 C 代码中,我只在一个部分应用并行性,即:

//(test_function declarations)

cilk_spawn highPrep(d, x, half);

d = temp_0;
r = malloc(sizeof(int)*(half));
temp_1 = r;
x = x_alloc + F_EXTPAD;
lowPrep(r, d, x, half);

cilk_sync;

//test_function return

根据我目前阅读的文档,cilk_spawn 预计-也许-(CilkPlus 不强制并行)采用 highPrep() 函数并在不同的硬件线程中执行它(如果可用),然后继续其余代码的执行,包括函数lowPrep()。然后线程应该在 cilk_sync 同步,然后继续执行其余代码。

我在 8 核/16 线程 Xeon E5-2680 上运行它,除了我的实验之外,它不会在任何给定时间执行任何其他操作。我现在的问题是,我注意到当我更改环境变量 CILK_NWORKERS 并尝试诸如 2、4、8、16 之类的值时,需要执行 test_function 的时间会发生很大变化。特别是,CILK_NWORKERS 设置得越高(在 2 之后),函数变得越慢。这对我来说似乎违反直觉,因为我希望 可用 线程数不会改变 cilk_spawn 的操作。我希望如果有 2 个线程可用,那么函数 highPrep 将在另一个线程上执行。超过 2 个线程我希望保持空闲。

highPrep 和 lowPrep 函数是:

void lowPrep(int *dest, int *src1, int *src2, int size)
{
   double temp;
   int i;
   for(i = 0; i < size; i++)
   {
      temp = -.25 * (src1[i] + src1[i + 1]) + .5;
      if (temp > 0)
         temp = (int)temp;
      else
      {
          if (temp != (int)temp)
              temp = (int)(temp - 1);
      }
      dest[i] = src2[2*i] - (int)(temp);
   }
}

void highPrep(int *dest, int *src, int size)
{
   double temp;
   int i;
   for(i=0; i < size + 1; i++)
   {
      temp = (-1.0/16 * (src[-4 + 2*i] + src[2 + 2*i]) + 9.0/16 * (src[-2 + 2*i] + src[0 + 2*i]) + 0.5);
      if (temp > 0)
           temp = (int)temp;
      else
      {
         if (temp != (int)temp)
              temp = (int)(temp - 1);
      }
      dest[i] = src[-1 + 2*i] - (int)temp;
    }
}

这背后一定有一个合理的解释,这样的程序预期不同的执行时间是否合理?

【问题讨论】:

    标签: c multithreading parallel-processing cilk cilk-plus


    【解决方案1】:

    澄清:Cilk 会“继续窃取”,而不是“窃取孩子”,因此 highPrep 始终与其调用者在同一硬件线程上运行。它是可能最终在不同线程上运行的“其余代码”。请参阅this primer 以获得更完整的解释。

    至于减速,这可能是实现偏向于可以消耗所有线程的高度并行性的产物。额外的线程正在寻找工作,在此过程中会占用一些内存带宽,而超线程处理器会占用一些核心周期。 Linux“完全公平调度器”在这方面给了我们一些遗憾,因为 sleep(0) 不再放弃时间片。额外的线程也可能导致操作系统将软件线程映射到机器上的效率降低。

    问题的根源在于一个棘手的权衡:积极行动的窃贼可以让他们在工作出现时更快地完成工作,但如果没有工作可用,也会导致他们不必要地消耗资源。在没有可用工作时让窃贼进入睡眠状态可以节省资源,但会增加大量的生成开销,因为现在生成线程必须检查是否有要唤醒的睡眠线程。 TBB 支付了这个开销,但对于 TBB 来说并不多,因为无论如何 TBB 的生成开销要高得多。当前的 Cilk 实现确实支付了这个税:它只在顺序执行期间使工作人员休眠。

    我能给出的最好(但不完美)的建议是找到更多的并行性,这样就不会有工作线程长时间徘徊并造成麻烦。

    【讨论】:

    猜你喜欢
    • 2021-10-18
    • 1970-01-01
    • 2020-06-23
    • 2022-01-21
    • 2020-10-09
    • 2018-11-24
    • 1970-01-01
    • 2013-05-29
    • 2012-05-11
    相关资源
    最近更新 更多