分析
在很早之前,使用opnecv实现了photoshop中的扩散特效滤镜。【OpenCV滤镜-PS扩散特效】。当时是只写了最朴素的实现,虽然是C++实现,但是性能还是比较差,有很大优化空间。本篇给出优化的过程和实现,首先看一下原来的朴素实现
|
|
分析盘点一下,可以进行的优化点有
- 逻辑优化,原实现逻辑太简单粗暴,且存在循环里面每次生成随机数、使用switch跳转等不友好的逻辑实现。需要优化
- 多线程并行,循环遍历处理像素,支持比较方便的多线程优化
- simd优化,处理时没有交错和跳转访问,没有复杂的非线性计算,适合采用simd优化
优化
下面开始优化,优化之前仍然首先考虑两个问题
- 优化前后效果无差异,这个在本次案例中无法做到,因为随机数的存在,即使相同的实现重复跑也会出现不一样输出,从原理上这个已经决定了。所以只能通过人眼观察输出效果是否符合预期。
- Release模式下测试,耗时对比
逻辑优化
上面分析在循环里面有随机数、和switch跳转问题,针对此可以将这两部分搬到循环外面,随机数统一提前生成,switch跳转可以使用查找表的方式进行优化。基于这个优化策略,另一个优点是,优化后可以更进一步方便进行simd优化。
|
|
优化后,观察效果符合预期,性能方面提升非常明显:
|
|
提升高达3倍,可见原先朴素的实现逻辑写的太烂了😂
多线程并行
接着,可以加上openmp的多线程并行
|
|
之行效果符合预期,但是性能却出现了劣化,并没有提升
|
|
估计是线程调度的新增的开销大于并行带来的收益了
simd优化
并行尝试无果,还有一招,继续做simd优化,在开始simd优化之前先把处理改成使用指针访问
|
|
指针访问去除了通道的for循环,方便simd批量加载,单改完后发现lut还是存在批量加载的问题, 此时又需要把lut由二维拆分成两个一维
|
|
但拆分完发现新问题了,多一个维度的访问,耗时就上去了
|
|
预感不妙,继续改成simd实现,但发现还是无法继续,有lut的还是会面临无法联系访问的问题
|
|
到此,最终的优化以下的指针版本为最优解
|
|