Почему все итерации в цикле распараллелены с использованием расписания OpenMP (динамического), отданного одному потоку? (МСВС 2010)

Прямой вопрос: у меня есть простой цикл с функцией, требующей значительных вычислительных ресурсов. Предположим, что каждая итерация занимает одинаковое количество времени (поэтому балансировка нагрузки должна быть легкой).

#pragma omp parallel
{

#pragma omp for schedule(dynamic)
for ( int i=0; i < 30; i++ )
{
     MyExpensiveFunction();
}

}  // parallel block

Почему все итерации назначаются одному потоку? Я могу добавить:

std::cout << "tID = " << omp_get_thread_num() << "\n\n";

и он печатает кучу нулей, причем только последняя итерация назначена потоку 1.

Моя система: я должен поддерживать кросс-компиляцию. Итак, я использую gcc 4.4.3 и 4.5.0, и они оба работают должным образом, но для MS 2010 я вижу описанное выше поведение, когда 29 итераций назначаются потоку 0, а одна итерация назначается потоку 1.

Действительно странно. Мне потребовалось некоторое время, чтобы понять, что это может быть просто проблема с расписанием. Я погуглил и нашел этот сайт, который, если вы пропустите его вниз, содержит пример с тем, что должно быть автоматически сгенерировано. Все итерации с использованием динамического и управляемого планирования назначаются нулевому потоку??!?

Любое руководство будет с благодарностью!!


person M. Tibbits    schedule 14.11.2010    source источник


Ответы (2)


Скорее всего, это связано с тем, что реализация OMP в Visual Studio решила, что вы проделали недостаточно работы, чтобы заслуживать ее включения в более чем один поток. Если вы просто увеличите количество итераций, то вполне можете обнаружить, что другие потоки имеют большее использование. Динамическое планирование означает, что реализация разветвляет новые потоки только в том случае, если они ей нужны, поэтому, если они ей не нужны, она не заставляет их работать и не назначает их.

person Puppy    schedule 14.11.2010
comment
Я думаю, что в целом вы правы, поэтому я принял ваш ответ, но хотел добавить, что после обширного тестирования я смог определить, что отмеченное странное поведение на самом деле было связано с блокировкой моего процесса для определенного набора ядра. В Windows я использовал SetProcessAffinityMask — у меня определенно было достаточно ядер для размещения моих потоков (я вызывал omp_set_max_threads(4) на двухъядерном четырехъядерном процессоре), но по какой-то причине сходство мешало распределению OpenMP. Когда я удалил привязку (сохранив omp_set_max_threads(4)), я увидел ожидаемое распределение, которое соответствовало gcc. - person M. Tibbits; 07.12.2010
comment
@М. Тиббитс: Обычно вы упоминаете такие вещи в вопросе :P - person Puppy; 07.12.2010

  1. Если каждая итерация занимает одинаковое количество времени, то вам фактически не нужно динамическое планирование, которое вызывает больше накладных расходов, чем статические политики планирования. (статические, 1) и (статические) должны быть в порядке.

  2. Не могли бы вы сообщить мне продолжительность каждой итерации? Что касается приведенного вами примера (пример MSDN для планирования), это связано с тем, что объем работы каждой итерации настолько мал, что первый поток почти получил работу. Если реально увеличить работу каждой итерации (хотя бы на порядок миллисекунды), то вы увидите отличия.

Я провел много экспериментов, связанных с политиками планирования OpenMP. Реализация динамического планирования в MSVC работает хорошо. Я почти уверен, что ваша работа в каждой итерации была слишком маленькой.

person minjang    schedule 28.11.2010