링크타고 헤메다가
기선님의 블로그 에 우연히 들어가서 이와 같은 주제의 자바 실험을 봤다.
이거 학생때나 하던 실험인데, 내가 점점 기본을 등한시 한다는 생각이 문득 들었다.
자바는 기선님이 실험 하셨으니.. 1년은 안만진 C에서 어떻게 돌아가나 실험해 보았다.
우선 추측..
gcc를 위시한 대부분의 C compiler는 i++, ++i, i=i+1 세개의 statement를 동일하게 컴파일해 낸다.
다만 evaluation되는 값을 STOR instruction의 위치를 ADD위에 두느냐 아래에 두느냐만 달라진다.
따라서 세가지 모두 같은 시간을 소모할 것이다.
실험결과 일부는 맞고 일부는 틀렸다;; 나도 녹슬었다..ㅠㅠ
컴파일러의 행동을 예측하지 못한단 말인가..ㅡㅡ;;
우선 실험에 사용한 급조 C코드를 보자.
t.c보기
[CODE type=c] #include #include int main() { int i = 0, cnt = 0; double t1, t2, t3, t4, t5; double l, CPS = CLOCKS_PER_SEC; int num = 1; for (cnt = 0; cnt < 20; cnt++) { printf("%3d: ", cnt); t1=clock(); for (i=0; i<300000000; i++) num++; t2=clock(); for (i=0; i<300000000; i++) ++num; t3=clock(); for (i=0; i<300000000; i++) num=num+1; t4=clock(); for (i=0; i<300000000; i++); t5=clock(); l = t5-t4; printf ("num++: %.5f ++num: %.5f num=num+1: %.5f\n", (t2-t1-l)/CPS, (t3-t2-l)/CPS, (t4-t3-l)/CPS); } } [/HTML][/CODE]
결과는 이렇다.
[CODE] 0: num++: 0.30000 ++num: 0.31000 num=num+1: 0.31000 1: num++: 0.40000 ++num: 0.42000 num=num+1: 0.46000 2: num++: 0.47000 ++num: 0.40000 num=num+1: 0.56000 3: num++: 0.51000 ++num: 0.44000 num=num+1: 0.53000 4: num++: 0.42000 ++num: 0.44000 num=num+1: 0.51000 5: num++: 0.41000 ++num: 0.40000 num=num+1: 0.56000 6: num++: 0.42000 ++num: 0.46000 num=num+1: 0.41000 7: num++: 0.39000 ++num: 0.41000 num=num+1: 0.46000 8: num++: 0.41000 ++num: 0.40000 num=num+1: 0.51000 9: num++: 0.40000 ++num: 0.35000 num=num+1: 0.42000 10: num++: 0.41000 ++num: 0.47000 num=num+1: 0.45000 11: num++: 0.32000 ++num: 0.32000 num=num+1: 0.39000 12: num++: 0.41000 ++num: 0.51000 num=num+1: 0.43000 13: num++: 0.40000 ++num: 0.40000 num=num+1: 0.38000 14: num++: 0.33000 ++num: 0.42000 num=num+1: 0.36000 15: num++: 0.40000 ++num: 0.40000 num=num+1: 0.43000 16: num++: 0.40000 ++num: 0.45000 num=num+1: 0.41000 17: num++: 0.37000 ++num: 0.37000 num=num+1: 0.40000 18: num++: 0.40000 ++num: 0.41000 num=num+1: 0.51000 19: num++: 0.37000 ++num: 0.38000 num=num+1: 0.51000 [/CODE]
별 차이가 없는건 예상대로다..
혹시나 싶어 컴파일만 시켜봤다.
이 c 코드를 gcc는 이러한 어셈으로 번역한다.
[CODE type=asm] .file "t.c" .section .rodata .LC1: .string "%3d: " .align 4 .LC2: .string "num++: %.5f ++num: %.5f num=num+1: %.5f\n" .align 8 .LC0: .long 0 .long 1093567616 .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp subl $104, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp movl $0, -4(%ebp) movl $0, -8(%ebp) fldl .LC0 fstpl -64(%ebp) movl $1, -68(%ebp) movl $0, -8(%ebp) .L2: cmpl $19, -8(%ebp) jg .L3 movl -8(%ebp), %eax movl %eax, 4(%esp) movl $.LC1, (%esp) call printf call clock pushl %eax fildl (%esp) leal 4(%esp), %esp fstpl -16(%ebp) movl $0, -4(%ebp) .L5: cmpl $299999999, -4(%ebp) jg .L6 leal -68(%ebp), %eax incl (%eax) leal -4(%ebp), %eax incl (%eax) jmp .L5 .L6: call clock pushl %eax fildl (%esp) leal 4(%esp), %esp fstpl -24(%ebp) movl $0, -4(%ebp) .L8: cmpl $299999999, -4(%ebp) jg .L9 leal -68(%ebp), %eax incl (%eax) leal -4(%ebp), %eax incl (%eax) jmp .L8 .L9: call clock pushl %eax fildl (%esp) leal 4(%esp), %esp fstpl -32(%ebp) movl $0, -4(%ebp) .L11: cmpl $299999999, -4(%ebp) jg .L12 leal -68(%ebp), %eax incl (%eax) leal -4(%ebp), %eax incl (%eax) jmp .L11 .L12: call clock pushl %eax fildl (%esp) leal 4(%esp), %esp fstpl -40(%ebp) movl $0, -4(%ebp) .L14: cmpl $299999999, -4(%ebp) jg .L15 leal -4(%ebp), %eax incl (%eax) jmp .L14 .L15: call clock pushl %eax fildl (%esp) leal 4(%esp), %esp fstpl -48(%ebp) fldl -48(%ebp) fsubl -40(%ebp) fstpl -56(%ebp) fldl -40(%ebp) fsubl -32(%ebp) fsubl -56(%ebp) fdivl -64(%ebp) fstpl 20(%esp) fldl -32(%ebp) fsubl -24(%ebp) fsubl -56(%ebp) fdivl -64(%ebp) fstpl 12(%esp) fldl -24(%ebp) fsubl -16(%ebp) fsubl -56(%ebp) fdivl -64(%ebp) fstpl 4(%esp) movl $.LC2, (%esp) call printf leal -8(%ebp), %eax incl (%eax) jmp .L2 .L3: leave ret .size main, .-main .section .note.GNU-stack,"",@progbits .ident "GCC: (GNU) 3.4.3" [/HTML][/CODE] 딴데는 중요한게 없고, .L5, .L8, .L11 만이 관심이 되는 부분인데, 동일하다. 이는 컴파일러가 i++이나, ++i의 evaluation을 할 필요가 없다고 판단해서 그렇게 된거 같다. 그게 진짜인지는 해피투게더 보구 해볼란다;;