почему мой SSE не быстрее, чем код C / C ++? - PullRequest
3 голосов
/ 16 ноября 2011

Я только начал использовать SSE для оптимизации своего кода для проекта компьютерного зрения с целью определения цвета кожи на изображении. Ниже моя функция. Функция берет цветное изображение, просматривает каждый пиксель и возвращает карту вероятности. Закомментированный код был моей первоначальной реализацией C ++, а остальное - версия SSE. Я рассчитал их оба, и было бы странно узнать, что SSE не быстрее, чем мой оригинальный код C ++. Любые предложения о том, что происходит или как оптимизировать функцию дальше?

void EvalSkinProb(const Mat& cvmColorImg, Mat& cvmProb)
{
    std::clock_t ts = std::clock();  
    Mat cvmHSV = Mat::zeros(cvmColorImg.rows, cvmColorImg.cols, CV_8UC3);
    cvtColor(cvmColorImg, cvmHSV, CV_BGR2HSV);
    std::clock_t te1 = std::clock(); 

    float fFG, fBG;
    double dp;

    __declspec(align(16)) int frgb[4] = {0};
    __declspec(align(16)) int fBase[4] = {g_iLowHue, g_iLowSat, g_iLowVal, 0};
    __declspec(align(16)) int fIndx[4] = {0};
    __m128i* pSrc1 = (__m128i*) frgb;
    __m128i* pSrc2 = (__m128i*) fBase;
    __m128i* pDest = (__m128i*) fIndx;
    __m128i m1;

    for (int y = 0; y < cvmColorImg.rows; y++)
    {
        for (int x = 0; x < cvmColorImg.cols; x++)
        {
            cv::Vec3b hsv = cvmHSV.at<cv::Vec3b>(y, x);
            frgb[0] = hsv[0];hsv[1] = hsv[1];hsv[2] =hsv[2];
            m1 = _mm_sub_epi32(*pSrc1, *pSrc2);
            *pDest = _mm_srli_epi32(m1, g_iSValPerbinBit); 

            // c++ code
            //fIndx[0] = ((hsv[0]-g_iLowHue)>>g_iSValPerbinBit);
            //fIndx[1] = ((hsv[1]-g_iLowSat)>>g_iSValPerbinBit);
            //fIndx[2] = ((hsv[2]-g_iLowVal)>>g_iSValPerbinBit);

            fFG = m_cvmSkinHist.at<float>(fIndx[0], fIndx[1], fIndx[2]);
            fBG = m_cvmBGHist.at<float>(fIndx[0], fIndx[1], fIndx[2]);
            dp = (double)fFG/(fBG+fFG);
            cvmProb.at<double>(y, x) = dp;          
        }
    }
    std::clock_t te2 = std::clock();  
    double dSecs1 = (double)(te1-ts)/(CLOCKS_PER_SEC);
    double dSecs2 = (double)(te2-te1)/(CLOCKS_PER_SEC);
}

Ответы [ 3 ]

8 голосов
/ 16 ноября 2011

Первая проблема заключается в том, что вы выполняете очень мало работы с SSE для огромного объема перемещения данных.Большую часть времени вы будете тратить только на упаковку / распаковку данных в регистрах SSE для двух инструкций ...

Во-вторых, в этом коде будет очень незначительное снижение производительности.

Вы используете буфер для передачи данных между переменными и регистрами SSE.Это БОЛЬШОЙ НЕТ-НЕТ .

Причина этого заключается в загрузке / хранении ЦП.Когда вы записываете данные в ячейку памяти, а затем сразу же пытаетесь прочитать их обратно с другим размером слова, это обычно приводит к тому, что данные сбрасываются полностью в кэш и перечитываются.Это может повлечь за собой более 20 циклов штрафа.

Это связано с тем, что блоки загрузки / сохранения ЦП не оптимизированы для такого необычного доступа.

1 голос
/ 16 ноября 2011

Я не слишком знаком с OpenCV, но я подозреваю, что вы получите достойную пропускную способность, только если убедитесь, что данные, к которым вы обращаетесь, уже выровнены вне цикла, а не загружены без выравниваниявнутри петли.

0 голосов
/ 16 ноября 2011

Не проверено, но оно должно дать вам несколько идей:

auto base = _mm_set_epi32(g_iLowHue, g_iLowSat, g_iLowVal, 0);

for (int y = 0; y < cvmColorImg.rows; y++)
{
    for (int x = 0; x < cvmColorImg.cols; x++)
    {              
        auto hsv = _mm_loadu_si128(&cvmHSV.at<cv::Vec3b>(y, x)[0]); // Would be better if cvmHSV was aligned in which case _mm_load_si128 is faster     
        auto m1  = _mm_sub_epi32(hsv, base);
        auto m2  = _mm_srli_epi32(m1, g_iSValPerbinBit); 

        auto fFG = static_cast<double>(m_cvmSkinHist.at<float>(m2.m128i_i32[0], m2.m128i_i32[1], m2.m128i_i32[2]));
        auto fBG = static_cast<double>(m_cvmBGHist.at<float>(m2.m128i_i32[0], m2.m128i_i32[1], m2.m128i_i32[2]));         
        cvmProb.at<double>(y, x) = fFG/(fBG+fFG);                         
    }
}
...