Распараллеливание OpenMP внутри циклов for занимает слишком много времени - PullRequest
0 голосов
/ 04 августа 2020

Я готовлю программу, которая должна использовать распараллеливание OpenMP. Программа должна сравнивать два кадра, внутри которых оба кадра должны сравниваться блок за блоком, и OpenMP должен применяться двумя способами: один, когда работа кадра должна быть разделена между потоками, а другой, где работа должна быть разделена между потоки на уровне блока, нахождение минимальной стоимости каждого сравнения.

Основная идея, лежащая в основе скелета кода, будет выглядеть следующим образом:

int main() {
  // code
  for () {
    for () {
      searchBlocks();
    }
  }
  // code
}

searchBlocks() {
  for () {
    for () {
      getCost()
    }
  }
}

getCost() {
  for () {
    for () {
      // operations
    }
  }
}

Затем, учитывая распараллеливание на уровень кадра, я могу просто изменить основной вложенный l oop на этот

int main() {
  // code
  omp_set_num_threads(threadNo);

  #pragma omp parallel for collapse(2) if (isFrame)
  for () {
    for () {
      searchBlocks();
    }
  }
  // code
}

, где threadNo указывается при запуске, а isFrame получается через параметр, чтобы указать, требуется ли распараллеливание на уровне кадра . Это работает, и время выполнения программы становится короче по мере увеличения количества используемых потоков. Однако, пытаясь распараллелить уровень блоков, я попытался сделать следующее:

getCost() {
  #pragma omp parallel for collapse(2) if (isFrame)
  for () {
    for () {
      // operations
    }
  }
}

Я делаю это в getCost(), учитывая, что это самая внутренняя функция, в которой происходит сравнение каждого соответствующего блока, но как Я делаю это, программа занимает очень много времени для выполнения, настолько, что, если бы я запускал ее без поддержки OpenMP (то есть 1 одиночный поток) против поддержки OpenMP с 10 потоками, первый завершил бы sh первым.

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

Пожалуйста, дайте мне знать, нужно ли мне объяснить это лучше, или что это такое? может измениться для успешного выполнения этого распараллеливания, и спасибо всем, кто может оказать помощь.

Ответы [ 2 ]

1 голос
/ 04 августа 2020

Помните, что каждый раз, когда ваша программа выполняет директиву #pragma omp parallel, она порождает новых потоков. Создание потоков обходится очень дорого, и, поскольку вы выполняете getCost() много-много раз, и каждый вызов не требует больших вычислительных затрат, вы в конечном итоге тратите все время на создание и присоединение потоков (что, по сути, вызывает дорогостоящие системные вызовы).

С другой стороны, когда выполняется директива #pragma omp for, она не порождает никаких потоков, но позволяет всем существующим потокам (которые порождены предыдущей директивой parallel) выполнять параллельно для отдельных фрагментов данных.

Итак, вы хотите, чтобы порождало потоки на верхнем уровне ваших вычислений, выполнив: (обратите внимание: for)

int main() {
  // code
  omp_set_num_threads(threadNo);

  #pragma omp parallel
  for () {
    for () {
      searchBlocks();
    }
  }
  // code
}

, а затем до разделить петли , выполнив (номер уведомления parallel)

getCost() {
  #pragma omp for collapse(2) if (isFrame)
  for () {
    for () {
      // operations
    }
  }
}
0 голосов
/ 04 августа 2020

Получается каскадное распараллеливание. Возьмите предельные значения в основных циклах как I, J, а в циклах getcost как K, L: вы получите потоки I * J * K * L. Здесь любая операционная система go сойдет с ума. Так что незадолго до вилки бомба добралась ...

Ну и "развал" тоже непонятно зачем. Внутри еще два цикла, и особого смысла в этом параметре я не вижу. Попробуйте убрать параллелизм в Getcost.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...