다음과 같은 코드가 있습니다. test_1 과 test_65536 중에 어느 것이 더 빠를까요?




[test_1] 


for (int j = 0; j < 65536; j++) // loop를 이용하여 "a++"을 65536번 실행
{
  a++;
}




[test_65536]


a++;
a++;
a++;
... // 총 65536번




좀 더 면밀한 테스트를 위해서 프로젝트를 만들어 실행을 했습니다.




[테스트 환경]


Assembly 코드상으로 비교를 제대로 위해 최적화 옵션을 배제하였습니다.


 CPU 

 Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz 

 OS 

 Windows 7

 Compiler 

 Microsoft Visual Studio 2012 Update 4 

 Compile Option 

 Optimization - Disabled (/Od)




[테스트 코드]


다운로드 :  loop_test.zip (Visual Studio 2012 project file, source code and assembly file 포함)


#include <windows.h>
#include <iostream>
using namespace std;

#define LOOP16(A) (A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);(A);
#define LOOP256(A) LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);LOOP16(A);
#define LOOP4096(A) LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);LOOP256(A);
#define LOOP65536(A) LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);LOOP4096(A);

#define N     65536
#define COUNT 100000

void test_1(__int64 a)
{
  for (int i = 0; i < COUNT; i++)
  {
    for (int j = 0; j < N; j++)
    {
      a++;
    }
  }
  cout << "a=" << a << endl;
}

void test_16(__int64 a)
{
  for (int i = 0; i < COUNT; i++)
  {
    for (int j = 0; j < N / 16; j++)
    {
      LOOP16(a++);
    }
  }
  cout << "a=" << a << endl;
}

void test_256(__int64 a)
{
  for (int i = 0; i < COUNT; i++)
  {
    for (int j = 0; j < N / 256; j++)
    {
      LOOP256(a++);
    }
  }
  cout << "a=" << a << endl;
}

void test_4096(__int64 a)
{
  for (int i = 0; i < COUNT; i++)
  {
    for (int j = 0; j < N / 4096; j++)
    {
      LOOP4096(a++);
    }
  }
  cout << "a=" << a << endl;
}

void test_65536(__int64 a)
{
  for (int i = 0; i < COUNT; i++)
  {
    for (int j = 0; j < N / 65536; j++)
    {
      LOOP65536(a++);
    }
  }
  cout << "a=" << a << endl;
}

int main()
{
  DWORD begTick, endTick;

  // test_1
  begTick = timeGetTime();
  test_1(0);
  endTick = timeGetTime();
  cout << "test_1 takes " << endTick - begTick << endl;

  // test_16
  begTick = timeGetTime();
  test_16(0);
  endTick = timeGetTime();
  cout << "test_16 takes " << endTick - begTick << endl;

  // test_256
  begTick = timeGetTime();
  test_256(0);
  endTick = timeGetTime();
  cout << "test_256 takes " << endTick - begTick << endl;

  // test_4096
  begTick = timeGetTime();
  test_4096(0);
  endTick = timeGetTime();
  cout << "test_4096 takes " << endTick - begTick << endl;

  // test_65536
  begTick = timeGetTime();
  test_65536(0);
  endTick = timeGetTime();
  cout << "test_65536 takes " << endTick - begTick << endl;

  return 0;
}




[어셈블리 - test_1]

파란색이 루프(j) 처리 반복 루틴이고, 빨간색이 a++ 루틴입니다. "파란색-빨간색"이 65536번 반복되어 실행이 됩니다.


; 16   :   {
; 17   :     for (int j = 0; j < N; j++)

	mov	DWORD PTR _j$1[ebp], 0
	jmp	SHORT $LN3@test_1
$LN2@test_1:
	mov	ecx, DWORD PTR _j$1[ebp]
	add	ecx, 1
	mov	DWORD PTR _j$1[ebp], ecx
$LN3@test_1:
	cmp	DWORD PTR _j$1[ebp], 65536		; 00010000H
	jge	SHORT $LN1@test_1

; 18   :     {
; 19   :       a++;

	mov	edx, DWORD PTR _a$[ebp]
	add	edx, 1
	mov	eax, DWORD PTR _a$[ebp+4]
	adc	eax, 0
	mov	DWORD PTR _a$[ebp], edx
	mov	DWORD PTR _a$[ebp+4], eax

; 20   :     }

	jmp	SHORT $LN2@test_1
$LN1@test_1:

; 21   :   }

	jmp	SHORT $LN5@test_1
$LN4@test_1:




[어셈블리 - test_65536]

빨간색이 하나의 a++ 루틴입니다. 빨간색 코드만 아래위로 65536번 그대로 반복되어 일렬로 늘어져 있습니다.


; 66   :     {
; 67   :       LOOP65536(a++);

	mov	edx, DWORD PTR _a$[ebp]
	add	edx, 1
	mov	eax, DWORD PTR _a$[ebp+4]
	adc	eax, 0
	mov	DWORD PTR _a$[ebp], edx
	mov	DWORD PTR _a$[ebp+4], eax
	mov	edx, DWORD PTR _a$[ebp]
	add	edx, 1
	mov	eax, DWORD PTR _a$[ebp+4]
	adc	eax, 0
	mov	DWORD PTR _a$[ebp], edx
	mov	DWORD PTR _a$[ebp+4], eax
	mov	edx, DWORD PTR _a$[ebp]
	add	edx, 1
	mov	eax, DWORD PTR _a$[ebp+4]
	adc	eax, 0
	mov	DWORD PTR _a$[ebp], edx
	mov	DWORD PTR _a$[ebp+4], eax
        ...




[실행 결과]


>loop_test

a=6553600000

test_1 takes 13935

a=6553600000

test_16 takes 12366

a=6553600000

test_256 takes 12605

a=6553600000

test_4096 takes 12961

a=6553600000

test_65536 takes 13584




[결론]


test_1 에서는 반복 횟수 확인을 하는 코드가 추가되어 test_65536보다 더 느려 질 것 같은데,  결과는 그리 차이가 나지 않는 것을 볼 수가 있습니다. 정확한 원인이 무엇일까요?