У меня довольно большой код, и я хочу оптимизировать некоторые операции с помощью инструкций AVX. Основываясь на моих тестах, улучшение должно быть до 4 раз.
Однако в коде используются простые старые массивы (без std::vector) с оператором new.
double * tmp = new double[size];
Проблема в том, что для AVX мне нужно, чтобы все двойные массивы были выровнены по 32-байтовой границе. Решение состоит в том, чтобы заменить все new на aligned_alloc (или _aligned_malloc в MSVC), а также заменить функции выпуска на адекватные. Проблема в том, что мне нужно просмотреть весь код и найти все new, надеясь не забыть ни одного, и в будущем все не должны забывать использовать выровненный алокатор.
Есть ли другой способ? Я думал об операторе перегрузки new только для double, но я не уверен, что это правильный способ, и если да, то как это сделать правильно/безопасно.
Я не могу переключиться на std::vector с собственным выровненным алокатором из-за некоторых внешних библиотек только для C, которые принимают массив в качестве входных параметров.
Если вы можете использовать статический буфер, вы можете использовать специальные параметры вашего компилятора, такие как #pragma align
@YSC: Очевидно, библиотека C не будет вызывать delete.
@MSalters ^^ Я имел в виду free(), но я так привык delete, что мои пальцы печатают это незаметно :D (я называю этот рефлекс «цифровым» сборщиком мусора)
@Martin Не могли бы вы использовать std::vector со специальным распределителем и передать своим внешним библиотекам C только для C указатель на базовый массив, возвращаемый vec.data() ?
C-библиотека @YSC может хранить данные внутри и возвращать их через некоторую функцию «получить как», когда их необходимо освободить. Освобождение происходит на стороне C++, но вектор может уже исчезнуть вместе с объектом, который его выделил. Или, может быть, повторное использование, которое снова делает недействительными его внутренние данные.
@MSalters, но если new[] - это решение проблемы, то, конечно, проблема должна заключаться в использовании delete[] :)





Есть ли другой способ? Да, _mm_loadu_* и _mm_storeu_*, где u означает невыровненный.
Лучше всего это работает, если архитектура ЦП как минимум Haswell (2013) или Zen (2017); на старых платформах может быть небольшое замедление по сравнению с выровненным доступом.
Я сделал несколько тестов, и на моем процессоре нет видимой разницы.
Просто для дополнительной уверенности: когда вы пишете «из-за некоторых внешних библиотек только для C, которые принимают массив в качестве входных параметров», вы имеете в виду, что не можете дать им
vector.data(), потому что эти библиотеки потенциально сохраняют указатель после того, как вектор сделал его недействительным? или потому что либыdeleteсами память? Или что-то в этом роде?