Простым решением было бы разделить проблему на 2 ядра:
Сокращение ядра
- Разделите ваш массив на куски по
N * M
элементов в каждом где N
- количество рабочих элементов в группе, а M
- количество элементов массива, обработанных каждым рабочим элементом. - Каждый рабочий элемент вычисляет
min()
и * 1014. * из M
элементов. - В рабочей группе выполните параллельное сокращение из
min
и max
по N
рабочим элементам, чтобы получить минимум / max для каждого чанка. - Получив эти значения, один из элементов в группе может использовать атомику для обновления глобальных значений min / max. Учитывая, что вы используете float, вам нужно будет использовать хорошо известный обходной путь для отсутствия операций атома c min / max / CAS на float.
Приложение
- После того, как ваше первое ядро завершено, вы знаете, что глобальные минимальные и максимальные значения должны быть правильными. Вы можете вычислить свой масштабный коэффициент и смещение нормализации, а затем запустить столько рабочих элементов, сколько в вашем массиве есть элементов, чтобы умножить / добавить каждый элемент массива для его корректировки.
Настройте свои значения для N и M, чтобы найти оптимальный вариант для конкретной реализации OpenCL и комбинации оборудования. (Обратите внимание, что M = 1
может быть оптимальным, т. Е. Запуск прямо в параллельном сокращении.)
Необходимость синхронизации между двумя ядрами не идеальна, но я действительно не вижу способа обойти это. Если у вас есть несколько независимых массивов для обработки, вы можете скрыть издержки синхронизации, отправив их все параллельно.