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

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

概述我正试图在英特尔®酷睿™i5-6500 CPU @ 3.20GHz×4上使用OpenMP加速OpenCV SIFT算法.您可以在 sift.cpp中找到代码. 最昂贵的部分是描述符计算,特别是: static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints, 我正试图在英特尔®酷睿™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%以上,如下图所示:

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

我认为这是第一张图像中的变化是正常的,因为我们多次执行相同的短程序,这比一个大程序更不稳定.我不明白为什么我们永远不会达到超过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或指令),是否由于内存带宽或错误共享问题而存在任何限制,以及许多其他问题.

总结

以上是内存溢出为你收集整理的c – OpenMP:为什么这个应用程序有时会扩展?全部内容,希望文章能够帮你解决c – OpenMP:为什么这个应用程序有时会扩展?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1224842.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存