首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用openmp优化MSE算法

利用openmp优化MSE算法
EN

Stack Overflow用户
提问于 2013-02-11 09:51:26
回答 2查看 322关注 0票数 1

我想用openMP优化下面的代码

代码语言:javascript
复制
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);
}

}

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-11 10:24:26

我认为你能做的最简单的事情就是把它分成4个线程,然后计算每个线程的UYVY误差。不是让它们分隔值,而是使它们成为数组:

代码语言:javascript
复制
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

因此,我对每个变量进行了简化,并使用了一个循环:

代码语言:javascript
复制
    #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倍的性能提升:

代码语言:javascript
复制
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;double pad7;}sqError4来解决这个问题;现在每个sqErrori.val将在单独的缓存线中,因此没有错误的共享。

票数 2
EN

Stack Overflow用户

发布于 2013-02-11 10:16:42

代码看起来像是在计算均方误差,但是加上了相同的和m。为了让并行性正常工作,你需要消除m的共享,一种方法是预先分配一个数组(我想是宽*高/2)来存储不同的和,或者ms。最后,把所有的和加起来。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14804859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档