Я использую FFT для обработки аудио, и я придумала несколько очень быстрых способов сделать необходимое обращение битов, которые могут быть полезны для других, но из-за размера моих FFT (8192), Я пытаюсь уменьшить использование памяти / очистку кеша до размера таблиц поиска или кода и повысить производительность. Я видел много умных подпрограмм разворота битов; все они позволяют вам передавать их с любым произвольным значением и получать немного перевернутый вывод, но FFT не нуждаются в такой гибкости, поскольку они идут в предсказуемой последовательности. Сначала позвольте мне заявить, что я пытался и / или выяснил, поскольку это может быть самым быстрым на сегодняшний день, и вы можете увидеть проблему, затем я задам вопрос.
1) Я написал программу для генерации прямого, не зацикленного исходного кода x86, который можно вставить в мой FFT-код, который читает аудиосэмпл, умножает его на значение окна (это сама таблица поиска), а затем просто помещает результирующее значение в правильную бито-отсортированную позицию по абсолютным значениям в режимах адресации x86, таких как: movlps [edi + 1876], xmm0. Это самый быстрый способ сделать это для меньших размеров БПФ. Проблема заключается в том, что когда я пишу код напрямую для обработки значений 8192, код выходит за рамки размера кэша инструкций L1, а производительность падает. Конечно, в отличие от этого, таблица поиска с обращением 32K бит, смешанная с таблицей окон 32K, плюс другие вещи, также слишком велика, чтобы соответствовать кешу данных L1, и производительность снижается, но сейчас я так и делаю.
2) Я нашел шаблоны в последовательности обращения битов, которые можно использовать для уменьшения размера таблицы поиска, например, используя 4-разрядные числа (0..15) в качестве примера, последовательность обращения битов выглядит следующим образом: 0, 8,4,12,2,10,6,14 | 1,5,9,13,3,11,7,15. Первое, что можно увидеть, это то, что последние 8 чисел совпадают с первыми 8 +1, поэтому я могу нарезать свою половину LUT. Если я посмотрю на разницу между числами, то здесь будет больше избыточности, поэтому, если я начну с нуля в регистре и захочу добавить к нему значения, чтобы получить следующий битовый перевернутый номер, они будут: + 0, + 8, -4 , + 8, -10, + 8, -4, + 8 и то же самое для второй половины. Как видно, у меня может быть таблица поиска только 0 и -10, потому что + 8 и -4 всегда отображаются предсказуемым образом. Код будет развернут для обработки 4 значений в цикле: одно будет считано из таблицы поиска, а остальные 3 будут прямым кодом для +8, -4, +8, прежде чем снова зацикливаться. Затем второй цикл может обработать последовательность 1,5,9,13,3,11,7,15. Это здорово, потому что теперь я могу сократить свою таблицу поиска еще на 4 фактора. Это также увеличивает масштаб для FFT размером 8192. Теперь я могу обойтись LUT размером 4K вместо 32K. Я могу использовать тот же шаблон и удвоить размер моего кода, и снова сократить LUT еще на половину, как бы далеко я не хотел идти. Но чтобы полностью исключить LUT, я возвращаюсь к запрещенному размеру кода.
Для больших размеров БПФ, я считаю, что это решение № 2 является абсолютным самым быстрым на сегодняшний день, так как необходимо выполнить относительно небольшой процент операций чтения из справочной таблицы, и каждый алгоритм, который я в настоящее время нахожу в Интернете, требует слишком много последовательных / вычисления зависимостей, которые нельзя векторизовать.
Вопрос в том, существует ли алгоритм, который может увеличивать числа, чтобы MSB действовал как LSB и так далее? Другими словами (в двоичном виде): 0000, 1000, 0100, 1100, 0010 и т. Д. Я пытался придумать какой-то способ, и пока, за исключением нескольких вложенных циклов, я не могу найти путь для быстрого и простого алгоритма, который является зеркальным отображением простого добавления 1 к младшему разряду числа. И все же кажется, что должен быть способ.