mirror of
https://github.com/opencv/opencv.git
synced 2026-11-09 18:04:29 -06:00
core: vectorize cv::sum for CV_64F (#30582)
* core: vectorize cv::sum for CV_64F Sum_SIMD has specializations for the 8-, 16- and 32-bit depths, but not for CV_64F, so cv::sum and cv::mean on a double matrix fall through to the scalar unrolled loop in sum_. CV_64FC1 is not in TYPICAL_MAT_TYPES, so no perf test covered it. The source type is already the accumulator type, so the specialization needs neither expansion nor conversion: it loads three vectors at the native width and adds them. The channel limit matches DEFINE_SUM_SIMD_32 because init_maskbuf can only build the cn == 4 masks once the vector holds four lanes, which rules the case out on an SSE2 baseline. Extend sum_wide with the CV_64F rows so the change is measurable. * core: reuse DEFINE_SUM_SIMD_16 for CV_64F Drop the near-duplicate DEFINE_SUM_SIMD_64 and instantiate DEFINE_SUM_SIMD_16 with v_float64 instead, as suggested in review. The one thing that kept the two apart was the channel guard. DEFINE_SUM_SIMD_16 rejects cn > 4, which is correct only while the vector holds at least four lanes: init_maskbuf builds the cn == 4 masks under that condition, so with a narrower vector the reduction runs against all-zero masks and drops the vectorized elements without reporting anything. Every 32-bit register type has four lanes or more, so the existing instantiations never saw it; v_float64 has two on an SSE2 baseline. Widening the guard to the DEFINE_SUM_SIMD_32 form leaves the existing instantiations unchanged, since 3+(simd_width>=4) is 4 for all of them.
This commit is contained in:
@@ -4,11 +4,12 @@ namespace opencv_test
|
||||
{
|
||||
using namespace perf;
|
||||
|
||||
// The 32-bit integer depths are not in TYPICAL_MAT_TYPES, so they were not measured; they are the
|
||||
// ones whose scalar accumulation step this touches.
|
||||
// The wide depths are not in TYPICAL_MAT_TYPES, so they were not measured; they are the ones
|
||||
// whose scalar accumulation step this touches.
|
||||
PERF_TEST_P(Size_MatType, sum_wide,
|
||||
testing::Combine(testing::Values(TYPICAL_MAT_SIZES),
|
||||
testing::Values(CV_32SC1, CV_32UC1, CV_32SC3)))
|
||||
testing::Values(CV_32SC1, CV_32UC1, CV_32SC3,
|
||||
CV_64FC1, CV_64FC3)))
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
int type = get<1>(GetParam());
|
||||
|
||||
@@ -124,6 +124,10 @@ template<> struct Sum_SIMD<T, ST> \
|
||||
ST maskbuf[VTraits<VecT>::max_nlanes*9]; \
|
||||
};
|
||||
|
||||
// The channel limit is 4 only once the vector holds at least four lanes: init_maskbuf builds
|
||||
// the cn == 4 masks under that condition, so a narrower vector would reduce against all-zero
|
||||
// masks and silently drop the vectorized elements. Every 32-bit register type has four lanes
|
||||
// or more; v_float64 on an SSE2 baseline has two.
|
||||
#undef DEFINE_SUM_SIMD_16
|
||||
#define DEFINE_SUM_SIMD_16(T, ST, iST, VecT, load_op) \
|
||||
template<> struct Sum_SIMD<T, ST> \
|
||||
@@ -134,10 +138,10 @@ template<> struct Sum_SIMD<T, ST> \
|
||||
} \
|
||||
int operator ()(const T* src, const uchar* mask, ST* dst, int len, int cn) const \
|
||||
{ \
|
||||
if (mask || (cn < 1 || cn > 4)) \
|
||||
int x = 0, simd_width = VTraits<VecT>::vlanes(); \
|
||||
if (mask || (cn < 1 || cn > 3+(simd_width>=4))) \
|
||||
return 0; \
|
||||
len *= cn; \
|
||||
int x = 0, simd_width = VTraits<VecT>::vlanes(); \
|
||||
VecT m0 = vx_load(maskbuf), m1, m2, m3, m4, m5, m6, m7, m8; \
|
||||
if (cn == 1) { \
|
||||
m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m0; \
|
||||
@@ -229,6 +233,8 @@ template<> struct Sum_SIMD<T, ST> \
|
||||
|
||||
DEFINE_SUM_SIMD_32(int, double, int64, v_float64)
|
||||
DEFINE_SUM_SIMD_32(float, double, int64, v_float64)
|
||||
|
||||
DEFINE_SUM_SIMD_16(double, double, int64, v_float64, vx_load)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user