최적화의 위력

By | 2009/10/01

그럼 컴파일러가 어떤 어셈블리 코드를 내놓는지 확인하였습니다. 작동 환경은 Fedora 11 32bit Intel CPU / gcc 4.4.1입니다.

어셈블리 코드를 읽어보니 딱히 최적화라고 볼만한 것이 보이지 않았습니다. 그저 코드 하나하나를 어셈블리로 구현한 정도에 그쳤습니다. 그래서 O2 옵션을 주어서 살펴보았습니다.

  위의 글을 어디서 보셨나요? 사실 위의 글은 ‘Tail Recursion과 최적화 이야기‘에 나오는 글입니다. 저렇게 글을 적은 후 어셈블리 코드를 보았습니다. 어떻게 최적화 되었을까 궁금하면서도 이렇게 되지 않았을까 라는 예상을 하며 보았습니다.

  하지만 예상을 크게 빗나간 결과 하나가 보였고, 급히 C 소스를 수정하였습니다. 저를 황당하게 했던 코드를 바로 main 함수 부분입니다.

  1: int main(void)
  2: {
  3: 
  4: 	printf("n is 10 : %d\n", sum(10));
  5: 	printf("n is 100 : %d\n", sum(100));
  6: 	printf("n is 1000 : %d\n", sum(1000));
  7: 
  8: 	return 0;	
  9: }

  이것이 제가 기본으로 짰던 소스 파일입니다. 저는 printf 함수 안에 인자로 sum 함수를 넣었기에 그것을 call 하는 코드가 들어있으리라 생각하였습니다.

c17

  하지만 제가 졌습니다.OTL 최적화를 수행하면 아마도 인자가 고정된 상수일 경우 그 함수가 어떤 함수인지 파악해서 rumtime에 계산하지 않도록 compile time에 계산하는 듯싶습니다. 그래서 굳이 call 하지 않고 그 값을 인자로 저장해서 출력하도록 만들었습니다.OTL..

  따라서 이렇게 수정을 한 후 sum 함수를 call하도록 하였습니다.

  1: int main(void)
  2: {
  3: 	int temp;
  4: 	
  5: 	printf("n? ");
  6: 	scanf("%d", &temp);
  7: 	printf("n is %d : %d\n", temp, sum(temp));
  8: 	
  9: 	printf("n? ");
 10: 	scanf("%d", &temp);
 11: 	printf("n is %d : %d\n", temp, sum(temp));
 12: 	
 13: 	printf("n? ");
 14: 	scanf("%d", &temp);
 15: 	printf("n is %d : %d\n", temp, sum(temp));
 16: 
 17: 	return 0;	
 18: }

  조금 무식한 방법이지만, 이런 부분에서의 최적화를 신경 쓰지 않기로 하였습니다. 그리고 각각 10, 100, 1000을 입력값으로 넘겼습니다.

c21

  역시 잘 되는 것을 확인하였습니다.

  그럼 이 소스 코드의 어셈블리 코드를 확인하였습니다.

c22

  제가 또 졌습니다. call 하지 않고 함수 body를 main에 그대로 넣어버렸습니다. 그럼 굳이 call하여 stack frame을 새롭게 만들고 ebp나 return address 등을 저장하는 등의 일을 할 필요가 없어졌습니다.

  최적화.. 무섭네요. 이렇게 코드가 확 바뀔 수 있구나 하는 점을 새삼스럽게 느끼는 밤입니다.

2 thoughts on “최적화의 위력

  1. thot135

    tail recursion으로 짜든 안짜든 -O2 옵션만 주면 call을 전부 날려버리는
    비범함을 보이더군요. gcc 만세 최적화 만세-_-…

    Reply
    1. NoSyu

      반갑습니다.
      O2는 call을 전부 날리는군요!
      그런데 tail recursion으로 할 경우 같은 O2라도 어셈코드가 줄어든다고 하니 그만큼 컴파일러가 파악하기 쉽다는 건 사실인 듯싶습니다.^^

      Reply

Leave a Reply