加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – OpenMP:为什么这个应用程序有时会扩展?

发布时间:2020-12-16 06:52:09 所属栏目:百科 来源:网络整理
导读:我正试图在英特尔?酷睿?i5-6500 CPU @ 3.20GHz×4上使用OpenMP加速OpenCV SIFT算法.您可以在 sift.cpp 中找到代码. 最昂贵的部分是描述符计算,特别是: static void calcDescriptors(const std::vectorMat gpyr,const std::vectorKeyPoint keypoints,Mat des
我正试图在英特尔?酷睿?i5-6500 CPU @ 3.20GHz×4上使用OpenMP加速OpenCV SIFT算法.您可以在 sift.cpp中找到代码.

最昂贵的部分是描述符计算,特别是:

static void calcDescriptors(const std::vector<Mat>& gpyr,const std::vector<KeyPoint>& keypoints,Mat& descriptors,int nOctaveLayers,int firstOctave )
{
    int d = SIFT_DESCR_WIDTH,n = SIFT_DESCR_HIST_BINS;
    for( size_t i = 0; i < keypoints.size(); i++ )
    {
        KeyPoint kpt = keypoints[i];
        int octave,layer;
        float scale;
        unpackOctave(kpt,octave,layer,scale);
        CV_Assert(octave >= firstOctave && layer <= nOctaveLayers+2);
        float size=kpt.size*scale;
        Point2f ptf(kpt.pt.x*scale,kpt.pt.y*scale);
        const Mat& img = gpyr[(octave - firstOctave)*(nOctaveLayers + 3) + layer];

        float angle = 360.f - kpt.angle;
        if(std::abs(angle - 360.f) < FLT_EPSILON)
            angle = 0.f;
        calcSIFTDescriptor(img,ptf,angle,size*0.5f,d,n,descriptors.ptr<float>((int)i));
    }
}

此函数的串行版本平均需要52毫秒.

这个有很高的粒度:它执行了604次(这是keypoints.size()). for中的主要耗时组件是calcSIFTDescriptor,它占用大部分周期时间计算,平均需要105 us,但经常需要200us或50us.

但是,我们非常幸运:每个循环之间没有依赖关系,所以我们可以添加:

#pragma omp parallel for schedule(dynamic,8)

并获得初始加速.引入动态选项,因为它似乎比静态(不知道为什么)提供更好的性能.

问题是它确实不稳定而且不能扩展.这是在并行模式下计算函数所需的时间:

25ms 43ms 32ms 15ms 27ms 53ms 21ms 24ms

正如您所看到的那样,只有达到四核系统的最佳加速(15ms).大多数情况下,我们达到最佳加速的一半:四核系统中的25ms只是理论最佳加速的一半.

为什么会这样?我们该怎样改进这个?

更新:
正如评论中所建议的那样,我试图使用更大的数据集.使用巨大的图像,串行版本需要13574ms来计算描述符,而并行版本3704ms具有相同的四核之前.好多了:即使它不是最好的理论结果,它实际上也可以很好地扩展.但实际上问题仍然存在,因为之前的结果是从典型的图像中获得的.

更新1:正如评论所建议的那样,我尝试在“热模式”执行之间没有任何间隔进行基准测试(有关更多详细信息,请参阅注释).更频繁地实现更好的结果,但仍然存在许多变化.这是在热模式下100次运行的时间(以毫秒为单位):

43 42 14 26 14 43 13 26 15 51 15 20 14 40 34 15 15 31 15 22 14 21 15 15 14 27 14 16 14 22 14 22 15 15 14 43 16 16 15 28 14 24 14 36 15 32 13 21 14 23 14 15 13 26 15 35 13 32 14 36 14 34 15 40 28 14 14 15 15 35 15 22 14 17 15 23 14 24 17 16 14 35 14 29 14 25 14 32 14 28 14 34 14 30 22 14 15 24 14 31

你可以看到很多好的结果(14毫秒,15毫秒),但也有很多可怕的结果(> 40毫秒).平均值为22ms请注意,顺序模式中最多没有4ms的变化:

52 54 52 52 51 52 52 53 53 52 53 51 52 53 53 54 53 53 53 53 54 53 54 54 53 53 53 52 53 52 51 52 52 53 54 54 54 55 55 55 54 54 54 53 53 52 52 52 51 52 54 53 54 54 54 55 54 54 52 55 52 52 52 51 52 51 52 52 51 51 52 52 53 53 53 53 55 54 55 54 54 54 55 52 52 52 51 51 52 51 51 51 52 53 53 54 53 54 53 55

更新2:

我注意到“热模式”基准测试期间的每个CPU利用率都非常随机,而且从未达到80%以上,如下图所示:

enter image description here

相反,下图显示了我通过make -j4编译OpenCV时的CPU利用率.你可以看到它更稳定,几乎100%使用它:

enter image description here

我认为这是第一张图像中的变化是正常的,因为我们多次执行相同的短程序,这比一个大程序更不稳定.我不明白为什么我们永远不会达到超过80%的CPU利用率.

解决方法

我强烈建议你使用一些性能工具,如Paraver( http://www.bsc.es/paraver),TAU( http://www.cs.uoregon.edu/research/tau/home.php)Vampir( https://tu-dresden.de/die_tu_dresden/zentrale_einrichtungen/zih/forschung/projekte/vampir)甚至英特尔的Vtune( https://software.intel.com/en-us/intel-vtune-amplifier-xe).

这些工具将帮助您了解线程在哪些周期中花费.通过它们,您可以找到应用程序是否不平衡(通过IPC或指令),是否由于内存带宽或错误共享问题而存在任何限制,以及许多其他问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读