|
板凳

楼主 |
发表于 2017-8-28 22:36:30
|
只看该作者
本帖最后由 ancientcc 于 2017-8-29 11:07 编辑
cv_cpu_config.h
由cmake生成,指示了要使用的优化设置。以下是一个例子,支持优化指令集:SSE、SSE2、SSE_1、SSE_2、FP16、AVX、AVX2。- // OpenCV CPU baseline features
- #define CV_CPU_COMPILE_SSE 1
- #define CV_CPU_BASELINE_COMPILE_SSE 1
- #define CV_CPU_COMPILE_SSE2 1
- #define CV_CPU_BASELINE_COMPILE_SSE2 1
- #define CV_CPU_BASELINE_FEATURES 0 \
- , CV_CPU_SSE \
- , CV_CPU_SSE2 \
- // OpenCV supported CPU dispatched features
- #define CV_CPU_DISPATCH_COMPILE_SSE4_1 1
- #define CV_CPU_DISPATCH_COMPILE_SSE4_2 1
- #define CV_CPU_DISPATCH_COMPILE_FP16 1
- #define CV_CPU_DISPATCH_COMPILE_AVX 1
- #define CV_CPU_DISPATCH_COMPILE_AVX2 1
复制代码
让以fastAtan32f为例,描述OpenCV如何根据特定指令集进行优化过程。- modules/core/mathfuncs_core.dispatch.cpp
- void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees)
- {
- CV_INSTRUMENT_REGION()
- CALL_HAL(fastAtan32f, cv_hal_fastAtan32f, Y, X, angle, len, angleInDegrees);
- CV_CPU_DISPATCH(fastAtan32f, (Y, X, angle, len, angleInDegrees),
- CV_CPU_DISPATCH_MODES_ALL);
- }
复制代码
让深入CALL_HAL。- #define CALL_HAL(name, fun, ...) \
- { \
- int res = fun(__VA_ARGS__); \
- if (res == CV_HAL_ERROR_OK) \
- return; \
- else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
- CV_Error_(cv::Error::StsInternal, \
- ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \
- }
- #define cv_hal_fastAtan32f hal_ni_fastAtan32f
- inline int hal_ni_fastAtan32f(const float* y, const float* x, float* dst, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
复制代码
CALL_HAL最后执行hal_ni_fastAtan32f,它就是空操作,但由于返回CV_HAL_ERROR_NOT_IMPLEMENTED,调用它的fastAtan32f会继续执行后面的CV_CPU_DISPATCH,正是这个宏执行了真正操作。在深入这宏前让介绍mathfuncs_core.dispatch.cpp中的两条include语句。- #include "mathfuncs_core.simd.hpp"
- #include "mathfuncs_core.simd_declarations.hpp"
复制代码
第一个include作用是两个,1)声明cpu_baseline版本,2)实现baseline版本,这是通过不定义CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY宏,使得mathfuncs_core.simd.hpp包含实现。第二个include也两个作用,1)声明特殊指令集版本(只是声明),2)定义一个叫CV_CPU_DISPATCH_MODES_ALL的宏。- #define CV_CPU_DISPATCH_MODES_ALL AVX2, AVX, SSE2, BASELINE
复制代码
CV_CPU_DISPATCH_MODES_ALL宏指示了每个模块实现了的指令集版本。它实现了4种指令集,AVX2、AVX、SSE2是特殊指令集,BASELINE则是cpu_baseline实现。
上面4个种版本,cpu_baseline的函数已由第一个include实现,三种特殊指令集则由另外三个源文件实现,它们有着一样内容。
- #include "precomp.hpp"
- #include "mathfuncs_core.simd.hpp"
复制代码
要编译这三个文件,必须在文件层定义一个叫CV_CPU_DISPATCH_MODE的宏。
文件 | 文件层的预定义宏 | 最后实现的函数 | mathfuncs_core.avx.cpp | CV_CPU_DISPATCH_MODE=AVX | cv::hal: pt_AVX::fastAtan32f | mathfuncs_core.avx2.cpp | CV_CPU_DISPATCH_MODE=AVX2 | cv::hal: pt_AVX2::fastAtan32f | mathfuncs_core.sse2.cpp | CV_CPU_DISPATCH_MODE=SSE2 | cv::hal: pt_SSE2::fastAtan32f |
有了这4个版本的fastAtan32f实现,让回到CV_CPU_DISPATCH,看它是如何调用这四个函数。以下这个宏的伪代码。
- CV_CPU_DISPATCH(fastAtan32f, (Y, X, angle, len, angleInDegrees), AVX2, AVX, SSE2, baseline)
- {
- if (cv::checkHardwareSupport(CV_CPU_AVX2) {
- cv::hal::opt_AVX2::fastAtan32f(Y, X, angle, len, angleInDegrees);
- return;
- }
- if (cv::checkHardwareSupport(CV_CPU_AVX) {
- cv::hal::opt_AVX::fastAtan32f(Y, X, angle, len, angleInDegrees);
- return;
- }
- cv::hal::opt_SSE2::fastAtan32f(Y, X, angle, len, angleInDegrees); return;
- cv::hal::cpu_baseline::fastAtan32f(Y, X, angle, len, angleInDegrees); return;
- }
复制代码 CV_CPU_DISPATCH_MODES_ALL宏决定了四个fastAtan32f调用次序。要没意外,CV_CPU_DISPATCH的最后两个总是__CV_CPU_DISPATCH_CHAIN_BASELINE, __CV_CPU_DISPATCH_CHAIN_END,后者是个空操作。
- #define __CV_CPU_DISPATCH_CHAIN_END(fn, args, mode, ...) /* done */
复制代码
baseline features和dispatched features
- #if !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_COMPILE_AVX
- # define CV_TRY_AVX 1
- # define CV_CPU_HAS_SUPPORT_AVX 1
- # define CV_CPU_CALL_AVX(fn, args) return (opt_AVX::fn args)
- #elif !defined CV_DISABLE_OPTIMIZATION && defined CV_ENABLE_INTRINSICS && defined CV_CPU_DISPATCH_COMPILE_AVX
- # define CV_TRY_AVX 1
- # define CV_CPU_HAS_SUPPORT_AVX (cv::checkHardwareSupport(CV_CPU_AVX))
- # define CV_CPU_CALL_AVX(fn, args) if (CV_CPU_HAS_SUPPORT_AVX) return (opt_AVX::fn args)
- #else
- # define CV_TRY_AVX 0
- # define CV_CPU_HAS_SUPPORT_AVX 0
- # define CV_CPU_CALL_AVX(fn, args)
- #endif
- #define __CV_CPU_DISPATCH_CHAIN_AVX(fn, args, mode, ...) CV_CPU_CALL_AVX(fn, args); __CV_EXPAND(__CV_CPU_DISPATCH_CHAIN_ ## mode(fn, args, __VA_ARGS__))
复制代码
当中有两个宏:CV_CPU_COMPILE_AVX、CV_CPU_DISPATCH_COMPILE_AVX。回看cv_cpu_config.h,第一个是baseline features,第二个是dispatched features。baseline features指的是那些必须满足的SIMD。一旦运行在的cpu不支持这种SIMD,app会因为非法而退出。dispatched features指的是那些会运行时判断是否支持的指令集,即用cv::checkHardwareSupport运行时检查cpu是否能支持这种SIMD。
为让支持更多cpu,应尽可能低的定义baseline features。当前就是SSE、SSE2。
opencv3.3.0有BUG,必须把AVX、AVX2定义为baseline features。以下是个人解决这BUG方法。- #ifdef CV_CPU_COMPILE_AVX
- # include <immintrin.h>
- # define CV_AVX 1
- #endif
复制代码 中的第一句改为- #if defined CV_CPU_COMPILE_AVX || defined CV_CPU_DISPATCH_COMPILE_AVX
复制代码
- #ifdef CV_CPU_COMPILE_AVX2
- # include <immintrin.h>
- # define CV_AVX2 1
- #endif
复制代码 中的第一句改为- #if defined CV_CPU_COMPILE_AVX2 || defined CV_CPU_DISPATCH_COMPILE_AVX2
复制代码 |
|