Параллелизм в GPU - CUDA / OpenCL - PullRequest
4 голосов
/ 22 декабря 2011

У меня есть общие вопросы о параллелизме в коде CUDA или OpenCL на GPU.Я использую NVIDIA GTX 470.

Я кратко прочитал в руководстве по программированию Cuda, но не нашел соответствующих ответов, поэтому спрашиваю здесь.

У меня есть функция верхнего уровня, которая вызывает ядро ​​CUDA (длято же самое ядро, у меня есть его версия OpenCL).Эта функция верхнего уровня сама вызывается 3 раза в цикле for из моей основной функции для 3 различных наборов данных (данные изображения R, G, B), и фактический кодлет также обрабатывает все пиксели в изображении / кадретак что у него 2 «для циклов».

Что я хочу знать, так это то, какой параллелизм здесь используется - параллелизм на уровне задач или параллелизм данных?

Итак, что я хочу понять, так этосоздает ли этот код CUDA и C несколько потоков для разных функций / функций в кодлете и коде верхнего уровня, выполняет их параллельно и использует параллелизм задач.Если да, то кто его создает, поскольку нет библиотеки потоков, явно включенной в код или связанной с.

ИЛИ

Он создает потоки / задачи для различных итераций цикла for, которые являются независимыми и, таким образом,достижение параллелизма данных.Если он выполняет этот тип параллелизма, использует ли он это, просто отмечая, что разные итерации цикла не имеют зависимостей и, следовательно, могут планироваться параллельно?

Поскольку я не вижу специальных конструкций / встроенных функций компилятора (параллельных для циклов, как в openMP), которые сообщают компилятору / планировщику планировать такие циклы / функции параллельно?

Любое чтениематериал поможет.

Ответы [ 3 ]

6 голосов
/ 22 декабря 2011

Параллелизм на графических процессорах - это SIMT (однорядная многопоточность).Для ядер CUDA вы указываете сетку блоков, где каждый блок имеет N потоков.Библиотека CUDA выполняет всю работу, а CUDA Compiler (nvcc) генерирует код графического процессора, который выполняется графическим процессором.Библиотека CUDA сообщает драйверу графического процессора и, более того, планировщику потоков на графическом процессоре, сколько потоков должно выполнять ядро ​​((количество блоков) x (количество потоков)).В вашем примере функция верхнего уровня (или функция хоста) выполняет только вызов ядра, который является асинхронным и немедленно возвращается.Библиотека потоков не нужна, поскольку nvcc создает вызовы для драйвера.

Пример вызова ядра выглядит следующим образом:

helloworld<<<BLOCKS, THREADS>>>(/* maybe some parameters */);

OpenCL следует той же парадигме, но вы компилируете ядро ​​(если онине скомпилированы) во время выполнения.Укажите количество потоков для запуска ядра, а библиотека сделает все остальное.

Лучший способ изучить CUDA (OpenCL) - посмотреть в Руководстве по программированию CUDA ( OpenCL).Руководство по программированию ) и посмотрите примеры в GPU Computing SDK .

2 голосов
/ 29 декабря 2011

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

Чтобы получить параллелизм задач, вы должны сделать это вручную - в Cuda это понятие называется потоками, а в очередях команд OpenCL.Без явного создания нескольких потоков / очередей и планирования каждого ядра в свою очередь, они будут выполняться последовательно (есть функция OpenCL, позволяющая очереди работать не по порядку, но я не знаю, поддерживает ли какая-либо реализация это.) Однако параллельное выполнение ядер, вероятно, не принесет особой пользы, если каждый набор данных достаточно велик, чтобы использовать все ядра графического процессора.

Если в ваших ядрах есть фактические циклы for, они сами по себе не будут распараллелены.параллелизм возникает из-за указания размера сетки, в результате чего ядро ​​будет вызываться параллельно для каждого элемента в этой сетке (поэтому, если у вас есть циклы внутри вашего ядра, они будут выполняться полностью каждым потоком ).Другими словами, вы должны указывать размер сетки при вызове ядра, а внутри ядра использовать threadIdx / blockIdx (Cuda) или getGlobalId () (OpenCL), чтобы определить, какой элемент данных обрабатывать в этом конкретном потоке.

Полезной книгой для изучения OpenCL является Руководство по программированию OpenCL , но также стоит посмотреть спецификацию OpenCL .

2 голосов
/ 25 декабря 2011

Что я хочу знать, так это то, какой параллелизм здесь используется - параллелизм на уровне задач или параллелизм данных?

Преимущественно параллелизм данных, но есть и некоторый параллелизм задач.

В вашем примере обработки изображений ядро ​​может выполнить обработку для одного выходного пикселя. Вы бы указали OpenCL или CUDA запускать столько потоков, сколько пикселей в выходном изображении. Затем он планирует эти потоки для запуска на GPU / CPU, на который вы ориентируетесь.

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

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

...