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:为什么这个应用程序有时会扩展?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)