Динамическое размещение объектов с выровненными элементами — возможные решения?

Я рассматриваю возможность использования SSE для ускорения некоторого кода в моем проекте. Обычно для этого требуется 16-байтовое выравнивание данных, над которыми я работаю. Для статического распределения я полагаю, что __declspec(align(16)) решает проблему, но моя проблема заключается в следующем: как лучше всего убедиться, что это так при выполнении динамических распределений? Особенно в тех случаях, когда выделенный объект не требует выравнивания напрямую, но использует объекты с требованием выравнивания в качестве членов (таким образом, гораздо проще забыть о том, чтобы убедиться, что он правильно выровнен). Я придумал следующие решения:

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

  2. Будьте очень осторожны и используйте только _aligned_malloc/_aligned_free для выделения любого объекта, требующего выравнивания, и любого объекта, который использует их в качестве членов. Это, вероятно, очень легко забыть и, следовательно, подвержено ошибкам.

  3. Перегружайте new/delete глобально и/или создавайте собственные функции malloc/free, которые выравнивают память, а затем используют их для всего. Однако, вероятно, не лучшая идея буквально выравнивать все, что выделяется динамически.

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

  5. Какой-то другой способ, о котором я не подумал или не знаю?

Варианты 1.-3. вероятно, не самые лучшие идеи. А 4.? Я ошибаюсь в чем-либо, что я упомянул? Предложения, мнения, полезные ссылки по этой теме?

Заранее спасибо :)


person Curious Cpp User    schedule 09.02.2012    source источник
comment
Почему бы вам просто не выровнять членов, которые в этом нуждаются? Облегчает жизнь.   -  person Xeo    schedule 09.02.2012
comment
Если я правильно вас понимаю (и то, как работает __declspec(align) или подобное), то это мало что изменит. Если бы у меня был класс Foo, который нужно выровнять, я бы использовал __declspec(align(16)) в его определении, что правильно выровняло бы его для всех static распределений без необходимости явного выравнивания при использовании в качестве члена класса Bar. Однако это ничего не меняет для динамического распределения, и мне пришлось бы использовать одно из решений, которые я упомянул как для Foo, так и для Bar, а также для любого другого класса, который использует любой из них в качестве членов.   -  person Curious Cpp User    schedule 09.02.2012


Ответы (2)


В Windows malloc выравнивается по 16 байтам (msdn). Если ваша платформа malloc имеет более низкие требования к выравниванию, вам необходимо использовать выровненные версии malloc для объектов, используемых SSE.

РЕДАКТИРОВАТЬ: Если у вас есть определенный класс объектов, которым требуется поддержка SSE, вы можете переопределить new/delete только для этого класса.

person rasmus    schedule 09.02.2012
comment
Спасибо за ссылку. Я этого не знал, к сожалению, видимо, это верно только для 64-битной платформы, когда malloc скомпилировано для 32-битной выравнивается до 8 байтов, и изменение его поведения по умолчанию на 16, вероятно, отрицательно повлияет на производительность на 32-битных платформах. Да, я боюсь, что самое чистое и безопасное решение - просто перегрузить new/delete для всех классов, которые используют SSE либо напрямую, либо через одного из своих членов, и используя новую (для меня) информацию из вашей ссылки, просто отключите этот код при компиляции для 64-битных платформ. - person Curious Cpp User; 09.02.2012
comment
@CuriousCppUser И не забудьте предоставить настраиваемый распределитель для любых стандартных контейнеров для выровненных объектов, поскольку распределитель по умолчанию просто вызывает глобальный operator new. - person Christian Rau; 22.02.2012

Не уверен, что это практично для ваших целей, но вы можете использовать распределитель Дуга Ли и определить макрос MALLOC_ALIGNMENT в соответствии с вашими потребностями. потребности (до 128 байт).

Вам даже не нужно заменять распределитель по умолчанию — вы должны иметь возможность использовать специфичные для Дуга Ли dlmalloc и dlfree только для ваших нужд SSE и продолжать использовать распределитель по умолчанию для всего остального.

person Branko Dimitrijevic    schedule 09.02.2012