Разница между построением ядер и параллельным построением

Я изучаю много статей и руководство по OpenACC, но до сих пор не понимаю основного различия этих двух конструкций.


person pg1927    schedule 19.11.2012    source источник


Ответы (3)


Директива kernels - это более общий случай, о котором вы, вероятно, могли бы подумать, если ранее писали ядра GPU (например, CUDA). kernels просто указывает компилятору работать с фрагментом кода и производить произвольное количество «ядер» произвольной «размерности», которые должны выполняться последовательно, чтобы распараллелить / выгрузить конкретную часть кода на ускоритель. Конструкция parallel позволяет более детально управлять тем, как компилятор будет пытаться структурировать работу на ускорителе, например, путем указания конкретных размеров распараллеливания. Например, количество рабочих и групп обычно будет постоянным как часть директивы parallel (поскольку обычно подразумевается только одно базовое «ядро»), но, возможно, не в директиве kernels (поскольку это может быть преобразовано в несколько базовых «ядер» ).

Хороший ответ на этот конкретный вопрос содержится в этой статье о PGI.

Цитата из резюме статьи: «Каждое ядро ​​OpenACC и параллельные конструкции пытаются решить одну и ту же проблему, идентифицируя параллелизм цикла и отображая его на машинный параллелизм. в соответствии с требованиями целевого ускорителя. Параллельная конструкция является более явной и требует от программиста более тщательного анализа, чтобы определить, когда она является законной и уместной ".

person Robert Crovella    schedule 20.11.2012
comment
С GCC parallel реализовано намного лучше. Насколько я могу судить, reduction не поддерживается kernel в GCC. - person Z boson; 12.03.2018

Директивы OpenACC и ядра графического процессора - это всего лишь два способа представления одного и того же - раздела кода, который может выполняться параллельно.

OpenACC может быть лучшим вариантом при модернизации существующего приложения для использования преимуществ графического процессора и / или когда желательно позволить компилятору обрабатывать больше деталей, связанных с такими проблемами, как управление памятью. Это может ускорить написание приложения с потенциальными потерями в производительности.

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

Я думаю, что у людей, плохо знакомых с графическими процессорами, может возникнуть соблазн перейти на OpenACC, потому что он выглядит более знакомым. Но я думаю, что на самом деле лучше пойти другим путем и начать с написания ядер, а затем, возможно, перейти на OpenACC, чтобы сэкономить время в некоторых проектах. Причина в том, что OpenACC - это дырявая абстракция. Таким образом, хотя OpenACC может выглядеть так, как будто детали графического процессора абстрагированы, они все еще существуют. Таким образом, использование OpenACC для написания кода графического процессора без понимания того, что происходит в фоновом режиме, скорее всего, разочарует, с появлением странных сообщений об ошибках при попытке компиляции и приведет к тому, что приложение будет иметь низкую производительность.

person Roger Dahl    schedule 19.11.2012
comment
Этот ответ, похоже, отвечает на вопрос, каковы причины использовать или не использовать OpenACC, игнорируя вопрос OP, который связан с различением двух немного разных способов попросить компилятор OpenACC сгенерировать код GPU для региона. Кроме того, цитируется ссылка на статью. Все нетривиальные абстракции в какой-то степени нечеткие. Итак, критика ограниченной глубины ИМХО. Я полагаю, что лучше предположить, что этот плакат знает, как программировать графические процессоры, и на самом деле его интересуют синтаксические и функциональные различия между двумя указанными языковыми конструкциями. - person Robert Crovella; 20.11.2012
comment
Возможно, я действительно ответил не на тот вопрос. Я не знал, что OpenACC тоже имеет концепцию ядра. Я думал, что все дело в директивах, вроде OpenMP. - person Roger Dahl; 20.11.2012
comment
@RogerDahl - kernels - это директива, определенная стандартом OpenACC. Он также включает директиву parallels. - person Mark Ebersole; 14.01.2013

Параллельная конструкция

  1. Определяет область программы, которая должна быть скомпилирована для параллельного выполнения на устройстве-ускорителе.

  2. Директива параллельного цикла - это утверждение программиста о том, что распараллеливание затронутого цикла безопасно и желательно. Это требует от программиста правильного определения параллелизма в коде и удаления из кода всего, что может быть небезопасно для распараллеливания. Если программист неверно утверждает, что цикл может быть распараллелен, результирующее приложение может дать неверные результаты.

  3. Параллельная конструкция позволяет более детально контролировать то, как компилятор будет пытаться структурировать работу на ускорителе. Таким образом, он не сильно зависит от способности компилятора автоматически распараллеливать код.

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

  5. Более опытные параллельные программисты, которые, возможно, уже определили параллельные циклы в своем коде, вероятно, сочтут подход параллельного цикла более желательным.

например, ссылка

#pragma acc parallel
{
    #pragma acc loop
    for (i=0; i<n; i++) 
         a[i] = 3.0f*(float)(i+1);
    #pragma acc loop
    for (i=0; i<n; i++) 
         b[i] = 2.0f*a[i];
}

 Сгенерировать одно ядро

 Между двумя петлями нет барьера: второй цикл может начаться до того, как закончится первый. (Это отличается от OpenMP).

Конструкция ядра

  1. Определяет область программы, которая должна быть скомпилирована в последовательность ядер для выполнения на устройстве-ускорителе.

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

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

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

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

например, ссылка

#pragma acc kernels
{
   for (i=0; i<n; i++)
       a[i] = 3.0f*(float)(i+1);
   for (i=0; i<n; i++)
        b[i] = 2.0f*a[i];
}

 Создайте два ядра

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

person Gambitier    schedule 29.12.2019