CPU 아키텍처(CPU Architecture)에 따라 C/C++ 소프트웨어 성능을 최적화하는 다양한 기법 소개
컴파일러(Compiler)를 활용하여 특정 CPU에 맞게 코드를 빌드하거나, IFUNC를 사용하여 런타임에 최적의 함수 선택
인스트린식(Intrinsics)을 직접 사용하여 AVX2와 같은 명령어 집합을 활용하는 방법 제시
GCC/Clang 컴파일러의 `target_clones` 속성을 활용하여 여러 버전의 함수를 생성하고, 런타임에 적합한 버전을 선택하는 방법 설명
저자는 IFUNC(Indirect Function)를 사용하여 런타임에 CPU의 기능을 감지하고, 최적의 함수 버전을 선택하는 방법을 제시한다. 특히, `__attribute__((ifunc("resolve_my_func")))` 구문을 통해 컴파일러가 링킹 시점에 적절한 함수를 선택하도록 한다. 이를 통해, 개발자는 CPU 아키텍처(CPU Architecture)의 변화에 유연하게 대응하며, 성능 저하(Performance Degradation) 없이 최적의 코드를 실행할 수 있다. 또한, MUSL libc는 IFUNC를 아직 지원하지 않는다는 점을 언급하며, 플랫폼별 호환성 문제를 강조한다.
게시물에서는 컴파일러의 `-march=native` 옵션을 사용하여 특정 CPU 마이크로아키텍처에 맞게 코드를 최적화하는 방법을 소개한다. 또한, `target_clones` 속성을 사용하여 여러 버전의 함수를 생성하고, 런타임에 적합한 버전을 선택하는 방법을 설명한다. 이러한 기법은 개발자가 다양한 CPU 환경(CPU Environment)에서 최적의 성능을 유지하면서, 코드의 이식성(Code Portability)을 확보하는 데 도움을 준다. 특히, C23 표준의 `[[gnu::target_clones("avx2,default")]]` 구문을 통해 간결하게 구현할 수 있음을 강조한다.
저자는 인스트린식(Intrinsics)을 사용하여 AVX2와 같은 특정 명령어 집합을 직접 활용하는 방법을 설명한다. 이를 위해, `#ifdef __AVX2__`와 같은 전처리기 지시어를 사용하여 컴파일러가 지원하는 기능을 확인하고, 해당 기능을 사용하는 코드를 작성한다. 이러한 방식은 개발자가 세밀한 제어(Fine-grained Control)를 통해 성능을 극대화할 수 있게 해주지만, 코드의 복잡성(Code Complexity)을 증가시키고, 유지 보수(Maintenance)를 어렵게 만들 수 있다. 또한, GCC와 Clang 컴파일러에서 `pragma` 지시어를 사용하여 인스트린식을 활성화하는 방법을 제시한다.
게시물에서는 x86-64 아키텍처의 마이크로아키텍처 레벨(Microarchitecture Levels)을 소개하며, 각 레벨이 지원하는 명령어 집합을 설명한다. x86-64-v1부터 x86-64-v4까지의 레벨을 제시하며, 각 레벨이 지원하는 기능(예: POPCNT, SSE4.2, AVX2, AVX-512)을 구체적으로 언급한다. 이러한 정보는 개발자가 타겟 CPU(Target CPU)의 기능을 파악하고, 최적화 전략(Optimization Strategy)을 수립하는 데 도움을 준다. 또한, 인텔과 AMD의 CPU 간의 기능 차이와, 특정 기능의 느린 구현(예: AMD의 BMI2)에 대한 주의를 강조한다.