[C/C++] 컴파일러 최적화 (전체 프로그램 최적화)

윤찬호·2023년 4월 10일
0

에러

목록 보기
6/6

현상

MFC 프로그램에서 A.dll을 사용하는데, Debug 모드로 빌드한 dll파일을 사용했을 때는 정상적으로 작동했으나 Release 모드로 빌드한 dll파일을 사용했을 때는 프로그램 실행중 강제 종료되는 현상 발생.

해결과정

Debug 모드에서는 정상적으로 작동했고 소스코드에는 따로 전처리된 부분이 없기 때문에 소스코드 문제가 아닌 빌드 환경(프로젝트 속성) 문제일 것으로 예상함.

Debug 모드에서의 설정과 Release 모드에서의 설정을 하나씩 비교하며 Debug 모드 기준으로 설정 값을 바꿔가며 테스트 진행.

'C/C++' - '최적화' - '전체 프로그램 최적화'를 '예'에서 '아니요'로 수정하고 빌드 진행.

빌드 결과물로 다시 테스트 해보니 정상 작동!

최적화 기능이란?

컴파일러 최적화 기능은 소스 코드를 기계어로 변환할 때, 코드를 더 빠르게 실행하고 메모리를 효율적으로 사용(더 작은 메모리를 사용)하기 위한 옵션이다. 이를 통해 컴파일된 프로그램의 성능을 최적화할 수 있다.

컴파일러는 코드를 컴파일 할 떄 여러 종류의 최적화를 수행한다.
코드에서 중복되는 부분을 찾아서 함수나 변수로 대체하거나, 반복문을 단순화하거나, 상수 표현식을 미리 계산하여 실행 시간을 줄일 수 있다. 또한, 컴파일러는 프로그램의 실행 특성을 분석하여 적절한 코드 배치와 데이터 구조를 선택하거나, 임시 변수를 제거하여 메모리 사용량을 줄일 수도 있다.

최적화 기능이 어떤 식으로 작동하는지는 아래 블로그에 설명이 잘 되어 있다
https://blog.naver.com/PostView.nhn?blogId=tipsware&logNo=221018587422

최적화 기능의 단점

최적화 기능은 프로그램의 성능을 향상시킬 수 있지만, 종종 예상하지 못한 결과를 초래할 수도 있다. 최적화는 프로그램이 더 빨리 실행되거나 메모리를 더 적게 사용하도록 만들기 때문에, 프로그램의 동작이 변경되거나 버그가 발생할 수 있다. 때문에 최적화를 사용할 때에는 테스트를 충분히 수행하여 프로그램이 예상한 대로 동작하는지 확인해야 한다. 또한, 최적화 기능을 사용하지 않는 옵션도 제공하기 때문에, 최적화 기능을 사용하지 않는 것이 더 안전할 수도 있다.

전체 프로그램 최적화 (/GL)

전체 프로그램 최적화는 여러 소스 파일로 이루어진 큰 규모의 프로그램을 컴파일할 때, 전체 프로그램을 대상으로 최적화를 수행하는 기능이다.

프로그램의 모든 소스 파일을 하나의 유닛으로 취급하여 컴파일하며, 이를 통해 전체 프로그램을 최적화할 수 있다. (전체 프로그램을 대상으로 중복 코드 제거, 인라인 함수 확장, 상수 전파, 변수 최적화)

라이브러리 파일 적용시
LIB나 DLL을 만들 때 전체 프로그램 최적화 기능을 사용하지 않았다면, 최적화 기능이 적용되지 않은 상태에서 생성되었을 가능성이 있기 때문에, 이 경우 LIB/DLL을 사용하는 프로젝트에서 전체 프로그램 최적화 기능을 사용해도 해당 라이브러리 파일은 최적화되지 않는다.

GL 옵션의 장점

GL 옵션은 여러 파일에서 동일한 함수나 변수를 사용하는 경우에 효과적이다. 전체 프로그램을 하나의 유닛으로 컴파일 하기 때문에 함수나 변수가 중복되는 경우를 찾아 중복을 제거하거나, 함수 호출을 인라인 확장하여 실행 시간을 줄일 수 있다. 함수나 변수의 접근 패턴을 분석하여 적절한 데이터 구조나 메모리 배치를 선택하거나, 임시 변수를 제거하여 메모리 사용량을 줄일 수 있다.

GL 옵션의 단점

전체 프로그램 최적화는 프로그램의 성능을 높이는 데 도움이 되지만, 큰 규모의 프로그램을 컴파일하는 데 많은 시간이 걸리고, 메모리 사용량도 증가할 수 있다. 또한, 최적화 기능을 과도하게 사용하면 예상치 못한 결과를 초래할 수 있으므로, 프로그램이 정상적으로 동작하는지 테스트를 충분히 수행해야 한다.

