Распараллеливание OpenMP C, вложенное в медленный цикл - PullRequest
1 голос
/ 21 августа 2011

Я пытался распараллелить вложенный цикл, как показано здесь:

http://pastebin.com/nkictYsw

Я сравниваю время выполнения последовательной версии и параллельной версии этого кода, но последовательная версия всегда, кажется, имеет более короткое время выполнения с различными входными данными?

Входные данные для программы:

  • numParticles (индекс цикла)
  • timeStep (не важно, значение не меняется)
  • numTimeSteps (индекс цикла)
  • numThreads (количество потоков, которые будут использоваться)

Я посмотрел в Интернете и попробовал кое-что (сейчас), и ничего не изменилось. Я уверен, что параллельный код правильный, потому что я проверил результаты. Я что-то здесь не так делаю?

РЕДАКТИРОВАТЬ: Кроме того, кажется, что вы не можете использовать предложение сокращения для структур C?

EDIT2: Работа над gcc на linux с 2-х ядерным процессором. Я попытался запустить это со значениями, такими как numParticles = 40 и numTimeSteps = 100000. Может быть, я должен попробовать выше?

Спасибо

Ответы [ 2 ]

1 голос
/ 21 августа 2011

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

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

РЕДАКТИРОВАТЬ: я проверил ваш код с numParticles 1000 и двух потоков.Это бежало через 30 секунд.Однопоточная версия работала за 57 секунд.Даже с numParticles 40 я вижу значительное ускорение.Это Visual Studio 2010.

0 голосов
/ 21 августа 2011

Я могу подумать о двух возможных источниках замедления: а) компилятор сделал некоторые оптимизации (векторизация в первую очередь) в последовательной версии, но не в версии OpenMP, и б) накладные расходы на управление потоками.И то, и другое легко проверить, запускаете ли вы также версию OpenMP с одним потоком (т. Е. Установите для numThreads значение 1).Если это намного медленнее, чем последовательное, то (а) является наиболее вероятной причиной;если он аналогичен последовательному и быстрее, чем тот же код с 2 потоками, наиболее вероятной причиной является (b).

В последнем случае вы можете реструктурировать код OpenMP для уменьшения накладных расходов.Во-первых, наличие двух параллельных областей (#pragma omp parallel) внутри цикла не обязательно;у вас может быть одна параллельная область и два параллельных цикла внутри нее:

for (t = 0; t <= numTimeSteps; t++) {
    #pragma omp parallel num_threads(numThreads)
    {
    #pragma omp for private(j)
    /* The first loop goes here */
    #pragma omp for
    /* The second loop goes here */
    }
}

Затем параллельная область может быть запущена до цикла временного шага:

#pragma omp parallel num_threads(numThreads) private(t)
for (t = 0; t <= numTimeSteps; t++) {
    ...
}

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

...