结合openmp和sse指令

时间:2012-05-24 06:47:40

标签: c openmp sse

原始代码看起来像

for(i=0;i<20;i++){
    if(){
        do(); 
    }
    else{

        num2 = _mm_set_pd(Phasor.imaginary, Phasor.real);

        for(int k=0; k<SamplesIneachPeriodCeil[iterationIndex]; k++) 
        {
            /*SamplesIneachPeriodCeil[iterationIndex] is in range of 175000*/

            num1 = _mm_loaddup_pd(&OutSymbol[k].real);
            num3 = _mm_mul_pd(num2, num1);
            num1 = _mm_loaddup_pd(&OutSymbol[k].imaginary);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num4 = _mm_mul_pd(num2, num1);
            num3 = _mm_addsub_pd(num3, num4);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num5 = _mm_set_pd(InSymbolInt8[k],InSymbolInt8[k] );
            num6 = _mm_mul_pd(num3, num5);
            num7 = _mm_set_pd(Out[k].imaginary,Out[k].real);
            num8 = _mm_add_pd(num7,num6);
            _mm_storeu_pd((double *)&Out[k], num8);

        }
        Out = Out + SamplesIneachPeriodCeil[iterationIndex];
    }
}

这段代码给了我15milsec的速度

当我修改代码以将openmp包含为

注意::这里我只包括其他部分

else{
    int size = SamplesIneachPeriodCeil[iterationIndex];

#pragma omp parallel num_threads(2) shared(size)
    {
        int start,end,tindex,tno,no_of_iteration;
        tindex = omp_get_thread_num();
        tno = omp_get_num_threads();
        start = tindex * size / tno;
        end = (1+ tindex)* size / tno ;
        num2 = _mm_set_pd(Phasor.imaginary, Phasor.real);
        int k;
        for(k = start ; k < end; k++){


            num1 = _mm_loaddup_pd(&OutSymbol[k].real);
            num3 = _mm_mul_pd(num2, num1);
            num1 = _mm_loaddup_pd(&OutSymbol[k].imaginary);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num4 = _mm_mul_pd(num2, num1);
            num3 = _mm_addsub_pd(num3, num4);
            //_mm_storeu_pd((double *)&newSymbol, num3);
            num2 = _mm_shuffle_pd(num2, num2, 1);
            num5 = _mm_set_pd(InSymbolInt8[k],InSymbolInt8[k] );
            num6 = _mm_mul_pd(num3, num5);
            num7 = _mm_set_pd(Out[k].imaginary,Out[k].real);
            num8 = _mm_add_pd(num7,num6);
            _mm_storeu_pd((double *)&Out[k], num8);


        }
    }
    Out = Out + size;
}

此代码显示的速度是30万毫秒

所以我想知道我在这里做错了什么。

2 个答案:

答案 0 :(得分:2)

你没有做任何事情来分配两个线程之间的循环执行。您只是创建一个具有两个线程的并行区域,这些线程执行完全相同的代码。您可能想要做的是将并行区域移动到仅包含for循环并使用工作共享构造:

int k;
#pragma omp parallel for num_threads(2) ...
for(k = start ; k < end; k++){
   ...
}

<击>

感谢都铎的纠正。您的代码已正确并行化,但在循环内部有一个并行区域。进入和退出并行区域与一些开销相关联。通常这被描述为“fork / join model”,其中在进入该区域时创建一组线程,然后在退出时将所有线程连接到master。大多数OpenMP运行时使用各种线程池技术来减少开销,但它仍然存在。

你的循环运行15毫秒。与OpenMP开销相比,这已经足够快,因此开销变得可见。考虑在外环上移动并行区域,开销应减少最多20倍(取决于else分支的使用频率),但您可能仍然看不到计算时间的改善

并行化仅适用于问题足够大的程序,因此与计算时间相比,通信或同步开销可以忽略不计或至少很小。

答案 1 :(得分:0)

您应该在外部循环之外(i之外)开始并行区域,并使用k将for循环并行化omp for。循环中使用的所有变量(num1num2 ...)最好只在其中声明,以便它们自动private(实际上,大多数变量可以重复使用,但是编译器应该发现我们无论如何。)