【问题标题】:Mat matrix in OpenCV and 16-byte alignment for SSEOpenCV 中的 Mat 矩阵和 SSE 的 16 字节对齐
【发布时间】:2014-06-06 09:41:40
【问题描述】:

我喜欢测试SSE/SSE2 处理OpenCV's Mat 的增强。由于SSE's 性能增强仅对 16 字节对齐数据很明显,(1) 我需要修改 Mat 矩阵以与SSE 寄存器一起使用吗?我所做的如下,(2)这是正确的方法吗?

 void test(Mat flowxy, Mat flowresult)
    {
         __m128 x, y, xsquare, ysquare, ybyx, xRecip , sum, r, theta ;//gen is for general purpose
        float *input = (float*)(flowxy.data);
        for(int i = 0; i  < flowxy.rows; i++)
            {
                for(int j = 0; j + SSE_INCREMENT < flowxy.cols; j = j + SSE_INCREMENT)
                {

                    x = _mm_set_ps(input[flowxy.step * (j+6) + i ], input[flowxy.step * (j+4) + i ], input[flowxy.step * (j+2) + i ], input[flowxy.step * (j) + i ]);
                    y = _mm_set_ps(input[flowxy.step * (j+7) + i ], input[flowxy.step * (j+5) + i ], input[flowxy.step * (j+3) + i ], input[flowxy.step * (j+1) + i ]);
                    xRecip  = _mm_rcp_ps(x);
                    xsquare = _mm_mul_ps(x, x);
                    ysquare = _mm_mul_ps(y, y);             
                    ybyx = _mm_mul_ps(xRecip , y);
                    sum = _mm_add_ps(xsquare, ysquare);
                    r = _mm_sqrt_ps(sum);
                    theta = taninverse(ybyx);
                }


            }

    }

我按照here的讨论把设置_mm_set_ps的顺序颠倒过来了。

编辑 1:

void CObjectDetection_TrackingDlg::flow_XY_RTHETA(Mat flowxy, vector<Mat> &flowrtheta)
{
    clock_t start;   
    clock_t finish;  
    start = clock();
    flowrtheta.resize(2);
    if(flowrtheta[0].empty() && flowrtheta[1].empty()){
        flowrtheta[0].create(cvSize(flowxy.rows, flowxy.cols), CV_32FC1);
        flowrtheta[1].create(cvSize(flowxy.rows, flowxy.cols), CV_32FC1);
    }
    vector<Mat> flowxy_S;
    split(flowxy, flowxy_S);
    printMatGrayDatainfloat(flowxy_S[0]);
    printMatGrayDatainfloat(flowxy_S[1]);
    //check SSE2 available
    bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
    if( useSIMD )
    {
        __m128 x, y, xsquare, ysquare, ybyx, xRecip , sum, r, theta ;//gen is for general purpose       
        __declspec(align(16)) struct { int i, j; } sub;
        for(sub.i = 0; sub.i  < flowxy.rows; sub.i++)
        {
            const float *input_x = flowxy_S[0].ptr<float>(sub.i);
            const float *input_y = flowxy_S[1].ptr<float>(sub.i);
            float *output_r = flowrtheta[0].ptr<float>(sub.i);
            float *output_t = flowrtheta[1].ptr<float>(sub.i);
            for(sub.j = 0; sub.j + 4 < flowxy.cols; sub.j = sub.j + 4)
            {

                x = _mm_loadu_ps(&input_x[sub.j]);
                y = _mm_loadu_ps(&input_y[sub.j]);
                xRecip  = _mm_rcp_ps(x);
                xsquare = _mm_mul_ps(x, x);
                ysquare = _mm_mul_ps(y, y);             
                ybyx = _mm_mul_ps(xRecip , y);
                sum = _mm_add_ps(xsquare, ysquare);
                r = _mm_sqrt_ps(sum);
                theta = taninverse(ybyx);
                _mm_storeu_ps(&output_r[sub.j], r);
                _mm_storeu_ps(&output_t[sub.j], theta);

            }


        }

    }
    else
    {
        for(int i = 0; i  < flowxy.rows; i++)
        {
            const float *input_x = flowxy_S[0].ptr<float>(i);
            const float *input_y = flowxy_S[1].ptr<float>(i);
            float *output_r = flowrtheta[0].ptr<float>(i);
            float *output_t = flowrtheta[1].ptr<float>(i);
            for(int j = 0; j  < flowxy.cols; j++)
            {
                double x_sq = input_x[j] * input_x[j];
                double y_sq = input_y[j] * input_y[j];
                double y_by_x =  input_y[j] / input_x[j];
                output_r[j] = sqrt(x_sq + y_sq);
                output_t[j] = atan(y_by_x);
            }


        }


    }
    flowxy_S[0].release();
    flowxy_S[1].release();
    finish = clock() - start;
    double interval = finish / (double)CLOCKS_PER_SEC;
    //printMatGrayDatainfloat(flowrtheta[0]);
    //printMatGrayDatainfloat(flowrtheta[1]);
    return;
}

【问题讨论】:

  • 您的代码或多或少没问题,因为您没有进行任何需要 16 字节对齐的加载或存储。但是使用_mm_set_ps 效率非常低 - 您应该使用_mm_loadu_ps 加载连续未对齐的数据,然后使用例如将元素随机排列到所需的顺序中。 _mm_shuffle_ps.
  • 让我探索更多,并会和你在一起。我的 r 和 theta 是我需要写回 2 通道 Mat flowresult 的结果。最好的方法是什么?谢谢
  • 您可以使用_mm_storeu_ps将结果写回内存。
  • @PaulR 我已经更新了。我比较了 if{} 和 else{} 中的两个进程。 else{} 0.411msec 和 if{} 中的过程是 0.419msec。为什么 if{} 中的过程没有快四倍?是不是因为内存不对齐?
  • 编译器可能无论如何都在向量化此代码,因此您可能无法从显式向量化中获得任何收益 - 查看为您的标量分支生成的代码,看看它是否包含 SSE 指令。另请注意,旧 CPU 上未对齐的加载/存储非常昂贵(如果这是例如 Core i7,您应该没问题)。

标签: opencv sse


【解决方案1】:

编译器可能无论如何都在向量化此代码,因此您可能无法从显式向量化中获得任何收益 - 查看为您的标量分支生成的代码并查看它是否包含 SSE 指令。另请注意,旧 CPU 上未对齐的加载/存储非常昂贵(如果这是例如 Core i7,您应该没问题)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2017-06-28
    • 1970-01-01
    • 2011-12-19
    相关资源
    最近更新 更多