Ветвление opencl против избыточности памяти
Я обрабатываю элементы в сетке, в зависимости от типа элемента должен выполняться другой тип вычисления / функции. Но я читал, что ветвление - очень плохая вещь, когда рабочие элементы делают одно и то же. Чтобы обойти это, я мог бы разделить сетку на сетку для каждого типа (в этом конкретном случае мне понадобилось бы только две)...
Что было бы лучше в этом случае; Оставить там ветвление или сделать две сетки по одному для каждого типа? Я понимаю, что это зависит от того, что происходит внутри ветви (вычислительная граница) и от того, насколько большими будут сетки (граница памяти / задержки).
Существуют ли основные правила, которым нужно следовать для такого рода решений, или существует консенсус, какое из них лучше в целом?
Редактировать: (пространственная) сетка не редкая, как обычно с пространственными сетками, но плотный массив (без пустых элементов) структур (~200 байт на структуру), который будет содержать до 500.000 элементов.
Я заполняю этот массив из другого источника, используя этот источник, я помещаю в него либо треугольники, либо сегменты линий.
Затем, используя эту сетку, мне нужно будет обнаружить столкновение сегмента линии / сегмента или сегмента линии / треугольника. Таким образом, вопрос заключается в том, будет ли эффективнее заполнить два отдельных массива (в качестве аргумента, скажем, 250 000 элементов x 200 байтов) в этом случае, и чтобы рабочие элементы выполняли пакетные вычисления только для линии / линии или линии / треугольника... или один большой из 500.000x200 байтов, и каждый рабочий элемент должен выяснить, какое вычисление выполнить для данного типа.
2 ответа
Это зависит от структуры ваших новых сеток, а также вашей старой.
Давайте возьмем наихудший случай. Нормальная прямоугольная сетка (например, изображение) Если каждый нечетный элемент имеет тип 1, а каждый четный - тип 2. Теперь в основном половина ваших потоков будет бездействовать в графическом процессоре (в то время как тип1 подсчитывается для потоков типа 2 как "бездействующие"). Это потому, что элементы в рабочей группе обычно используют общий счетчик программ.
Если ваши новые сетки - это два вызова ядра и просто "не типа 2? Return", то это хуже, чем в первом случае. Однако, если вам удастся создать 2 сетки, на которых каждый элемент имеет правильный тип, то лучше разделить его.
Если ваша исходная сетка имеет изображение с точными 2 половинами, это, вероятно, не имеет значения. Только группы в пределах границы будут выполнять дополнительную работу.
Ветви не так уж и плохи. Просто подумайте, что всякий раз, когда у вас есть ветвь и даже один поток в рабочей группе (или что-то еще, что является единицей планирования в вашем HW), идет направление, отличное от других, весь код в обеих ветвях будет взят везде.
Это также является причиной того, что оптимизации, такие как не выполнение дорогостоящих вычислений, если применяются какие-то особые условия, в целом не работают на GPU, потому что, если другие потоки не выполняют условие, вы все равно будете эффективно вычислять его в каждом потоке.
Там нет общего правила для этого, зависит от случая. Если вы разбираетесь в большом количестве кода, очевидно, что перестановка памяти лучше. Однако если в вашей ветке всего 2 инструкции, то не меняйте память.
Сначала я бы классифицировал количество элементов каждого типа (на стороне процессора или простого ядра) и запускал конкретное ядро для каждого типа элементов. Однако это не может быть хорошо для вашего случая.
Если вы можете опубликовать некоторый код, возможно, мы сможем указать вам правильное направление.