Вы можете сделать это с SIMD, но как быстро это будет зависеть от того, какие именно наборы инструкций у вас есть, и насколько вы умны в своей реализации.
Один из подходов состоит в том, чтобы взять массив и «просеять» его, чтобы выделить элементы, которые принадлежат разным сегментам.Например, возьмите 32 байта из вашего массива, который будет иметь 16 16-битных элементов.Используйте некоторые инструкции cmpgt
, чтобы получить маску, в которой определяется, попадает ли каждый элемент в корзину 00 + 01
или 02 + 03
.Затем используйте какую-либо операцию «сжатия» или «фильтрации», чтобы переместить все маскированные элементы непрерывно в один конец регистра, а затем то же самое для немаскированных элементов.
Затем повторите это еще раз, чтобы отсортировать 00
из 01
и 02
из 03
.
С AVX2 вы можете начать с этого вопроса для вдохновения в операции «компресс».С AVX512 вы можете использовать инструкцию vcompress
, чтобы помочь: он выполняет именно эту операцию, но только с 32-битной или 64-битной гранулярностью, поэтому вам нужно будет выполнить пару по крайней мере для каждого вектора.
Вы также можете попробовать вертикальный подход, при котором вы загружаете N векторов, а затем переключаетесь между ними, чтобы 0-й вектор имел наименьшие элементы и т. Д. На этом этапе вы можете использовать более оптимизированный алгоритм для этапа сжатия (например, еслиВы сортируете по вертикали достаточно векторов, векторы на концах могут полностью начинаться с 0x00
и т. д.)
Наконец, вы также можете рассмотреть возможность организации ваших данных по-другому, либо в источнике, либо в качестве этапа предварительной обработки.: выделение байта категории, который всегда равен 0-3, из байта полезной нагрузки.Многие этапы обработки должны выполняться только на одном или другом, так что вы можете потенциально повысить эффективность, разделив их таким образом.Например, вы можете выполнить операцию сравнения на 32 байтах всех категорий, а затем выполнить операцию сжатия на 32 байтах полезной нагрузки (по крайней мере, на последнем этапе, где каждая категория уникальна).
Это привело бы к массивам байтовых элементов, а не 16-битных элементов, где байт "категории" неявен.Вы сократили размер данных вдвое, что может ускорить все остальное, что вы хотите сделать с данными в будущем.
Если вы не можете создать исходные данные в этом формате, вы можете использоватьbucketing как возможность удалить байт тега, когда вы помещаете полезную нагрузку в правильное ведро, так что вывод равен uint8_t out[4][2048];
.Если вы делаете SIMD-левый пакет с байтовым перемешиванием pshufb
, как описано в комментариях, вы можете выбрать вектор управления перемешиванием, который упаковывает только байты полезной нагрузки в младшую половину.
(до AVX512BWВ x86 SIMD нет тасования слов с переменным управлением, только байт или двойное слово, поэтому вам уже понадобился тасование байтов, которое может так же легко отделить полезные данные от тегов одновременно с упаковкой байтов полезных данных в нижнюю часть.)