使用openmp优化MSE算法

时间:2013-02-11 01:51:26

标签: c algorithm optimization openmp mse

我想使用openMP优化以下代码

double val;
double m_y = 0.0f;
double m_u = 0.0f;
double m_v = 0.0f;

#define _MSE(m, t) \
val = refData[t] - calData[t];  \
m += val*val; 

#pragma omp parallel 
 {
 #pragma omp for
for( i=0; i<(width*height)/2; i++ ) {  //yuv422: 2 pixels at a time
    _MSE(m_u, 0); 
    _MSE(m_y, 1); 
    _MSE(m_v, 2); 
    _MSE(m_y, 3); 

  #pragma omp reduction(+:refData) reduction(+:calData)
    refData += 4;
    calData += 4;
 // int id = omp_get_thread_num();
 //printf("Thread %d performed %d iterations of the loop\n",id ,i);
}

}

任何建议欢迎优化上面的代码目前我有错误的输出。

2 个答案:

答案 0 :(得分:2)

我认为你能做的最简单的事情是允许它分成4个线程,并计算每个线程中的UYVY错误。而不是使它们成为单独的值,使它们成为一个数组:

double sqError[4] = {0};
const int numBytes = width * height * 2;

#pragma omp parallel for
for( int elem = 0; elem < 4; elem++ ) {
    for( int i = elem; i < numBytes; i += 4 ) {
        int val = refData[i] - calData[i];
        sqError[elem] += (double)(val*val);
    }
}

这样,每个线程只在一件事上运行,没有争用。

也许这不是OMP最先进的用途,但你应该看到加速。


在您对性能影响发表评论后,我做了一些实验,发现性能确实更差。我怀疑这可能是由于缓存未命中。

你说:

  这次使用openMP达到性能:时间:0.040637连续   时间:0.018670

所以我使用每个变量的减少并使用单个循环重新编写它:

    #pragma omp parallel for reduction(+:e0) reduction(+:e1) reduction(+:e2) reduction(+:e3)
    for( int i = 0; i < numBytes; i += 4 ) {
        int val = refData[i] - calData[i];
        e0 += (double)(val*val);
        val = refData[i+1] - calData[i+1];
        e1 += (double)(val*val);
        val = refData[i+2] - calData[i+2];
        e2 += (double)(val*val);
        val = refData[i+3] - calData[i+3];
        e3 += (double)(val*val);
    }

我的测试用例在4核机器上,我观察到的改善不到4倍:

serial:             2025 ms
omp with 2 loops:   6850 ms
omp with reduction: 455  ms

[编辑] 关于为什么第一段代码的表现比非并行版本差, Hristo Iliev 说:

  

你的第一段代码是虚假分享的一个可怕例子   在多线程代码中。因为sqError只有4个8字节的元素   每个,它适合单个缓存行(即使在半缓存行中   现代x86 CPU)。有4个线程不断写入邻居   元素,这将产生大量的核心间缓存   由于错误共享导致的失效。人们可以通过使用来解决这个问题   而是像这样的结构_error {double val;双   垫[7]; } sqError [4];现在每个sqError [i] .val都将单独存在   缓存行,因此没有虚假共享。

答案 1 :(得分:0)

代码看起来像是在计算MSE,但加上相同的总和m。为了使并行工作正常,你需要消除m的共享,一种方法是预先分配一个数组(我想象的宽度*高度/ 2)只是为了存储不同的总和,或m s。最后,将最后的所有金额加起来。

另外,测试一下这实际上更快!