我对线程化构建块和尝试在TBB中编码FFT算法是新手,以获得一些实践经验。在这个算法中,我只能并行化最里面的循环。但是通过这样做,性能已经下降到不可接受的程度(超过1000次)。我曾尝试将数组大小设置为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;
}
}如果我用普通循环替换它,那么一切都是正确的。
发布于 2011-04-03 17:36:34
对于非常短的工作负载,由于线程创建的开销,可能会发生巨大的减慢。对于数组中的2^20个元素,我不相信会发生如此巨大的性能下降。
性能下降的另一个重要原因是编译器无法在代码被TBBfied之后对其进行优化(特别是向量化)。了解您的编译器是否可以生成矢量化报告,并查找串行版本和TBB版本之间的差异。
一个可能的减慢来源可能是parallel_for的body类的复制构造函数,因为body被复制了很多次。但是给定的代码在这方面看起来并不可疑:似乎主体包含一些指针。无论如何,看看这是否会成为一个问题。
另一个常见的重要开销来源是太细粒度的并行,即许多任务,每个任务只包含很少的工作。但这里也不是这样,因为blocked_range的第三个参数中的grainsize SIZE/4指定body的运算符()()在每个算法中最多被调用4次。
我建议不要在初始实验中指定simple_partitioner和grainsize,而是让TBB动态分发工作。如果需要,您可以在以后对其进行调整。
发布于 2011-04-04 05:23:59
我的代码的问题是,随着n2变量的增加,工作负载减少了。因此,随着外循环的进行,parallel_for的工作负载将减半,并且在几次迭代之后,它变得太小,无法通过使用TBB来提高性能。因此,解决方案是只在内循环的工作负载足够时才对内循环进行并行化,而对于其余的迭代则对内循环进行序列化。其次,包含条件检查(k != r.end())的"for“循环头也会降低性能。解决方案是用初始化为r.end()的本地定义变量替换r.end()
感谢英特尔软件论坛对解决此问题的帮助。
https://stackoverflow.com/questions/5521954
复制相似问题