Testy przeprowadzane na Visual Studio 2012, procesor to Sandy Bridge.
Program testowy:
#include <Windows.h>
#include <cstdio>
__declspec(noinline) int do_magic(int value)
{
return value * 5;
}
int main()
{
LARGE_INTEGER start, end, freq;
QueryPerformanceFrequency(&freq);
size_t iterations = 100000;
size_t tests = 5000;
int* arr = new int[iterations];
QueryPerformanceCounter(&start);
for(int testIdx = 0; testIdx < tests; testIdx++)
{
// Wariant I
// for(int i = 0; i < iterations; i++)
// arr[i] = do_magic(arr[i]);
// Wariant II
// for(int *it = arr, *e = it + iterations; it < e; ++it)
// *it = do_magic(*it);
}
QueryPerformanceCounter(&end);
double result = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart * 1000;
printf("%fms\n", result);
}
Kod z włączonymi optymalizacjami kompiluje się do:
// Wariant I
for(int i = 0; i < iterations; i++)
00F31060 xor edx,edx
arr[i] = do_magic(arr[i]);
00F31062 mov ecx,dword ptr [esi+edx*4]
00F31065 call do_magic (0F31000h)
00F3106A mov dword ptr [esi+edx*4],eax
00F3106D inc edx
00F3106E cmp edx,186A0h
00F31074 jb main+52h (0F31062h)
// Wariant II
for(int *it = arr, *e = it + iterations; it < e; ++it)
00B91060 mov edx,ebx
00B91062 cmp ebx,esi
00B91064 jae main+66h (0B91076h)
*it = do_magic(*it);
00B91066 mov ecx,dword ptr [edx]
00B91068 call do_magic (0B91000h)
00B9106D mov dword ptr [edx],eax
00B9106F add edx,4
00B91072 cmp edx,esi
00B91074 jb main+56h (0B91066h)
Bez optymalizacji (debug), wariant I: 9599ms, wariant II: 9505ms, zysk: 0,97%
Z optymalizacjami (release), wariant I: 750ms, wariant II: 750ms, zysk: 0%
Robi się ciekawiej, gdy wywalimy wywołanie funkcji (arr[i] *= 5;
i *it *= 5;
). W pierwszym wariancie kompilator użyje SSE i czas wykonywania zmniejszy się do 89ms. Drugi wariant: 269ms. Wniosek: drugi kod wręcz zaciemnił twoje intencje przed kompilatorem, który nie mógł z tego powodu przeprowadzić lepszych, bardziej agresywnych optymalizacji.