Вопрос о распределении памяти в ядре CUDA - PullRequest
0 голосов
/ 13 мая 2011

Привет, у меня есть массив размером SIZE*sizeof(double) на моем хосте.Я выделяю указатель устройства размером с хост-массив и копирую массив на устройство.Теперь я передаю этот массив устройств dev_point в функцию ядра.Каждым потокам необходимо изменить некоторые значения переданного массива, а затем вычислить другую _device__ -функцию с новыми значениями массива (различными для каждого потока).Теперь интересно, как это сделать?До того, как у меня была полная CPU-версия (серийный код) моей программы, я просто всегда создавал новый массив, такой как double new_array[ SIZE ], и затем копировал в него данные из исходного массива, изменял его и затем снова удалял.Но как это сделать в CUDA, поскольку я не могу выделить память внутри функции ядра.Есть ли возможность использовать «локальную» память потока для хранения нового массива?Или мне нужно выделить большой массив размером SIZE * number_of_total_threads * sizeof(double) перед вызовом функции ядра, чтобы каждый поток мог хранить в нем измененный массив?Заранее большое спасибо!

РЕДАКТИРОВАТЬ: ПОЛНОЕ ОПИСАНИЕ! Хорошо, вот лучшее описание проблемы для моего «текущего» случая: в моей хост-программе у меня есть массив, скажем, с 300 значениями(в зависимости от пользовательского ввода от 100 до 400, давайте назовем эту переменную numValues, размер которой зависит от параметров программы, а не жестко запрограммирован в программе!) - удваивается.Теперь я хочу, чтобы каждое ядро-выполнение занимало именно этот массив (он фактически копируется в GPU и передается в функцию ядра в качестве указателя), изменяет значение на n-й элемент (n = уникальный идентификатор, который изменяется от 0 до numValues), тогда как все остальные элементы массива остаются прежними.Модификация представляет собой простое добавление определенного постоянного значения, которое также передается в программу пользователем.И затем вызвать функцию, которая определена так: __device__ double thefunction(double *ary), передав модифицированный массив .

Итак, первое решение, о котором я подумал, было то, о котором я просил: дать каждому потоку (каждому выполнению ядра) собственную копию массива (я думал, что это можно сделать локально, но, очевидно, не может, потому что numValues зависит от времени выполнения), а затем пусть каждый поток изменяет значение n и вычисляет thefunction с ним.

Теперь, когда я писал здесь, у меня возникла еще одна идея: возможно, было бы лучше иметь массив в постоянной или разделяемой памяти ONCE, чтобы каждый поток передавал массив как неизмененный массив в thefunctionно указывает в качестве дополнительных параметров к thefunction индекс int idx о том, какой элемент нужно изменить, и другой параметр double *add о значении, которое нужно добавить к idx -ому элементу.Единственное, что меня интересует, это: Как добавить значение *add к idx -ому элементу без изменения массива ary, переданного в функцию, потому что это передается как указатель, и я неНе хотите изменять оригинал!

Спасибо!

Ответы [ 2 ]

1 голос
/ 13 мая 2011

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

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

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

1 голос
/ 13 мая 2011

Если массив будет использоваться одним потоком графического процессора, вы можете выделить его в локальной или глобальной памяти.Локальная память объявляется внутри функции ядра и работает точно так же, как и объявление локальной переменной в C. Вы можете использовать локальную память, только если SIZE является целочисленной константой, а не значением времени выполнения.В противном случае вам придется использовать глобальную память.Чтобы использовать глобальную память, как вы сказали, выделите большой массив.Каждый поток будет вычислять смещение в большом массиве, который он будет использовать в качестве своего частного массива.

Однако вам следует подумать о реорганизации алгоритма на графическом процессоре.В отличие от процессора, где один поток может использовать большой кэш, встроенная память на графическом процессоре разделяется сотнями потоков.Недостаточно встроенной памяти для каждого потока, чтобы иметь большой частный массив, а внешняя память слишком медленная, чтобы быть полезной.(Например, типичное ядро ​​в архитектуре G80 будет иметь 256 потоков, использующих 16 КБ разделяемой памяти, что ограничивает максимальный размер массива 64 байтами.) Возможно ли распараллелить вычисление частного массива?

...