또한 중간 파일(obj, lib)의 사이즈가 커지고, 링크 시간이 늘어나며 모듈이 매우 클 경우 빌드가 되지 않는다.


Visual Studio 2019기준
Debug모드에서는 전체 프로그램 최적화 "아니요"로 설정되어 있고, Release모드에서는 "예"로 설정되어 있다.

에러 발생 원인

msdn에 나와있는 /GL (전체 프로그램 최적화) 설명을 보면 아래와 같은 내용이 있다.

/ZI 와 함께 사용할 수 없습니다. /GL

현재 버전에서 로 /GL 생성된 파일의 형식은 이후 버전의 Visual Studio 및 MSVC 도구 집합에서 읽을 수 없는 경우가 많습니다. 사용자가 현재와 미래에 사용할 것으로 예상되는 Visual Studio의 모든 버전에 대해 파일 복사본 .lib 을 제공하려는 경우가 아니면 에서 생성된 /GL 파일로 구성된 .obj 파일을 배송 .lib 하지 마세요. 자세한 내용은 이진 호환성에 대한 제한을 참조하세요.

이진 호환성에 대한 제한 사항
(전체 프로그램 최적화) 컴파일러 스위치를 사용하여 컴파일되거나 연결된(링크 타임 코드 생성)를 사용하여 컴파일된 정적 라이브러리 또는/LTCG 개체 파일은 부 버전 업데이트를 포함하여 버전 간에 이진 호환되지 않습니다.
/GL 컴파일된 /GL 모든 개체 파일 및 라이브러리는 컴파일 및 /LTCG 최종 링크에 정확히 동일한 도구 집합을 사용해야 합니다. 예를 들어 Visual Studio 2019 버전 16.7 도구 집합에서 사용하여 /GL 빌드된 코드는 Visual Studio 2019 버전 16.8 도구 집합을 사용하여 /GL 빌드된 코드에 연결할 수 없습니다. 컴파일러는 심각한 오류 C1047을 내보낸다.

첫 번째 /GL 옵션은 /ZI(디버깅 정보 형식) 옵션과 함께 사용할 수 없다.
일반적으로 Release 빌드시 /ZI 옵션은 사용하지 않게 되어 있으나, 내가 빌드한 프로젝트 설정에는 /ZI 옵션을 사용하는 것으로 설정 되어있었다.
/ZI 옵션을 사용하지 않고 테스트 했으나 동일한 오류가 발생했다.

두 번째 전체 프로그램 최적화를 사용하여 컴파일된 정적 라이브러리 파일은 버전 간에 이진 호환되지 않는다.

나의 오류는 두 번째 이유에 의해서 발생한 것이다.
오류의 원인을 설명하려면 내 프로그램에 대해 조금 더 설명이 필요하다.

1) MFC.exe를 실행하기 위해 A.dll 파일과 B.dll 파일이 필요하다.
2) A.dll 파일을 생성하기 위해 B.lib 파일을 사용한다.
3) 2)에서 사용한 B.lib 파일은 옛날 버전의 Visual Studio로 빌드한 파일이다.
4) B.dll 의 버그를 수정하는 과정에서 Visual Studio 2019로 업그레이드 하였으며, /GL 옵션을 사용했다.


즉, 2)에서 사용한 B.lib 파일과 4)에서 사용한 B.lib 파일의 Visual Studio 버전이 일치하지 않는다.
4)에서 사용한 B.lib 파일을 이용하여 A.dll을 빌드하고 다시 테스트 했을때는 정상적으로 작동했다.
따라서 버전 간에 이진 호환되지 않기 때문에 해당 에러가 발생한 것으로 볼 수 있다.

정리

해결과정을 보면 '전체 프로그램 최적화'옵션을 사용하지 않는 것으로 간단하게 해결됬다.

에러 발생 원인을 분석하는 과정에서 Visual Studio 버전이 불일치해서 발생했다는 것을 알게 되었고, 빌드 버전을 일치 시켰을때 에러가 해결됬다.

전체 프로그램 최적화 기능은 잘 쓰면 좋은 기능인 동시에 문제를 일으킬 수 있는 기능으로 보인다...




참고

컴파일러 최적화 기능
https://blog.naver.com/PostView.nhn?blogId=tipsware&logNo=221018587422

MSDN
https://learn.microsoft.com/ko-kr/cpp/build/reference/o-options-optimize-code?view=msvc-170
https://learn.microsoft.com/ko-kr/cpp/build/reference/gl-whole-program-optimization?view=msvc-170
https://learn.microsoft.com/ko-kr/cpp/porting/binary-compat-2015-2017?view=msvc-170#restrictions

전체프로그램 최적화
https://honestgame.tistory.com/48

컴파일러 옵션 설명
https://blog.naver.com/leemino/80155321845

0개의 댓글