У меня есть библиотека, которая имеет некоторые алгоритмы обработки изображений, включая алгоритм области интереса (обрезать). При компиляции с GCC автоматический векторизатор ускоряет большую часть кода, но ухудшает производительность алгоритма кадрирования. Есть ли способ пометить определенный цикл, чтобы он игнорировался векторизатором, или есть лучший способ структурирования кода для повышения производительности?
for (RowIndex=0;RowIndex<Destination.GetRows();++RowIndex)
{
rowOffsetS = ((OriginY + RowIndex) * SizeX) + OriginX;
rowOffsetD = (RowIndex * Destination.GetColumns());
for (ColumnIndex=0;ColumnIndex<Destination.GetColumns();++ColumnIndex)
{
BufferSPtr=BufferS + rowOffsetS + ColumnIndex;
BufferDPtr=BufferD + rowOffsetD + ColumnIndex;
*BufferDPtr=*BufferSPtr;
}
}
куда
SizeX
ширина источника
OriginX
находится слева от области интересов
OriginY
является вершиной области интереса
Я не нашел ничего об изменении флагов оптимизации для цикла, однако согласно документации вы можете использовать атрибут optimize
(смотреть Вот а также Вот) для функции, чтобы переопределить настройки оптимизации для этой функции, примерно так:
void foo() __attribute__((optimize("O2", "inline-functions")))
Если вы хотите изменить его для нескольких функций, вы можете использовать #pragma GCC optimize
установить его для всех следующих функций (Смотри сюда).
Таким образом, вы должны иметь возможность скомпилировать функцию, содержащую кадрирование, с другим набором флагов оптимизации, исключая автоматическую векторизацию. Это имеет недостаток в жестком кодировании флагов компиляции для этой функции, но это лучшее, что я нашел.
Что касается реструктуризации для повышения производительности, на ум приходят два момента, которые я уже упоминал в комментариях (при условии, что диапазоны не могут перекрываться):
объявив указатели как __restrict
сообщить компилятору, что они не являются псевдонимами (область, на которую указывает один указатель, не будет доступна никаким другим средствам внутри функции). Возможность наложения указателей является основным камнем преткновения для оптимизатора, так как он не может легко изменить порядок доступа, если не знает, пишет ли он в BufferD
изменит содержимое BufferS
,
Замена внутреннего цикла вызовом для копирования:
std::copy(BufferS + rowOffsetS, BufferS + rowOffsetS + Destination.GetColumns(), BufferD + rowOffsetD);
copy
функция, вероятно, будет довольно хорошо оптимизирована (возможно, пересылка аргументов memmove
), так что это может сделать ваш код быстрее, а также сделать ваш код короче (всегда плюс).
Других решений пока нет …