НЕОН увеличивая время выполнения

c++ neon

113 просмотра

1 ответ

В настоящее время я пытаюсь оптимизировать некоторые из моих кодов обработки изображений для использования инструкций NEON.

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

float*     l_ptrGauss_pf32   = [...];
float*     l_ptrLaplace_pf32 = [...]; // Three times as large 

for (uint64_t k = 0; k < l_numPixels_ui64; ++k)
{
    float l_weight_f32 = *l_ptrGauss_pf32;

    *l_ptrLaplace_pf32 *= l_weight_f32;
    ++l_ptrLaplace_pf32;
    *l_ptrLaplace_pf32 *= l_weight_f32;
    ++l_ptrLaplace_pf32;
    *l_ptrLaplace_pf32 *= l_weight_f32;
    ++l_ptrLaplace_pf32;

    ++l_ptrGauss_pf32;
}

Поэтому, когда я заменяю приведенный выше код на встроенные NEON, время выполнения увеличивается примерно на 10%.

float32x4_t l_gaussElem_f32x4;
float32x4_t l_laplElem1_f32x4;
float32x4_t l_laplElem2_f32x4;
float32x4_t l_laplElem3_f32x4;

for( uint64_t k=0; k<(l_lastPixelInBlock_ui64/4); ++k)
{
    l_gaussElem_f32x4 = vld1q_f32(l_ptrGauss_pf32);
    l_laplElem1_f32x4 = vld1q_f32(l_ptrLaplace_pf32);
    l_laplElem2_f32x4 = vld1q_f32(l_ptrLaplace_pf32+4);
    l_laplElem3_f32x4 = vld1q_f32(l_ptrLaplace_pf32+8);

    l_laplElem1_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem1_f32x4);
    l_laplElem2_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem2_f32x4);
    l_laplElem3_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem3_f32x4);

    vst1q_f32(l_ptrLaplace_pf32,   l_laplElem1_f32x4);
    vst1q_f32(l_ptrLaplace_pf32+4, l_laplElem2_f32x4);
    vst1q_f32(l_ptrLaplace_pf32+8, l_laplElem3_f32x4);

    l_ptrLaplace_pf32 += 12;
    l_ptrGauss_pf32   += 4;
}

Обе версии скомпилированы с -Ofast с использованием Apple LLVM 8.0. Действительно ли компилятор так хорош в оптимизации этого кода даже без встроенных функций NEON?

Автор: Chris Источник Размещён: 04.09.2019 05:18

Ответы (1)


0 плюса

Ваш код содержит относительно много операций векторной загрузки и несколько операций умножения. Так что я бы рекомендовал оптимизировать загрузку векторов. Есть два шага:

  • Используйте выровненную память в ваших массивах.
  • Используйте предварительную выборку.

Для этого я бы рекомендовал использовать следующую функцию:

inline float32x4_t Load(const float * p)
{
    // use prefetch:
    __builtin_prefetch(p + 256); 
    // tell compiler that address is aligned:
    float * _p = (float *)__builtin_assume_aligned(p, 16);
    return vld1q_f32(_p);
}
Автор: ErmIg Размещён: 30.03.2017 06:40
Вопросы из категории :
32x32