我是新手来构建模块并尝试在TBB中对FFT算法进行编码以获得一些实践经验。在该算法的情况下,我只能并行化最内层的循环。但通过这样做,性能降低到不可接受的程度(超过千倍)。我已经尝试过阵列大小高达2 ^ 20但结果相同。我的代码如下:
for(stage1=0;stage1 < lim;stage1 ++)
{
butterfly_index1 = butterfly_index2;
butterfly_index2 = butterfly_index2 + butterfly_index2;
k = -1*2*PI/butterfly_index2;
k_next = 0.0;
for(stage2 = 0 ; stage2 < butterfly_index1;stage2++)
{
sine=sin(k_next);
cosine = cos(k_next);
k_next = k_next + k;
FFT. sine = &sine;
FFT.cosine = &cosine;
FFT.n2 = &butterfly_index2;
FFT.loop_init = &stage2;
FFT.n1 = &butterfly_index1;
parallel_for(blocked_range<int>(
stage2,SIZE,SIZE/4),FFT,simple_partitioner());
}
}
和parallel_loop的主体是
void operator()(const blocked_range<int> &r)const
{
for(int k = r.begin(); k != r.end(); k++)
{
if(k != *loop_init)
{
if((k - (*loop_init))% (* n2)!= 0)
continue;
}
temp_real = (*cosine) * X[k + *n1].real - (*sine) * X[k + *n1].img;
temp_img = (*sine)* X[k + *n1].real + (*cosine) * X[k + *n1].img;
X[k + *n1].real = X[k].real - temp_real;
X[k + *n1].img = X[k].img - temp_img;
X[k].real = X[k].real + temp_real;
X[k].img = X[k].img + temp_img;
}
}
如果我用普通循环替换它,那么事情是正确的。
答案 0 :(得分:1)
对于非常短的工作负载,由于线程创建的开销,可能会发生巨大的减速。对于数组中的2 ^ 20个元素,我不相信会发生如此巨大的性能下降。
性能下降的另一个重要原因是编译器在TBBfied之后无法优化(特别是矢量化)代码。了解您的编译器是否可以生成矢量化报告,并查找串行和TBB版本之间的差异。
减速的可能来源可能是parallel_for的body类的复制构造函数,因为正在复制很多正文。但是给定的代码在这方面看起来并不可疑:似乎身体包含了一些指针。无论如何,看看它是否是一个问题。
另一个重要开销的常见来源是太细粒度的并行性,即每个包含很少工作的许多任务。但在这里也不是这样,因为在第3个参数中将SIZE / 4粒度化为blocked_range指定每个算法最多调用4次body的operator()()。
我建议不要为初始实验指定simple_partitioner和grainize,而是让TBB动态分配工作。如有必要,您可以稍后进行调整。
答案 1 :(得分:0)
我的代码的问题是随着n2变量的增加工作量的减少。因此,当out循环继续,parallel_for的工作量变为一半,并且在几次迭代之后,它变得太小而不能通过使用TBB来提高性能。因此,解决方案是在内循环的工作负载足够的情况下并行内循环以进行其余迭代时,仅针对迭代并行化内循环。其次,包含条件检查(k!= r.end())的“for”循环标头也会降低性能。解决方案是用本地定义的变量替换r.end(),该变量初始化为r.end()
感谢英特尔软件论坛在解决此问题方面的帮助