OpenCL: как использовать локальную память в JOCL - PullRequest
1 голос
/ 07 января 2012

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

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

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

Итак, предположив, что я прав в отношении скорости чтения локального или частного, как я это делаю на практике? Например, если для упрощения я уменьшаю график до int[] from и int[] to (сохраняя начало и конец каждого направленного ребра), я, конечно, могу заставить ядро ​​выглядеть так

computeMe(__local const int *to, __local const int *from, __global int *result) {
     //...
}

но я не понимаю, как я должен вызывать это из JOCL, так как здесь не указан модификатор private / local / global.

Будут ли локальные переменные автоматически записываться в память каждой локальной рабочей группы? Или как это работает? Мне совсем не понятно, как мне правильно делать это назначение памяти.

Ответы [ 2 ]

3 голосов
/ 09 января 2012

Вы не можете передавать значения для аргументов локальной памяти с хоста.Хост не может читать / записывать локальную память.Чтобы использовать локальную память, вам все равно необходимо передать данные как глобальные, а затем скопировать их из глобальной в локальную, прежде чем использовать их.Это полезно, только если вы читаете данные много раз.

Как насчет постоянной памяти?Если ваши входные данные не меняются и они не слишком велики, размещение ваших входных данных в постоянной памяти может значительно ускорить процесс.Доступная постоянная память обычно составляет от 16K до 64K.

computeMe(__constant int *to, __constant int *from, __global int *result) {
 //...
}

Редактировать (добавить ссылки):

Пример использования __local памяти в OpenCL см. здесь .

Для оборудования NVidia более подробная информация о производительности Руководство по передовым методам NVidia OpenCL (PDF) .Там больше информации о различиях в производительности между типами памяти.

1 голос
/ 11 мая 2013

Вы написали, что «размещение графика в глобальной памяти, по-видимому, исключено из соображений скорости».- ну, у вас нет много других вариантов.Я имею в виду, что данные в общем случае находятся в глобальной памяти.

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

Хорошо,в качестве совета, сначала попробуйте просто использовать «глобальную память».Время жизни локальной памяти - только во время выполнения ядра.Это оправдано только в том случае, если вы повторно используете один и тот же элемент данных более одного раза (представьте, что это кэш-память, в которую вы явно загружаете предварительно).

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

В вашем представлении вы можете разбить ребра (от [] до []) на группы фиксированного размера.

универсальныйшаблон

шаг 1. копирование из глобального в локальное

your_local_array [get_local_id (0)] = input_global_mem [get_global_id (0)]

шаг 2. убедитесь, что каждый потоктеперь выполняет операционный барьер (локальный забор)

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

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

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

...