Следующие тесты были выполнены с компилятором Visual C ++, так как он используется при установке по умолчанию Qt Creator (я думаю, без флага оптимизации). При использовании GCC нет большой разницы между версией Mystical и моим «оптимизированным» кодом. Итак, вывод заключается в том, что оптимизация компилятора заботится о микрооптимизации лучше, чем люди (наконец-то я). Я оставляю остаток моего ответа для справки.
Неэффективно обрабатывать изображения таким образом. Лучше использовать одномерные массивы. Обработка всех пикселей выполняется за один цикл. Произвольный доступ к точкам может быть выполнен с использованием:
pointer + (x + y*width)*(sizeOfOnePixel)
В этом конкретном случае лучше вычислять и кэшировать сумму трех пиксельных групп по горизонтали, поскольку они используются по три раза каждая.
Я сделал несколько тестов, и я думаю, что стоит поделиться. Каждый результат - в среднем пять тестов.
Оригинальный код от пользователя1615209:
8193: 4392 ms
8192: 9570 ms
Мистическая версия:
8193: 2393 ms
8192: 2190 ms
Два прохода с использованием одномерного массива: первый проход для горизонтальных сумм, второй для вертикальной суммы и среднего. Двухпроходная адресация с тремя указателями и только такими приращениями:
imgPointer1 = &avg1[0][0];
imgPointer2 = &avg1[0][SIZE];
imgPointer3 = &avg1[0][SIZE+SIZE];
for(i=SIZE;i<totalSize-SIZE;i++){
resPointer[i]=(*(imgPointer1++)+*(imgPointer2++)+*(imgPointer3++))/9;
}
8193: 938 ms
8192: 974 ms
Два прохода с использованием одномерного массива и адресации следующим образом:
for(i=SIZE;i<totalSize-SIZE;i++){
resPointer[i]=(hsumPointer[i-SIZE]+hsumPointer[i]+hsumPointer[i+SIZE])/9;
}
8193: 932 ms
8192: 925 ms
Горизонтальные кеширующие за один проход суммы всего на одну строку впереди, поэтому они остаются в кеше:
// Horizontal sums for the first two lines
for(i=1;i<SIZE*2;i++){
hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
}
// Rest of the computation
for(;i<totalSize;i++){
// Compute horizontal sum for next line
hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
// Final result
resPointer[i-SIZE]=(hsumPointer[i-SIZE-SIZE]+hsumPointer[i-SIZE]+hsumPointer[i])/9;
}
8193: 599 ms
8192: 652 ms
Вывод:
- Нет пользы от использования нескольких указателей и просто приращений (я думал, что это было бы быстрее)
- Кэшировать горизонтальные суммы лучше, чем вычислять их несколько раз.
- Два прохода не в три раза быстрее, только в два раза.
- Можно достичь в 3,6 раза быстрее, используя как один проход, так и кэшируя промежуточный результат
Я уверен, что можно сделать намного лучше.
ПРИМЕЧАНИЕ.
Обратите внимание, что я написал этот ответ для решения общих проблем с производительностью, а не проблемы с кешем, описанной в превосходном ответе Mystical. В начале это был просто псевдокод. Меня попросили сделать тесты в комментариях ... Вот полностью переработанная версия с тестами.