Наступні тести були зроблені з компілятором Visual C ++, оскільки він використовується за допомогою програми Qt Creator за замовчуванням (я думаю, що немає прапор оптимізації). Під час використання GCC немає великої різниці між версією Mystical і моїм "оптимізованим" кодом. Отже, висновок полягає в тому, що оптимізація компілятора краще піклується про мікрооптимізацію, ніж люди (нарешті я). Решту своєї відповіді я залишаю для довідки.
Обробляти зображення таким чином не ефективно. Краще використовувати одномірні масиви. Обробка всіх пікселів виконується в один цикл. Випадковий доступ до пунктів можна зробити за допомогою:
pointer + (x + y*width)*(sizeOfOnePixel)
У цьому конкретному випадку краще обчислити та кешувати суму трьох піксельних груп по горизонталі, оскільки вони використовуються три рази кожна.
Я зробив кілька тестів і, думаю, варто їх поділитися. Кожен результат - це в середньому п’ять тестів.
Оригінальний код користувача1615209:
8193: 4392 ms
8192: 9570 ms
Версія Mystical:
8193: 2393 ms
8192: 2190 ms
Два пропуски за допомогою 1D масиву: перший пропуск для горизонтальних сум, другий для вертикальної суми та середній. Адреса з двома проходами з трьома вказівниками та лише з таким кроком:
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
Два проходи, використовуючи 1D масив і адресуючи так:
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. На початку це був просто псевдо-код. Мене попросили зробити тести в коментарях ... Ось повністю відновлена версія з тестами.