并行计算 SLIC超像素算法(三) OpenMP优化(三)总结与运行结果加速比

目录

介绍

优化思路总结

1. 面向对象与面向过程优化

2.化赋值计算操作

3. 使用缓存替代计算

4. 优化cache命中率

5. 优化多次相同的操作 smid

6. 多线程并行

7. 对于区域生长算法的并行优化

8. 信仰优化

运行结果及加速比


介绍

        在这篇博客中,我会总结我们在OpenMP并行优化过程中遇到的问题以及对一些思路的总结,没看过上一篇博客 并行计算 SLIC超像素算法(三) OpenMP优化(二)具体优化过程 的,建议先看一下才能更好的理解。最后的最后,我会把我们实验的运行结果以及加速比放上去。

优化思路总结

1. 面向对象与面向过程优化

原来的程序时基于面向对象的,面向对象就必然有类的开销,优化程序的过程中先优化面向对象

  1. 将所有类的变量提取出来
  2. 将所有的方法孤立出来,通过全局变量传参
  3. 替换所有的vector为数组,在使用vector的时候,也是为了便利性牺牲了一定的性能,通过vector的替换可以省去许多函数调用,提高性能,利用数组与指针更加贴近于汇编操作,方便编译器进行优化操作
  4. 自己实现vector数组替换原始的面向对象的vector

这里使用全局变量主要是为了方便后期将所有的函数合一,减少函数调用时间

2.化赋值计算操作

  1. 原始的所有赋值操作是通过for循环进行赋值
  2. 用到系统自带的memset与memcpy会显著的提升赋值的性能
  3. 优化浮点除法,浮点除的性能明显低于浮点+-*
  4. 将浮点除法转换为浮点乘法,在编译期间就计算出可以计算的除法的结果
  5. 利用cebt立方根函数,代替pow函数

3. 使用缓存替代计算

  1. 在颜色转换中对rgb转换成lab需要进行多次浮点运算以及多次立方运算,性能很低
  2. 首先颜色空间的转换需要先从rgb转换为xyz,这一过程需要的是一次pow(x,2.4)的运算,考虑对于固定的rgb每次的起始运算都一致,只需要提前计算256种颜色的pow运算就可以省区后续的pow,只需要查表就可以了,大约优化0.2s
  3. 有多个颜色可能会同时出现在界面上,这个时候可以利用hashmap一类的函数,对颜色转换进行缓存,也可以省去许多浮点运算以及pow运算(在多线程的条件下,缓存命中率会明显下降,效率反而降低,所以最后我们决定放弃这一部分的缓存,进而提高多线程下的运行速度)。

4. 优化cache命中率

  1. 对于原始的cache,由于rgb与lab都是分开存储的cache的命中率不一定很高
  2. 使用三维数组直接存放rgb与lab相邻的lab与rgb基本上一定会命中cpu cache会提高效率 大约优化0.4-0.6s
  3. 对线程进行较大块的分割减少线程消耗同时,增加部分命中率
  4. 进行字节对齐提高内存读取速度

5. 优化多次相同的操作 smid

        对于相似的操作,只是单纯的利用多核效果并不出色,可以考虑到,由于cpu拥有多个运算单元,往往利用向量化,可以同时进行多个运算单元并行操作进一步提高并行化效果。

  原始代码如下所示

seeds[kn + 0] = sigma[kn + 0] * inv;
seeds[kn + 1] = sigma[kn + 1] * inv;
seeds[kn + 2] = sigma[kn + 2] * inv;
seeds[kn + 3] = sigma[kn + 3] * inv;
seeds[kn + 4] = sigma[kn + 4] * inv;

这五个明显是几乎相同的代码,因此可以进行向量化操作

#pragma omp simd
for (int i = 0; i < 5; ++i) {
   seeds[kn + i] = sigma[kn + i] * inv;
}

6. 多线程并行

利用openmp可以实现多线程并行,下面一行就是for循环的迭代过程

#pragma omp parallel for default(none) schedule(guided) shared(....)

对于schedule,经过系统测试,设置为guided,且把最小值设置为8的性能最高

对于可以实现的for循环进行并行

尽量极高线程并行粒度,减少线程生成的开销

对于无法实行单纯的for循环的并行的,可以自己实现规约算法,分线程规约,最后汇总。

7. 对于区域生长算法的并行优化

区域生长算法对应 更新聚类中心连接孤立像素 ,这一部分没法直接并行,而且局部性差。

所以我们想到了,先并行BFS直接对聚类进行打标签。然后使用 并查集 对BFS的结果进行合并,剩下的就容易并行优化了。

8. 信仰优化

使用编译器O3优化 。(O3!!!yyds!!!)。

运行结果及加速比

当我们拿到代码的时候,运行代码大概要跑 35 s左右。

经过我们努力的优化之后,因为受机器的原因,跑不了更多的线程,下面是有关线程数的加速比:

线程数目

运行时间(秒)

加速比

1

2.229

1.0

2

1.118

1.993

4

0.634

3.515

8

0.370

6.024

……

……

……

你可能感兴趣的:(并行计算设计与导论,算法,c++,并行计算,openmp,avx)