我试图将矩阵处理程序并行化。在使用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线程XeonE5-2680上运行这个线程的,除了我的实验之外,它不会在任何给定的时间执行任何其他的东西。现在我的问题是,我注意到当我更改环境变量CILK_NWORKERS并尝试2、4、8、16等值时,执行test_function所需的时间会发生很大的变化。特别是,设置的CILK_NWORKERS越高(2之后),函数的速度就越慢。这似乎与我的直觉相反,因为我希望可用的线程数不会改变cilk_spawn的操作。如果有两个线程可用,那么函数highPrep将在另一个线程上执行。任何超过两个线程,我预计将保持空闲。
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;
}
}在这背后一定有一个合理的解释,对于这样一个程序来说,期望不同的执行时间合理吗?
发布于 2014-09-24 15:47:08
澄清: Cilk做的是“连续窃取”,而不是“偷子”,所以highPrep总是运行在与调用者相同的硬件线程上。“其余的代码”可能会在另一个线程上运行。有关更全面的解释,请参见本底漆。
至于减速,它可能是一个工件,它的实现倾向于高度并行性,可以消耗所有线程。额外的线程正在寻找工作,在此过程中,占用一些内存带宽,而对于超线程处理器则消耗掉一些核心周期。Linux的“完全公平调度器”在这方面给了我们一些悲伤,因为睡眠(0)不再放弃时间。另外,额外的线程也可能导致操作系统将软件线程映射到机器上的效率较低。
问题的根源在于一个棘手的权衡:盗贼的侵略性使他们能够在工作出现时更快地开始工作,但如果没有工作,他们也会不必要地消耗资源。在没有工作的情况下让窃贼睡觉可以节省资源,但是会增加大量的开销,因为现在一个产卵线程必须检查是否有休眠线程被唤醒。TBB支付这一开销,但对TBB来说并不多,因为TBB的种子开销无论如何要高得多。当前的Cilk实现确实支付了此税:它只在顺序执行期间睡眠工作人员。
我能给出的最好的(但不完美的)建议是找到更多的并行性,这样就不会让工作线程长时间徘徊并造成麻烦。
https://stackoverflow.com/questions/26003918
复制相似问题