23.03.2016

И снова SSE

Пытался тут в очередной раз ускорить расчет векторного произведения для звуковых данных. С подачи Ивана в комментариях к моему посту о том, что нужно выполнять сразу четыре произведения, что должно дать существенный эффект.

Однако, для того, что бы оптимизировать, надо найти основу, с чего начинать. В качестве основы я взял, да и развернул циклы по векторному произведению для того простейшего случая, когда длина вектора равна 4. С включенным оптимизатором.

Естественно, выглядит такой код странно. Переписал его же на цикл. Скорость выполнения снизилась почти в два раза. Чему, честно сказать, я удивился. Ни конвейер, ни суперскалярная архитектура и прочие достижения современного процессоростроения ничего не смогли противопоставить старой, как мир, оптимизации в лоб.

После чего я перешел к оптимизации под SSE. Основная проблема тут состоит в том, что изначально данные расположены не так, как было бы удобно их вычислять с использованием SSE. Но так как мне было любопытно, какой выигрыш даст SSE в том случае, если данные уже расположены правильно, то я сделал вид, что они лежат типа правильно.
Результат оказался забавным. Умножение сразу четырех векторов было почти в три раза быстрее, чем скалярный расчет с использованием цикла, и всего лишь в полтора раза быстрее скалярного варианта с развертыванием циклов.

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

Но засада состоит все же в том, что в реальности данные организованы не так, как нужно для корректных вычислений. Поэтому на пути к векторизации вычислений лежит преграда в виде транспонирования векторов. Это потребует дополнительных операций и пока не понятно, даст ли в результате SSE какой-то выигрыш и если даст, то какой?

Набор команд SSE меня слегка разочаровал. Нет, конечно, очень важно сделать векторные команды. Но не менее важно иметь и команды, которые готовят данные к векторным операциям. В данном случае меня интересовали команды сбора данных из разных участков памяти в один вектор, а также команда умножения вектора на скаляр.
Первая из требуемых мне команд появилась лишь в наборе AVX2. Что касается второй команды, то ее нет вовсе. Что, в принципе понятно, так как умножение на скаляр можно заменить скалярным умножением на вектор, заполненный одним и тем же числом. Однако, такая команда, которая умеет весь вектор заполнять одним числом, также появляется лишь в AVX2.
Беда же состоит в том, что мой процессор, хоть и не самый старый, тем не менее AVX2 не поддерживает. Поэтому вкусить немного радости от его использования не удалось. Пришлось ограничится скалярным вариантом. В этом и состоит разочарование и вопрос: неужели в большинстве прикладных задач, требующих векторных вычислений, данные уже лежать так, как надо?

В результате выигрыш от векторизации есть. И для случая векторного произведения он составляет целых 21.5%!
Вот более детальные результаты:
ТестРезультат, такты
Развернутый скалярный цикл642
Скалярный цикл1149
SSE с формирование вектора из скаляра436
SSE с использованием готового вектора, сформ. из скаляра425
SSE+Транспонирование с формирование вектора из скаляра504
SSE+Транспонирование с использованием готового вектора, сформ. из скаляра630


Хотя, возможно, я просто не умею их готовить (вектора в смысле)?

На всякий случай выложу фрагмент кода, с помощью которого получил указанные выше результаты. Код писан для случая wavelet-преобразования, поэтому на самом деле рассчитывается V1*V2 и V1*V3, то есть реально рассчитывается 8 векторных произведений, каждый вектор длиной 4.

22.03.2016

Арифметическое кодирование

Дабы усилить качество сжатия звука, решил попробовать вместо Хаффмана использовать арифметическое кодирование с динамической моделью. Использование динамической модели позволяет отказаться от хранения словаря вместе со сжатыми данными.
Сначала, правда, пришлось много повозиться с упрощением для максимальной эффективности кодера, переписанного мною на основе курсовой Александра Шендрикова много-много лет назад.

В общем, использование арифметического кодирования дает определенные преимущества по степени сжатия по сравнению с Хаффманом. Но платой за это является существенно более медленная работа. По скорости пока их не сравнивал. Зато можно сравнить по объему при прочих равных.
При размере окна кодирования 44100 отсчетов выигрыш арифметического кодирования составил 3%. При более мелком окне (1764 отсчетов) выигрыш значительнее и составляет  12.8%. Это за счет того, что не хранится словарь.

На текущий момент самый большой достигнутый мною коэффициент сжатия аудиоданных (правда, на одном и том же музыкальном файле) без заметных на мой слух искажения, составил 1/7 - 1/7.5. В данном случае не используется какая-либо психоакустическая модель. Если добавить ее, то, наверное, удастся приблизится к коэффициенту сжатия MPEG.
Но без использования психоакустической модели зато получается более точная фазовая картина звука и не забиваются тихие участки на фоне/после громких. Так что в каких-то специальных случаях такой подход может быть более полезен.