컴파일 과정은 4가지 단계(전처리 과정 - 컴파일 과정 - 어셈블리 과정 - 링킹 과정)로 나누어 진다.
이 4가지 단계를 묶어서 컴파일 과정, 빌드 과정이라고 부르기도 하고 컴파일 과정과 링킹 과정을 따로 나눠서 부르기도 한다.
보통 빌드 과정은 컴파일 과정보다 넓은 의미(빌드=컴파일+링킹)로 사용되는데 상황에 맞게 이해하면 될 거 같다.
그럼 각 단계별 과정에 대해 자세히 알아보자.
전처리(Pre-processing) 과정은 전처리기(Preprocessor)를 통해 소스 코드 파일(.c)을 전처리된 소스 코드 파일(.i)로 변환하는 과정이다.
이 과정에서 대표적으로 세 가지 작업을 수행한다.
컴파일(Compilation) 과정은 컴파일러(Compiler)를 통해 전처리된 소스 코드 파일(.i)을 어셈블리어 파일(.s)로 변환하는 과정이다.
이 과정에서 우리가 일반적으로 컴파일하면 생각하는 언어의 문법 검사가 이루어진다. 또한 Static한 영역(Data, BSS 영역)들의 메모리 할당을 수행한다.
컴파일러는 세 단계(프론트엔드 - 미들엔드 - 백엔드)로 구성되어 있다.
프론트엔드(Front-end)
프론트엔드에서는 언어 종속적인 부분을 처리한다.
소스 코드가 해당 언어로 올바르게 작성되었는지 확인(어휘/구문/의미 분석)하고 미들엔드에 넘겨주기 위한 GIMPLE 트리(소스 코드를 트리 형태로 표현한 자료 구조)를 생성한다.
이 과정에서 C, C++, Java와 같은 다양한 언어들이 각 언어에 맞게 처리된 후 공통된 중간 표현(IR : Intermediate representation)인 GIMPLE 트리로 변환되므로 언어 종속적인 부분을 처리할 수 있다.
미들엔드(Middle-end)
미들엔드에서는 아키텍쳐 비종속적인 최적화를 수행한다.
아키텍쳐 비종속적인 최적화란 CPU 아키텍쳐가 무엇이든(arm, x86 등) 상관없이 할 수 있는 최적화를 말한다.
프론트엔드에서 넘겨받은 GIMPLE 트리를 이용해 아키텍쳐 비종속적인 최적화를 수행한 후 백엔드에서 사용하는 RTL(Register Transfer Language : 고급 언어와 어셈블리 언어의 중간 형태)를 생성한다.
백엔드(Back-end)
백엔드에서는 아키텍쳐 종속적인 최적화를 수행한다.
아키텍쳐 종속적인 최적화란 아키텍쳐 특성에 따라 최적화를 수행하는 것을 말한다. 같은 기능을 수행하는 명령어여도 CPU 아키텍처별로 더욱 효율적인 명령어로 대체하여 성능을 높이는 작업을 예를 들 수 있다.
미들엔드에서 넘겨받은 RTL을 이용해 아키텍쳐 종속적인 최적화를 수행하고 최적화가 완료되면 어셈블리 코드를 생성한다.
아키텍쳐 종속적인 최적화를 수행하면 해당 아키텍쳐만 이해할 수 있는 언어가 되기 때문에 아키텍쳐가 맞지 않으면 어셈블리 코드를 해석할 수 없다.
많은 컴파일러가 앞서 설명한 세 단계의 구조를 따르고 있지만, 컴파일러마다 차이가 존재한다.
GNU에서 만든 C 컴파일러인 gcc는 프론트엔드/미들엔드/백엔드 단계가 깔끔하게 분리되어 있지 않고 의존성이 존재한다. 그에 비해 오픈 소스 C 컴파일러인 Clang(프론트엔드) + LLVM(미들엔드, 백엔드)는 단계가 잘 분리되어 있다.
어셈블리(Assembly) 과정은 어셈블러(Assembler)를 통해 어셈블리어 파일(.s)을 오브젝트 파일(.o)로 변환하는 과정이다.
그럼 오브젝트 파일이란 무엇일까?
오브젝트 파일(Object File) 정의
어셈블리 코드는 이제 더 이상 사람이 알아볼 수 없는 기계어로 변환되는데 이를 오브젝트 코드라 부른다.
오브젝트 코드로 구성된 파일을 오브젝트 파일(Object File)이라 부르며 이 오브젝트 파일은 특정한 파일 포맷을 가진다.
※ 오브젝트 파일 포맷의 종류는 Windows의 경우 PE(Portable Executable), Linux의 경우 ELF(Executable and Linking Format)로 나눠진다.
오브젝트 파일 포맷은 다음과 같은 구조를 하고 있다.
여기서 중요한 부분은 심볼 테이블 섹션과 재배치 정보 섹션이다.
심볼(Symbol)은 함수나 변수를 식별할 때 사용하는 이름으로 심볼 테이블(Symbol Table) 안에는 오브젝트 파일에서 참조되고 있는 심볼 정보(이름과 데이터의 주소 등)를 가지고 있다.
이때 오브젝트 파일의 심볼 테이블에는 해당 오브젝트 파일의 심볼 정보만 가지고 있어야 하기 때문에 다른 파일에서 참조되고 있는 심볼 정보의 경우 심볼 테이블에 저장할 수 없다.
#include<stdio.h> 라이브러리를 이용해서 printf 함수를 사용하는 소스 코드 파일이 있다고 가정해보자.
우린 이 소스 코드 파일을 컴파일하여 오브젝트 파일을 생성할 수 있다.
하지만 이 오브젝트 파일은 독립적으로 실행할 수 없다. 이 파일 안에는 printf 함수를 구현한 내용이 없기 때문이다.
전처리 과정을 통해 #include<stdio.h>로부터 printf 함수의 원형은 복사했지만 printf를 구현한 내용은 포함되어 있지 않다. 오브젝트 파일 구조에서 말한 것처럼 심볼 테이블에는 해당 오브젝트 파일의 심볼 정보만 가지고 있지 외부에서 참조하는 printf 함수에 대한 심볼 정보는 가지고 있지 않다.
즉, 이 오브젝트 파일을 실행하기 위해서는 printf 함수를 사용하는 오브젝트 파일과 printf 함수를 구현한 오브젝트 파일(libc.a 라이브러리)을 연결시키는 작업이 필요하다.
이러한 연결 과정을 링킹(Linking)이라 부른다. 그럼 링킹에 대해 자세히 알아보자.
링킹(Linking) 과정은 링커(Linker)를 통해 오브젝트 파일(*.o)들을 묶어 실행 파일로 만드는 과정이다.
이 과정에서 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크하여 하나의 실행 파일을 만든다.
이때 라이브러리를 링크하는 방법에 따라 정적 링킹(Static Linking)과 동적 링킹(Dynamic Linking)으로 나눌 수 있다. 링킹 방식의 차이는 앞서 설명했던 라이브러리 포스트를 참고하자.
링커의 역할은 크게 심볼 해석과 재배치로 나눌 수 있다.
심볼 해석(Symbol Resolution)
심볼 해석은 각 오브젝트 파일에 있는 심볼 참조를 어떤 심볼 정의에 연관시킬지 결정하는 과정이다. 여러 개의 오브젝트 파일에 같은 이름의 함수 또는 변수가 정의되어 있을 때 어떤 파일의 어떤 함수를 사용할지 결정한다.
재배치(Relocation)
재배치는 오브젝트 파일에 있는 데이터의 주소나 코드의 메모리 참조 주소를 알맞게 배치하는 과정이다.
링커가 컴파일러가 생성한 오브젝트 파일을 모아서 하나의 실행 파일을 만들 때, 각 오브젝트 파일에 있는 데이터의 주소나 코드의 메모리 참조 주소가 링커에 의해 합쳐진 실행 파일에서의 주소와 다르게 때문에 그것을 알맞게 수정해줘야 한다.
이를 위해 오브젝트 파일 안에 재배치 정보 섹션(Relocation Information Section)이 존재한다.
링킹 과정에서 같은 세션끼리 합쳐진 후 재배치가 일어난다.
위 그림을 통해 알 수 있듯이 오브젝트 파일 형식은 링킹 과정에서 링커가 여러 개의 오브젝트 파일들을 하나의 실행 파일로 묶을 때 필요한 정보를 효율적으로 파악할 수 있는 구조이다.
링킹을 하기 전 오브젝트 파일을 재배치 가능한 오브젝트 파일(Relocatable Object File)이라 부르고 링킹을 통해 만들어지는 오브젝트 파일을 실행 가능한 오브젝트 파일(Executable Object File)이라 부른다.
결론
이로써 컴파일을 통해 소스 코드 파일이 실행 파일이 되는 과정에 대해 알아보았다.
이 글을 통해 프로그래밍의 원리를 이해하는 데 조금은 도움이 되었으면 좋겠다.
※ 컴파일 과정 동안 연쇄적으로 사용하는 개발 도구들(전처리기-컴파일러-어셈블리-링커)을 묶어서 툴체인(Toolchain)이라고도 부른다.
GCC (GNU Compiler Collection):
GNU Compiler Collection은 자유 및 오픈 소스 소프트웨어로, 다양한 언어를 지원하는 컴파일러 모음입니다. g++는 C++ 컴파일러를 나타냅니다.
Clang:
Clang은 LLVM 프로젝트의 일부로 개발된 컴파일러이며, C++을 비롯한 다양한 언어를 지원합니다. Clang은 모듈성과 확장성이 뛰어나며, 정교한 코드 분석을 제공합니다.
Visual C++ (Microsoft Visual Studio):
Microsoft에서 제공하는 Visual C++ 컴파일러는 Windows 환경에서 널리 사용됩니다. Visual Studio는 통합 개발 환경 (IDE)과 함께 제공되어 소프트웨어 개발을 편리하게 할 수 있습니다.
Intel C++ Compiler:
Intel C++ Compiler는 Intel에서 개발한 컴파일러로, Intel 프로세서를 타겟으로 하는 애플리케이션을 최적화할 수 있는 기능을 제공합니다.
Clion (JetBrains):
JetBrains의 Clion은 C++ 개발을 위한 통합 개발 환경으로, CMake 기반의 프로젝트를 지원하며, 컴파일러는 사용자가 설정할 수 있습니다.
컴파일러 제공 업체 역할 :
C++ 표준 라이브러리(STL)는 표준화된 API를 제공하며, 이를 구현하는 역할은 주로 컴파일러 제공 업체에게 있습니다. 표준 라이브러리는 C++ 언어의 표준 스펙에 따라 정의되어 있으며, 컴파일러 업체는 이러한 표준에 따라 라이브러리를 구현합니다.
컴파일러 제공 업체는 특정 플랫폼에 맞는 최적화와 호환성을 고려하여 C++ 표준을 구현합니다. 표준 라이브러리의 구현은 특정 운영 체제 및 하드웨어 환경에 맞추어져야 하며, 이는 각각의 컴파일러 제공 업체가 수행합니다.
표준 라이브러리의 구현은 주로 헤더 파일과 라이브러리 파일의 형태로 제공되며, 이를 프로그래머가 사용할 수 있게 합니다. 대표적인 C++ 컴파일러 업체로는 GCC(GNU Compiler Collection), Clang, Visual C++(Microsoft), Intel C++ Compiler 등이 있습니다. 각 컴파일러는 자체적으로 표준 라이브러리를 제공하며, 이를 통해 개발자는 표준 라이브러리를 사용하여 C++ 언어로 프로그래밍할 수 있습니다.
표준 라이브러리의 품질과 성능은 컴파일러 제공 업체마다 차이가 있을 수 있으므로, 특정 프로젝트에서는 컴파일러의 선택도 중요한 요소 중 하나가 될 수 있습니다.
The tests are performed on an Intel Xeon Platinum processor featuring the Skylake architecture with AVX-512 vector instructions.
방법에 의한 분류 프로그램 동작을 빠르게 하는 3가지 : 명령 수를 줄임, 더 빠른 명령 사용, 명렬 병렬 실행
대상 범위에 의한 분류 : 로컬 최적화, 글로벌 최적화
코드 최적화기는 프로그램을 블록, 흐름 그래프로 분류하고 정적 분석하여 최적화 할 위치 파악
핍홀 최적화 기법 (Peephole)
지역 최적화
전역 최적화
-O0
, -O2
, -O3
option 을 통해 Optimization level 설정 가능-O0
는 디버깅 목적, -O2
, -O3
는 release 목적-O3
라고 무조건 -O2
보다 빠르지 않음. 케바케 이므로 직접 build 해보고 benchmark test 해봐야 함.-c
option 으로 각각 컴파일해서 오브젝트 파일 만든 후에 한번에 링크 가능. 그리고 특정 파일만 수정했다면 그 파일만 다시 컴파일해서 다시 링크 가능 .c
의 경우 전처리, 컴파일, 어셈블이 수행된다. .i
의 경우 컴파일, 어셈블이 수행된다. .s
의 경우 어셈블이 수행된다.-std=XXX
: C++ standard version 지정-Wextra
,-Wall
: 필수-Wfloat-equal
: testing floating-point numbers for equality is bad (???)출처 :
https://stackoverflow.com/questions/3375697/what-are-the-useful-gcc-flags-for-c
-openmp
,-parallel
,출처:
COMPILER_PATH
: gcc는 COMPILER_PATH에 등록된 전처리기(cc1 -E), 컴파일러(cc1), 어셈블러(as), 링커(collect2, ld)를 찾는다. 따라서 export COMPILER_PATH={directory}를 통해 원하는 전처리기, 컴파일러, 어셈블러, 링커를 선택케 할 수 있다.C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH
: 소스 파일을 전처리 할 때 헤더파일을 찾을 디렉토리를 지정하는 환경변수이다.LIBRARY_PATH
: 라이브러리를 찾을 디렉토리를 지정하는 환경 변수이다.-O 옵션은 -ON(숫자)을 써줌으로써 최적화 단계를 구분할 수 있는데, N 값은 gcc 버전마다 차이가 나며 값이 커질수록 더욱 최적화된 코드가 나온다. 일반적으로, -O1, -O2를 많이 사용하며, -O1, -O2, -O3에 의한 최적화 내용은 다음과 같다.
machine dependent
옵션을 이용한 최적화-march={cpu_type} -mutne={cpu-type} -mcpu={cpu-type}:
gcc -O2 -o main main.c -fprofile-generate
를 통해 main 바이너리에 프로파일 정보를 출력하는 코드가 추가하여 컴파일한다.make
Makefile
Makefile
의 구성
Makefile 의 기본 구조
Makefile 작성규칙
목표파일 : 목표파일을 만드는데 필요한 구성요소들
(tab)목표를 달성하기 위한 명령 1
(tab)목표를 달성하기 위한 명령 2
// 매크로 정의 : Makefile에 정의한 string 으로 치환한다.
// 명령어의 시작은 반드시 탭으로 시작한다.
// Dependency가없는 target도 사용 가능하다.
Makefile 예제
여기서 더미타겟 은 파일을 생성하지 않는 개념적인 타겟으로 make clean
라 명령하면 현재 디렉토리의 모든 object 파일들과 생성된 실행파일인 diary_exe를 rm 명령어로 제거해 줍니다.
이제 make
로 Makefile을 실행해 줍니다.
Incremental build
Make 개선하기 : 매크로 사용 : 중복되는 파일 이름을 특정 단어로 치환
Make 개선하기2 : 내부 매크로 사용 (내부 매크로 훨씬 다양하게 많음)
./configure
./configure --prefix /usr/local/bin
로 설치 디렉토리 변경make distclean
치면 configure 설정 모두 제거 해 줌. 다시 configure
부터 시작하면 됨.중간 단계를 일일이 지정해줘야 하는 복잡한 Makefile
을 좀 더 편리하게 만들어 줌. 이를 위해서 CMakeLists.txt
작성해야 함. (Makefile 이 자체적으로 의존성을 파악하고 어느정도 자동화를 해주긴 하지만, Makefile 에 의존성 정보를 정확히 기재해줘야 함) CMake 를 쓰면 의존성 정보를 일일이 기술해 주지 않아도 됨.
프로젝트 처음 시작 시 Build Step 을 잘 구성해 놓으면, 이후에는 소스 파일 (*.c) 를 처음 추가할 때만 CMakeLists.txt 파일을 열어서 등록해 주면 됨. 이후에는 소스코드를 어떻게 수정하더라도 빌드에서 제외하지 않는 한 스크립트를 수정하지 않아도 됨.
CMake 도 Make 와 마찬가지로 의존성 검사를 해서 Incremental Build 를 수행하지만, 가장 큰 차이점은 CMake 는 소스파일 내부까지 들여다보고 분석해서 의존성 정보를 스스로 파악.
Makefile 에서는 빌드 중간 생성물인 Object 파일의 이름과 의존성까지 모두 기술해야 하지만 CMakeLists.txt 에서는 최종 빌드 결과물 (실행 바이너리, 라이브러리) 과 이를 빌드하기 위한 소스 파일 만 명시해주면 끝
CMake 는 Makefile 의 다소 지저분한 루틴들을 추상화해서 보다 직관적으로 빌드 과정을 기술 해 줌.. 일종의 Meta-Makefile.. 최종 빌드는 Make 와 마찬가지로 make 명령으로 수행. CMake 로 프로젝트 관리하면 CLion, Eclipse 와 같은 범용 IDE 에서 프로젝트 설정 파일로 사용 가능.
CMake 예제
//CMakeLists.txt
ADD_EXECUTABLE( app.out main.c foo.c bar.c )
cmake CMakeLists.txt
명령어 실행하면 Makefile
생성 됨.
make
명령으로 빌드
cmake CMakeLists.txt
명령은 자동 생성된 Makefile 을 삭제하지 않는 한 최초 한 번만 실행해 주면 됨. 생성된 Makefile 을 실행 할 때 CMakeLists.txt 파일의 변경 여부를 검사해서 필요한 경우 Makefile 을 자동으로 재생성 해 줌. 즉 cmake 명령은 최초 한 번만 사용.
CMake 내부 동작
Makefile, CMakeCache.txt, cmake_install.cmake ./CMakeFiles/
CMakeLists.txt
파일이 변경됬는지 여부를 검사하고, 변경 된 경우 Makefile 을 다시 생성하여 실행CMakeLists.txt 주요 명령과 변수 정리
SET (<변수명> <값>)
(값에 공백이 포함된 경우, 큰 따옴표 "..." 로 둘러주면 됨)$변수명 , ${<변수명>}
CMAKE_MINIMUM_REQUIRED ( VERSION <버전> )
: CMake 빌드 스크립트를 실행하기 위한 최소 버전 명시PROJECT ( <프로젝트명> )
: 프로젝트 이름 설정CMAKE_PROJECT_NAME
: PROJECT()
명령으로 설정한 프로젝트 이름이 이 변수에 저장 됨.CMAKE_BUILD_TYPE
: 빌드 형상 지정 (*빌드 형상: 빌드 목적(디버깅,배포) 에 따라 서로 다른 옵션을 지정해서 빌드하는 것으로, 대표적으로 Debug 와 Release 가 있음)MESSAGE( [<Type>] <메시지>)
:콘솔에 미시지나 변수를 출력. 디버깅 시 활용.CMAKE_VERBOSE_MAKEFILE
:true
, 1
로 지정하면 빌드 상세 과정을 모두 출력SET (CMAKE_VERBOSE_MAKEFILE true)
ADD_EXECUTABLE(<실행_파일명> <소스_파일> <소스_파일>)
: 빌드 최종 결과물로 생성 할 실행 파일 추가ADD_LIBRARY( <라이브러리_이름> [STATIC|SHARE|MODULE] <소스_파일> <소스_파일> ...)
: 빌드 최종 결과물로 생성 할 라이브러리 추가 ADD_LIBRARY (app STATIC foo.c bar.c)
: libapp.a 라는 이름의 라이브러리를 생성INSTALL ()
:make install
명령어 실행 할 때 무슨 동작 수행 할 지 지정.INSTALL ( TARGETS <Target_목록>
RUNTIME DESTINATION <바이너리_설치_경로>
LIBRARY DESTINATION <라이브러리_설치_경로>
ARCHIVE DESTINATION <아카이브_설치_경로>
)
SET (CMAKE_INSTALL_PREFIX /usr/bin)
: make install
에서 실행 바이너리, 라이브러리 등의 최종 생성물 복사 할 설치 디렉토리 지정. 지정하지 않으면 default 는 /usr/local
CMakeLists.txt 스크립트 기본 패턴
# 요구 CMake 최소 버전
CMAKE_MINIMUM_REQUIRED ( VERSION <버전> )
# 프로젝트 이름 및 버전
PROJECT ( "<프로젝트_이름>" )
SET ( PROJECT_VERSION_MAJOR <주_버전> )
SET ( PROJECT_VERSION_MINOR <부_버전> )
# 빌드 형상(Configuration) 및 주절주절 Makefile 생성 여부
SET ( CMAKE_BUILD_TYPE <Debug|Release> )
SET ( CMAKE_VERBOSE_MAKEFILE <true|false> )
# 빌드 대상 바이너리 파일명 및 소스파일 목록
SET ( OUTPUT_ELF
"${CMAKE_PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.out"
)
SET ( SRC_FILES
<소스_파일>
<소스_파일>
...
)
# 공통 컴파일러
SET ( CMAKE_C_COMPILER "<컴파일러>" )
# 공통 헤더 파일 Include 디렉토리 (-I)
INCLUDE_DIRECTORIES ( <디렉토리> <디렉토리> ... )
# 공통 컴파일 옵션, 링크 옵션
ADD_COMPILE_OPTIONS ( <컴파일_옵션> <컴파일_옵션> ... )
SET ( CMAKE_EXE_LINKER_FLAGS "<링크_옵션> <링크_옵션> ..." )
# 공통 링크 라이브러리 (-l)
LINK_LIBRARIES( <라이브러리> <라이브러리> ... )
# 공통 링크 라이브러리 디렉토리 (-L)
LINK_DIRECTORIES ( <디렉토리> <디렉토리> ... )
# "Debug" 형상 한정 컴파일 옵션, 링크 옵션
SET ( CMAKE_C_FLAGS_DEBUG "<컴파일_옵션> <컴파일_옵션> ..." )
SET ( CMAKE_EXE_LINKER_FLAGS_DEBUG "<링크_옵션> <링크_옵션> ..." )
# "Release" 형상 한정 컴파일 옵션, 링크 옵션
SET ( CMAKE_C_FLAGS_RELEASE "<컴파일_옵션> <컴파일_옵션> ..." )
SET ( CMAKE_EXE_LINKER_FLAGS_RELEASE "<링크_옵션> <링크_옵션> ..." )
# 출력 디렉토리
SET ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE} )
SET ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE}/lib )
SET ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE}/lib )
# 빌드 대상 바이너리 추가
ADD_EXECUTABLE( ${OUTPUT_ELF} ${SRC_FILES} )
project/
│
├── CMakeLists.txt # 최상위 CMakeLists 파일
├── src/ # 소스 코드 디렉토리
│ ├── CMakeLists.txt # 소스 코드 디렉토리의 CMakeLists 파일
│ ├── library1/ # 라이브러리 1 소스 코드
│ ├── library2/ # 라이브러리 2 소스 코드
│ └── executable/ # 실행 파일 소스 코드
├── include/ # 공통 헤더 파일 디렉토리
│ └── mylibrary/ # 라이브러리의 헤더 파일
├── build/ # 빌드 디렉토리 (컴파일된 파일들을 저장)
└── external/ # 외부 종속성 및 라이브러리 디렉토리
├── libraryA/ # 외부 라이브러리 A
└── libraryB/ # 외부 라이브러리 B
main()
함수가 포함된 소스 드출처 :
- 컴파일러 기초 :
https://bradbury.tistory.com/226- 컴파일러의 이해 (책) :
https://www.yes24.com/Product/goods/24330311?scode=029- 컴파일러 최적화 (내공 있는 프로그래머로 길러주는 컴파이럴의 이해, 요약) :
http://www.kwangsiklee.com/2018/06/%ec%bb%b4%ed%8c%8c%ec%9d%bc%eb%9f%ac-%ea%b0%95%ec%9d%98-9-%ec%bd%94%eb%93%9c-%ec%b5%9c%ec%a0%81%ed%99%94/- Compiler optimizations can be misleading :
https://medium.com/@techhara/compiler-optimizations-can-be-tricky-ee323415e6a- 환경 변수를 사용한 gcc 설정
https://jayy-h.tistory.com/9?_sc_token=v2%253ADJVligtLxXBl1gmGvMuFlPV4b7N8J4WNAPfAN9aCpPmGEMyL8xFiezArvbuZxTpB_CXLDp94HZV78bmcoj8SzDL5aJND38DIy6If1pWWncmgFn-rd532LJgXiWTZKDKysIaUzMcIfEfQN-dRIVgYculidcrUPslIr20tmOnw3ts%253D- gcc 기본 옵션 정리 (가시성 굿)
https://velog.io/@yoopark/gcc-options- make 와 Makefile (정리 잘 되어 있음)
https://bowbowbow.tistory.com/12- configure, make, make install 설명 (정리 잘 되어 있음)
https://positivemh.tistory.com/462- Makefile (상세, 추천)
https://www.tuwlab.com/27193?_sc_token=v2%253AL6oCyG2C256RSPHgRKGXRvashwdyW0w3i5XVjvqITPTBlNym893CLc3rva5AitZv3MvqLPQ8z3260452ycM-l5enMk89lLFyVWAaraqSCm47aSVFrjYtRt0h_7nocAgn5bmfvLRp0lsauUJ42JQCQzY3-xAGOStaqhMN01UYPBU%253D- CMakefile (상세, 추천)
https://www.tuwlab.com/27234
추후 볼 것:
-fp-model=fast
or -ffast-math
, -O2
, -fveclib=SVML
-fp-model=precise
,-O0
)-fast
-ipo,-Ofast,-static,-fp-model,fast=2, -xHost
를 설정.-xHost
옵션 때문에)O2
-Ofast
-O3
보다 더 나아가서, aggresive option 을 설정함.-x<>
-xCORE-AVX512
**-ax
-x
같은건데 더 개선이 있을때만 적용...? (평가해보기)-march=<>
-x
랑 뭐가 다른거지..?-xHost
-x<>
,-march
,-mtune
옵션을 자동으로 실행한다고 보면 됨.)-mauto-arch=<>
ax
옵션 값 아무거나-x, -ax
와는 동시 사용 불가0
: report 안 함.1
: 최소로 report-qopt-report-file=<>
filename
: 파일 이름 입력stderr
stdout
출처 :
https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2023-2/optimization-options.html
https://hackernoon.com/ko/%EC%B5%9C%EC%86%8C%ED%95%9C%EC%9D%98-%EC%A1%B0%EC%A0%95%EC%9C%BC%EB%A1%9C-%EC%BD%94%EB%93%9C-%EC%84%B1%EB%8A%A5%EC%9D%84-%ED%96%A5%EC%83%81%EC%8B%9C%ED%82%A4%EB%8A%94-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%B5%9C%EC%A0%81%ED%99%94 (추천)
flto
-fno-lto
-ipo
-flto
를 자동으로 설정.-no-ipo
-O2, -static
-xHost
적용 : AVX2(?) 에서 AVX512 사용, 0.6% 속도 개선-ipo
적용 : 2.5% 속도 개선-xHost, -Ofast
적용 : 2.8% 속도 개선-xHost, -Ofast, -ipo
적용 : 3.1% 속도 개선-Wall
-Werror
-Wshadow
,-Wno-shadow
-Wno-shadow
-qopenmp
option 으로 OpenMP 사용math
library 호출 제외) (inline 시키면 괜찮음)void no_vec(float a[], float b[], float c[]) {
int i = 0;
while (i < 100) {
if (a[i] < 50)
// The next statement is a second exit
// that allows an early exit from the loop.
break;
++i;
}
}
void no_cnt(float a[], float b[], float c[]) {
int i=0;
// Iterations dependent on a[i].
while (a[i]>0.0) {
a[i] = b[i] * c[i];
i++;
}
}
for
loop 에서 exit condition (ex:upper limit) 이 iteration 마다 변하면 안됨.switch,goto,return,if
, function call 지양pointer
대신에 array notation
활용Array of Structure
대신에 Structure of Array
활용acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, ceil, cos, cosh, erf, erfc, erfinv, exp, exp2, fabs, floor, fmax, fmin, log, log2, log10, pow, round, sin, sinh, sqrt, tan, tanh, trunc
#pragma ivdep
)#pragma simd
)F32vec4 add
)mm_add_ps()
)출처 :
https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2023-2/vectorization-programming-guidelines.html
https://www.intel.com/content/www/us/en/docs/dpcpp-cpp-compiler/developer-guide-reference/2023-2/user-mandated-or-simd-vectorization.html
stdio.h
와 같은 GNU hearder file, linker, librarries) 따라서 system 의 GCC, G++ version 과 호환이 되야함. 기본적으로 PATH
환경변수에를 통해 GCC,G++ 를 찾음. 다른 버전의 gcc 를 쓰고 싶으면 -gcc-toolchain
컴파일 옵션을 활용해서 경로 지정.