доступ к памяти без выравнивания - PullRequest
3 голосов
/ 17 декабря 2008

Я работаю на встроенном устройстве, которое не поддерживает выравниваемый доступ к памяти.

Для видеодекодера мне нужно обрабатывать пиксели (один байт на пиксель) в блоках 8x8 пикселей. Устройство имеет некоторые возможности обработки SIMD, которые позволяют мне работать с 4 байтами параллельно.

Проблема в том, что блоки 8x8 пикселей не гарантированно запускаются по выровненному адресу, и функции должны считывать / записывать до трех из этих блоков 8x8.

Как бы вы подошли к этому, если вы хотите очень хорошую производительность? Подумав немного, я пришел к следующим трем идеям:

  1. Делать все обращения к памяти в байтах. Это самый простой способ сделать это, но медленный, и он не работает с возможностями SIMD (это то, что я сейчас делаю в своем справочном C-коде).

  2. Напишите четыре функции копирования (по одной для каждого случая выравнивания), которые загружают данные пикселей с помощью двух 32-разрядных операций чтения, сдвигают биты в правильное положение и записывают данные в какой-то выровненный фрагмент памяти памяти. Функции обработки видео могут затем использовать 32-битный доступ и SIMD. Недостаток: ЦП не сможет скрыть задержку памяти за обработкой.

  3. Та же идея, что и выше, но вместо того, чтобы записывать пиксели в чистую память, выполняйте обработку видео на месте. Это может быть самый быстрый способ, но количество функций, которые я должен написать для этого подхода, велико (наверное, около 60).

Кстати: мне придется написать все функции на ассемблере, потому что компилятор генерирует ужасный код, когда дело доходит до расширения SIMD.

Какую дорогу вы выберете, или у вас есть другая идея, как подойти к ней?

Ответы [ 5 ]

4 голосов
/ 17 декабря 2008

Вы можете использовать memcpy (который, если я помню, можно оптимизировать для выполнения копирования слов, если это возможно), чтобы копировать в выровненную структуру данных (например, что-то, выделенное в стеке или из malloc). Затем выполните обработку для этой выровненной структуры данных.

Скорее всего, вы захотите обрабатывать вещи в регистрах вашего процессора, а не в памяти. То, как вы подходите к своей задаче, зависит от возможностей аппаратного обеспечения (например, можно ли разделить 32-разрядный регистр на четыре 8-разрядных? На каких регистрах работают операции SIMD?) Если вы идете по простому маршруту, Вы можете вызвать функцию небольшого загрузчика, которая выполнит ваши невыровненные операции чтения за вас.

3 голосов
/ 30 декабря 2008

Вы должны сначала разбить ваш код на секции выборки / обработки.

Код извлечения должен копироваться в рабочий буфер и иметь случаи для памяти, которая выровнена (где вы должны быть в состоянии копировать с использованием регистров SIMD), и не выровненной памяти, где вам нужно копировать побайтово (если ваш Платформа не может сделать доступ без выравнивания, и ваш источник / назначение имеют разные выравнивания, тогда это лучшее, что вы можете сделать).

Ваш код обработки может быть SIMD с гарантией работы с согласованными данными. Для любой реальной степени обработки процесс копирования + будет определенно быстрее, чем не-SIMD-операции с невыровненными данными.

При условии, что ваш source & dest одинаковы, дальнейшая оптимизация будет заключаться в том, чтобы использовать только рабочий буфер, если источник не выровнен, и выполнять обработку на месте, если память выровнена. Преимущества этого будут зависеть от характеристик ваших данных.

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

3 голосов
/ 30 декабря 2008

Сначала выровняйте данные, а затем используйте метод выравнивания SIMD.

Это меньше работы, чем в варианте 3, и, если повезет, ваш код будет работать на максимальной скорости в 25% случаев (т.е. уже выровненный случай). Вы можете счастливо использовать код в будущем в ситуациях, когда вы знаете, , что ввод будет правильно выровнен.

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

2 голосов
/ 30 декабря 2008

Общий совет: почему бы вам не пойти с чем-то, что звучит разумно (например, № 2), а затем измерить производительность? Если это не приемлемо, вы можете вернуться к чертежной доске.

Конечно, ручная работа с 60-ю функциями в ассемблере перед измерением будет считаться «преждевременной оптимизацией». :)

2 голосов
/ 17 декабря 2008

Я бы выбрал вариант 1), пока вы не узнаете, что он слишком медленный (медленный в порядке, слишком медленный - плохой)

...