CUDA и общие переменные среди разных глобальных функций

Всего несколько сомнений по поводу CUDA. Возможно, они могут показаться глупыми вопросами; Я извиняюсь за это.

Если я объявляю переменную на GPU (например, массив alpha с N элементами, cudaMalloc((void**)&alpha, N * sizeof(double))) и выделяю ее значение в глобальной функции, не освобождая память, эта переменная должна быть доступным для других последовательных глобальных функций, верно?

Кроме того, возможно ли (или целесообразно) вычислить скалярную переменную на GPU и сделать ее общей для нескольких глобальных функций на GPU, или лучше каждый раз передавать ее в качестве аргумента от CPU?

Спасибо за внимание.


person Pippo    schedule 29.12.2012    source источник
comment
Спасибо за все ваши ответы. Я не могу вычислить весь свой проект на графическом процессоре, так как у меня рекурсивный цикл. Следовательно, моей целью было бы вычислить некоторые константные массивы на графическом процессоре вне этого цикла, не освобождая используемую память, и некоторые константные скаляры на ЦП. Затем внутри рекурсивного цикла я буду использовать глобальные функции столько, сколько смогу.   -  person Pippo    schedule 30.12.2012


Ответы (3)


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

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

person agrippa    schedule 29.12.2012
comment
Параметры ядра также хранятся в глобальной памяти, но считываются через постоянный кэш. Если параметр является указателем на массив, сам массив также можно прочитать через кэш констант, используя квалификатор const в списке параметров ядра. - person Roger Dahl; 30.12.2012

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

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

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

person saeedn    schedule 29.12.2012

Если я объявлю переменную на GPU (например, массив alpha с N элементами, cudaMalloc((void**)&alpha, N * sizeof(double))) и выделю ее значение в глобальной функции, не освобождая память, эта переменная должны быть доступны для других последовательных глобальных функций, верно?

Вы не можете вызвать cudaMalloc() из глобальной функции (ядра). Это функция хоста. Вы можете использовать malloc() и new в ядрах, но это может быть неэффективно.

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

Кроме того, возможно ли (или целесообразно) вычислить скалярную переменную на GPU и сделать ее общей для нескольких глобальных функций на GPU, или лучше каждый раз передавать ее в качестве аргумента от CPU?

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

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

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

person Roger Dahl    schedule 29.12.2012
comment
Спасибо. Насчет использования cudaMalloc() я плохо объяснил в своем вопросе, но имел в виду то, что вы говорите (т.е. выделять память на GPU в основной функции, а не в глобальной). - person Pippo; 30.12.2012