Когда я должен использовать DO CONCURRENT и когда OpenMP?

Мне известно об этом и это, но я спрашиваю еще раз, так как первая ссылка уже довольно старая, а вторая ссылка, похоже, не привела к окончательному ответу. Сформировался ли какой-либо консенсус?

Моя проблема проста:

У меня есть цикл DO с элементами, которые могут выполняться одновременно. Какой метод я использую?

Ниже приведен код для создания частиц на простой кубической решетке.

  • npart — количество частиц
  • npart_edge и npart_face — вдоль ребра и грани соответственно.
  • space – шаг решетки
  • Rx, Ry, Rz — массивы позиций
  • x, y, z — временные переменные для определения положения на решетке.

Обратите внимание на разницу в том, что x,y и z должны быть массивами в случае CONCURRENT, но не в случае OpenMP, потому что они могут быть определены как PRIVATE.

Итак, я использую DO CONCURRENT (который, как я понял из приведенных выше ссылок, использует SIMD):

DO CONCURRENT (i = 1, npart)
    x(i) = MODULO(i-1, npart_edge)
    Rx(i) = space*x(i)
    y(i) = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y(i)
    z(i) = (i-1) / npart_face
    Rz(i) = space*z(i)
END DO

Или я использую OpenMP?

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(x,y,z)
!$OMP DO
DO i = 1, npart
    x = MODULO(i-1, npart_edge)
    Rx(i) = space*x
    y = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y
    z = (i-1) / npart_face
    Rz(i) = space*z
END DO
!$OMP END DO
!$OMP END PARALLEL

Мои тесты:

Размещение 64 частиц в коробке со стороной 10:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  6.870000000000001E-003
Real time =  3.600000000000000E-003

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  6.699999999999979E-005
Real time =  0.000000000000000E+000

Размещение 100000 частиц в коробке со стороной 100:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  8.213300000000000E-002
Real time =  1.280000000000000E-002

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  2.385000000000000E-003
Real time =  2.400000000000000E-003

Использование конструкции DO CONCURRENT, по-видимому, дает мне как минимум на порядок лучшую производительность. Это было сделано на i7-4790K. Кроме того, преимущество параллелизма, по-видимому, уменьшается с увеличением размера.


person physkets    schedule 24.07.2016    source источник
comment
Утверждение о том, что x, y и z должны быть массивами в случае DO CONCURRENT, не является требованием языка. То, как реализуется DO CONCURRENT, также во многом зависит от возможностей компилятора — ленивые компиляторы могут просто реализовать его как обычный последовательный цикл без какой-либо векторизации или распараллеливания. Так что ответ... Это зависит.   -  person IanH    schedule 24.07.2016
comment
@IanH Что вы имеете в виду, когда говорите, что это не требование языка? Я говорю, что они должны быть массивами, потому что в противном случае эти операции не могут выполняться одновременно. Кроме того, я добавил в качестве редактирования информацию о производительности.   -  person physkets    schedule 24.07.2016
comment
Так в чем вопрос сейчас? DO CONCURRENT против OpenMP в целом? Или как заставить этот фрагмент кода работать быстрее? Это ОЧЕНЬ разные вопросы. Общий ответ, конечно, использовать то, что быстрее.   -  person Vladimir F    schedule 24.07.2016
comment
И я не понимаю, почему вы вообще используете REDUCTION.   -  person Vladimir F    schedule 24.07.2016
comment
А 64 частицы — это очень мало. Для потоков у вас должно быть 10000 или 1000000. Запуск потока только для 8 частиц 8 - это шутка. Вы также должны синхронизировать соответствующий цикл.   -  person Vladimir F    schedule 24.07.2016
comment
Вопрос в том, чтобы понять, какие обстоятельства благоприятствуют одному по сравнению с другим. О, правда, ты прав. РЕДУКЦИЯ здесь не нужна; позвольте мне проверить с его удаленным. Я только синхронизирую соответствующий цикл.   -  person physkets    schedule 24.07.2016
comment
Семантика DO CONCURRENT не требует, чтобы эти переменные были массивами. На переменную можно ссылаться в итерации, если она была определена ранее в той же итерации или не определена ни в одной итерации (F2008 8.1.6.7p1). Если компилятор должен выполнять цикл одновременно (это не обязательно), то он должен провести необходимый анализ, чтобы определить, что переменная, которая определена, а затем используется в итерации, должна быть эквивалентной OpenMP PRIVATE.   -  person IanH    schedule 24.07.2016
comment
Проверяется без предложения REDUCTION. Не большая разница.   -  person physkets    schedule 24.07.2016
comment
@IanH, все, что я говорю, это то, что здесь. в этом случае, чтобы они были эквивалентом PRIVATE, они должны быть массивами. Я не делаю общее заявление. Если бы это было не так, одновременные операции здесь были бы невозможны. Вы не согласны?   -  person physkets    schedule 24.07.2016
comment
Я не согласен. Язык не требует, чтобы эти переменные были массивами. Внимательно прочитайте семантику DO CONCURRENT в стандарте Fortran 2008, а также исправления. DO CONCURRENT был несколько неудачно назван — на самом деле это не означает и не требует, чтобы итерации выполнялись одновременно.   -  person IanH    schedule 24.07.2016
comment
@IanH хорошо, я прочитал это и теперь понял. Таким образом, все это означает, что процессору разрешено выполнять итерации в произвольном порядке, который может быть или не быть параллельным. Это действительно случай плохого именования.   -  person physkets    schedule 24.07.2016
comment
Просто потому, что у нас есть блестящая новая функция: некоторая документация из do concurrent.   -  person francescalus    schedule 24.07.2016


