1

У меня есть функция, определенная Intel IPP для работы с изображением/областью изображения.
Ввод изображения является указателем на изображение, параметрами для определения размера процесса и параметров фильтра.
Функция IPP однопоточная.Обработка параллельных изображений в OpenMP - Разделение изображения

Теперь у меня есть изображение размера M x N.
Я хочу применить фильтр к нему параллельно.
Основная идея проста, разбить изображение на 4 вспомогательных изображения, которые не зависят друг от друга.
Примените фильтр к каждому вспомогательному изображению и напишите результат на дополнительный блок пустого изображения, где каждый поток записывается в отдельный набор пикселей.
Это действительно похоже на обработку 4 изображений на каждом из них.

Это программа, которую я делаю это с:

void OpenMpTest() 
{ 
    const int width = 1920; 
    const int height = 1080; 

    Ipp32f input_image[width * height]; 
    Ipp32f output_image[width * height]; 

    IppiSize size = { width, height }; 

    int step = width * sizeof(Ipp32f); 

    /* Splitting the image */ 
    IppiSize section_size = { width/2, height/2}; 

    Ipp32f* input_upper_left = input_image; 
    Ipp32f* input_upper_right = input_image + width/2; 
    Ipp32f* input_lower_left = input_image + (height/2) * width; 
    Ipp32f* input_lower_right = input_image + (height/2) * width + width/2; 

    Ipp32f* output_upper_left = input_image; 
    Ipp32f* output_upper_right = input_image + width/2; 
    Ipp32f* output_lower_left = input_image + (height/2) * width; 
    Ipp32f* output_lower_right = input_image + (height/2) * width + width/2; 

    Ipp32f* input_sections[4] = { input_upper_left, input_upper_right, input_lower_left, input_lower_right }; 
    Ipp32f* output_sections[4] = { output_upper_left, output_upper_right, output_lower_left, output_lower_right }; 

    /* Filter Params */ 
    Ipp32f pKernel[7] = { 1, 2, 3, 4, 3, 2, 1 }; 

    omp_set_num_threads(4); 
    #pragma omp parallel for 
    for (int i = 0; i < 4; i++) 
     ippiFilterRow_32f_C1R(
           input_sections[i], step, 
           output_sections[i], step, 
           section_size, pKernel, 7, 3); 
} 

Теперь вопросы, я не вижу никакого выигрыша по сравнению работает режим однотридовой на все изображение.
Я попытался изменить размер изображения или размер фильтра, и ничто не изменит изображение.
Больше всего я мог бы получить ничего значимого (10-20%).

Я думал, что это может иметь какое-то отношение к тому, что я не могу «обещать» каждому потоку зону, которую он получил, «Только для чтения».
Более того, чтобы сообщить, что место памяти, на которое он пишет, также принадлежит только самому себе.
Я читал об определении переменных как private и share, но я не мог найти руководство по работе с массивами и указателями.

Что было бы правильным способом справиться с указателями и вспомогательными массивами в OpenMP?

+0

Вы работаете с границей пропускной способности и поэтому не можете масштабироваться с количеством физических ядер (если ваш фильтр намного больше). Однако я ожидал бы улучшения более чем на 10-20%. Обычно я не распараллеливаю цикл, основанный на количестве потоков. Я бы сделал это для количества пикселей или чего-то еще. –

+0

Как я могу доказать себе, что эта проблема ограничена памятью? – Royi

+0

Для этого вам, вероятно, нужно использовать некоторый инструмент для профилирования. Но это не то, что я делаю. Я определяю FLOPS операции и сравниваю ее с пиковыми FLOPS процессора. Я также определяю, сколько пропускной способности используется в этой операции (вы также можете рассчитать это) и сравнить это с максимальной пропускной способностью процессора. Если операция намного меньше пиковой FLOPS и связана полосой пропускания, то это ограничение полосы пропускания памяти. –

ответ

0

Использование Intel IPP фильтра, лучшим решением было с помощью:

int height = dstRoiSize.height; 
     int width = dstRoiSize.width; 
     Ipp32f *pSrc1, *pDst1; 
     int nThreads, cH, cT; 

#pragma omp parallel shared(pSrc, pDst, nThreads, width, height, kernelSize,\ 
          xAnchor, cH, cT) private(pSrc1, pDst1) 
     { 
    #pragma omp master 
      { 
       nThreads = omp_get_num_threads(); 
       cH = height/nThreads; 
       cT = height % nThreads; 
      } 
    #pragma omp barrier 
      { 
       int curH; 
       int id = omp_get_thread_num(); 

       pSrc1 = (Ipp32f*)((Ipp8u*)pSrc + id * cH * srcStep); 
       pDst1 = (Ipp32f*)((Ipp8u*)pDst + id * cH * dstStep); 
       if(id != (nThreads - 1)) curH = cH; 
       else curH = cH + cT; 
       ippiFilterRow_32f_C1R(pSrc1, srcStep, pDst1, dstStep, 
          width, curH, pKernel, kernelSize, xAnchor); 
      } 
     } 

Спасибо.

0

Как выполняется сравнение резьбовых IPP? Предполагая отсутствие условий гонки, проблемы с записью в общие массивы, скорее всего, будут возникать в строках кэша, где часть строки записывается одним потоком, а другая часть считывается другим. Вероятно, потребуется область данных размером более 10 мегабайт или около того, прежде чем будет показано полное параллельное ускорение.
Вам понадобится более глубокий анализ, например. с помощью Intel VTune Amplifier, чтобы определить, ограничена ли пропускная способность памяти или перекрытие данных.

Смежные вопросы