写在前面
Orb特征的原理部分可以搜到很多讲解内容,这里就不赘述了,直接记录如何通过openmp对orb特征提取进行加速。Orb特征提取参考的orbslam2的代码实现,作者对提取过程加了很多包装,包括构建四叉树分散特征点等。加速代码在这个地方。
https://github.com/BlackApple-LMZ/orb_extractor_with_openmp
加速首先要分析从代码实现角度来讲哪个地方可以并行加速;然后考虑这个地方的时间消耗占比,如果占比很低,用openmp加速反而会变慢,适得其反;最后就是怎么加速,考虑用openmp实现的细节:是否用临界区,是否原子操作,是否动态调度等等。
并行加速分析
可并行化环节分析:
- 计算图像金字塔 ComputePyramid
构建了8层的图像金字塔,然后存储。对比情况如下:
无omp | 28 | 28 | 30 | 26 | 32 | 31 | 30 | 30 | 29 | 26 | 29 |
有omp | 37 | 41 | 41 | 38 | 41 | 38 | 40 | 35 | 40 | 37 | 38.8 |
可以看出引入openmp反而变慢了;
-
为关键点计算orientation
这个用openmp会提速,但是因为计算过程时间消耗不大,对整体的提升不是很明显,有omp是1ms,无omp是7ms左右。
- 计算fast特征点,这个明显是快了很多;
采用omp的情况:测试了三次,每次要对8个size的图像提取特征,最后一栏是总的时间消耗;
1 | 34 | 19 | 14 | 11 | 10 | 7 | 5 | 2 | 102 |
2 | 34 | 19 | 15 | 12 | 8 | 5 | 5 | 3 | 101 |
3 | 35 | 17 | 13 | 10 | 8 | 6 | 4 | 3 | 96 |
平均 | 34.3 | 18.3 | 14 | 11 | 8.6 | 6 | 4.6 | 2.6 | 99.6 |
不用openmp的情况:
1 | 96 | 67 | 43 | 29 | 19 | 12 | 9 | 3 | 278 |
2 | 101 | 66 | 45 | 30 | 20 | 13 | 10 | 3 | 288 |
3 | 95 | 68 | 44 | 33 | 21 | 12 | 10 | 4 | 287 |
平均 | 97.3 | 67 | 44 | 30.6 | 20 | 12.3 | 9.6 | 3.3 | 284.33 |
明显提速了很多
- DistributeOctTree 分配四叉树这个也挺费时间的啊
63 | 42 | 30 | 25 | 15 | 10 | 10 | 6 | 201 |
然后干脆直接对ComputeKeyPointsOctTree进行并行加速,效果更好
对计算描述子采用openmp加速,效果也一般,没有变快;
加速前后的对比:
1加载一张图片:
有omp:328 348 344 355 337 350 337 349 348 339 343.5
无omp:535 551 534 537 521 540 552 540 544 538 539.2
2 加载1000张图片并且处理:
无omp 9m22s,clock是559441
有omp 6m clock是354328
速度得到明显的提升。
还有一个问题是openmp是否可以与thread同时使用:
一、两个线程的任务量差距比较大的情况:
Thread的join会等待线程执行结束再交给主线程,所以只有一个thread的时候,用openmp冲突变化不大;
有omp:328 348 344 355 337 350 337 349 348 339 343.5
单join+omp 340 354 354 348 352 354 368 385 370 338 356.3
单detach+omp 344 332 371 370 382 344 343 337 349 354 352.6
多detach+omp(另个线程没开omp)354 354 356 347 352 362 364 379 361 361 359
多detach+omp(另个线程开omp) 372 367 372 362 374 376 346 357 338 364 362.8
多个thread加openmp也没有很大的影响;
二、两个线程任务量相近:这里每个任务都是检测特征点;
一个采用omp(单线程360),另一个没有采用omp(单线程550):
384 399 377
765 751 761
两个omp
408 415 420
572 609 595
两个无
603 635 611
730 674 674
另一个测试是提取特征for循环3次,与开3个thread分别进行特征提取比较:
For循环3次:
335 309 327
342 334 321
350 335 318
341 317 311
348 315 314
开三个线程omp:
540 726 849
507 687 837
489 755 826
484 680 823
538 725 866
总结
用thread再加openmp会互相影响,降低程序的性能;
thread越多,每个线程里的任务耗时越大,然后其他线程用omp越多,对omp的效果影响越大,但是用omp还是要比不用omp更快;
用for循环串行执行每个omp线程,影响最小,几乎对omp没有影响;
可以看出来thread对于openmp还是有一定的影响的,每个thread分配给omp的线程可能减小或者是在thread里面继续调用omp再开线程会带来更大的成本,导致omp单独执行时变慢。所以推测在orbslam里面开了多个线程,每个线程必然要相互影响然后导致运行时间增加,但是对线程里采用omp加速orb特征提取,还是会对tracking线程的处理速度有提升。