Ответы (1)


DO CONCURRENT не выполняет распараллеливания как такового. Компилятор может решить распараллелить его с помощью потоков или использовать SIMD-инструкции. Для потоков вам часто приходится указывать это делать. Или (часто!) он просто рассматривает его как обычный DO и использует SIMD, если он будет использовать их для обычного DO.

OpenMP — это не просто потоки, компилятор может использовать SIMD-инструкции, если захочет. Также есть директива omp simd, но это всего лишь предложение компилятору использовать SIMD, его можно игнорировать.

Надо пробовать, мерить и смотреть. Однозначного ответа нет. Даже не для данного компилятора, тем более для всех компиляторов.

Моя практика заключается в использовании OpenMP и попытке убедиться, что компилятор векторизует (SIMD) то, что он может. Тем более, что я все равно использую OpenMP во всей своей программе. DO CONCURRENT еще должен доказать, что он действительно полезен. Я еще не убежден.

person Vladimir F    schedule 24.07.2016
comment
Я добавил информацию, которую вы запросили ранее, в качестве редактирования. Кроме того, я использую openmp в другом месте своего кода, но там параллелизм не поможет. - person physkets; 24.07.2016
comment
ifort -qparallel запрашивает распараллеливание do concurrent. С параметрами, указанными выше, будет только симд-векторизация, которая кажется более эффективной для вашего размера задачи. Если длина вашего внутреннего цикла не превышает 100, разделение его на фрагменты с нитями устранит большую часть преимуществ векторизации simd. BLOCK можно использовать внутри DO CONCURRENT, чтобы избежать создания массивов для локальных переменных. - person tim18; 24.07.2016
comment
Предполагая, что вы работаете с включенными гиперпотоками, вам нужно будет проверить параллельную производительность с меньшим количеством потоков, чем по умолчанию, установив OMP_PLACES=cores, прежде чем вы сделаете вывод, что параллельная работа слишком неэффективна. Нет особых оснований ожидать, что параллельный автоматический параллелизм будет работать иначе, чем OpenMP. - person tim18; 24.07.2016
comment
@ tim18 Лучший комментарий под вопросом. Этот ответ был написан до того, как были раскрыты подробности, и совсем их не отражает. - person Vladimir F; 24.07.2016
comment
@tim18 tim18 Значит, если я помещу BLOCK в цикл DO, локальные переменные каждой итерации будут независимыми? Это более эффективно, чем создание массива? Кроме того, почему я должен настроить omp, чтобы не использовать гиперпотоки? - person physkets; 24.07.2016
comment
@physkets Было бы лучше обсудить это под вопросом, а не под этим ответом. Объявление его в блоке будет иметь тот же эффект, что и объявление в начале процедуры, а затем преобразование его в private. С массивом вы рискуете ложным обменом en.wikipedia.org/wiki/False_sharing - person Vladimir F; 24.07.2016
comment
@physkets А почему не гиперпотоки? Потому что это часто замедляет код. Если у вас 4 ядра, использование 8 гиперпотоков волшебным образом не принесет новых ядер. Это сложная тема. Пожалуйста, не обсуждайте это здесь. Задайте полный вопрос, если хотите. Если я удалю свой ответ, все эти комментарии исчезнут. - person Vladimir F; 24.07.2016
comment
@VladimirF Может ли мод скопировать и вставить туда эти комментарии? - person physkets; 25.07.2016
comment
Нет, никто не может. Комментарии не предназначены для того, чтобы нести важную информацию и выживать здесь. - person Vladimir F; 25.07.2016