Оптимизация цикла с несколькими инструкциями (SSE2, SSE4) с TBB - PullRequest
1 голос
/ 10 февраля 2011

У меня есть простой алгоритм, связанный с обработкой изображений.Вкратце, изображение (среднее значение) с плавающей точкой вычитается из 8-битного изображения, результат которого затем сохраняется в изображение с плавающей точкой (dest)

эта функция в основном написана встроенными функциями.Я пытался оптимизировать эту функцию с помощью TBB, parrallel_for, но я получил не выигрыш в скорости, а штраф.

Что мне делать?Должен ли я использовать более низкоуровневую схему, такую ​​как задача TBB, для оптимизации кода?

float           *m, **m_data,
                *o, **o_data;
unsigned char   *p, **src_data;
register unsigned long len, i;
unsigned long   nr,
                nc;

src_data    =   src->UByteData;    // 2d array
m_data      =   mean->FloatData;   // 2d array
o_data      =   dest->FloatData;   // 2d array
nr          =   src->Rows;
nc          =   src->Cols;

__m128i xmm0;

for(i=0; i<nr; i++)
{
    m = m_data[i];
    o = o_data[i];
    p = src_data[i];
    len = nc;
    do
    {
        _mm_prefetch((const char *)(p + 16),  _MM_HINT_NTA);
        _mm_prefetch((const char *)(m + 16),  _MM_HINT_NTA);

        xmm0 = _mm_load_si128((__m128i *) (p));

        _mm_stream_ps(
                        o,
                        _mm_sub_ps(
                                    _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 0))),
                                    _mm_load_ps(m + offset)
                                )
                    );
        _mm_stream_ps(
                        o + 4,
                        _mm_sub_ps(
                                    _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 4))),
                                    _mm_load_ps(m + offset + 4)
                                )
                    );
        _mm_stream_ps(
                        o + 8,
                        _mm_sub_ps(
                                    _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 8))),
                                    _mm_load_ps(m + offset + 8)
                                )
                    );
        _mm_stream_ps(
                        o + 12,
                        _mm_sub_ps(
                                    _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 12))),
                                    _mm_load_ps(m + offset + 12)
                                )
                    );

        p += 16;
        m += 16;
        o += 16;
        len -= 16;
    }
    while(len);
}

1 Ответ

1 голос
/ 10 февраля 2011

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

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

Если возможно, вам следует объединить этот цикл с любыми другими операциями, которые вы выполняете до / после этого, - таким образом вы амортизируете стоимость операций ввода-вывода памяти по сравнению с дополнительными вычислениями.

...