C++20에서는 코드의 성능과 가독성을 향상시키기 위한 다양한 기능이 도입되었습니다. 그중에서도 [[likely]]와 [[unlikely]] 속성은 조건문의 분기 예측을 컴파일러에 힌트로 제공하여 최적화를 도울 수 있습니다. 이번 글에서는 이 속성들의 개념과 사용법, 그리고 이전 버전과 비교하여 어떻게 개선되었는지 알아보겠습니다.

[[likely]]와 [[unlikely]]란 무엇인가요?
[[likely]]와 [[unlikely]]는 C++20에서 도입된 속성(attribute)으로, 조건문에서 어떤 분기(branch)가 더 자주 실행될 것인지 컴파일러에 힌트를 제공하는 역할을 합니다. 이를 통해 컴파일러는 분기 예측(branch prediction)을 최적화하여 실행 성능을 향상시킬 수 있습니다.
이전 버전에서는 어떻게 했나요?
C++20 이전에는 개발자가 분기 예측을 최적화하기 위해 컴파일러별 확장이나 비표준 함수들을 사용해야 했습니다.
예제: 이전 방식으로 분기 예측 힌트 제공
// GCC와 Clang에서 제공하는 매크로 사용
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
int process(int value) {
if (LIKELY(value > 0)) {
// 자주 실행되는 코드
} else {
// 드물게 실행되는 코드
}
return 0;
}
- 문제점:
- 이식성 부족: __builtin_expect는 GCC와 Clang에서만 지원되며, 다른 컴파일러에서는 동작하지 않습니다.
- 가독성 저하: 매크로와 비표준 함수를 사용하여 코드가 복잡해집니다.
- 표준화되지 않음: 표준 C++ 문법이 아니므로 코드 유지 보수에 어려움이 있습니다.
C++20의 [[likely]]와 [[unlikely]]를 사용한 개선
C++20에서는 표준 속성으로 [[likely]]와 [[unlikely]]가 도입되어, 컴파일러에 분기 예측 힌트를 제공할 수 있습니다.
예제: [[likely]]와 [[unlikely]] 사용
int process(int value) {
if (value > 0) [[likely]] {
// 자주 실행되는 코드
} else {
// 드물게 실행되는 코드
}
return 0;
}
- [[likely]]와 [[unlikely]]를 조건문 바로 뒤에 위치시켜 사용합니다.
- 컴파일러는 해당 분기가 더 자주 또는 드물게 실행된다는 힌트를 받아 최적화를 수행할 수 있습니다.
어떻게 좋아졌나요?
- 이식성 향상: 표준 C++ 문법이므로 모든 컴파일러에서 동작합니다.
- 가독성 개선: 코드에 직접적으로 힌트를 제공하므로 이해하기 쉽습니다.
- 유지 보수성 증가: 비표준 확장이나 매크로를 사용할 필요가 없어 코드 유지 보수가 용이합니다.
- 최적화 도움: 컴파일러가 분기 예측을 최적화하여 실행 성능을 향상시킬 수 있습니다.
상세한 예제와 비교
1. 복잡한 조건문에서의 사용
이전 방식
if (LIKELY(status == SUCCESS)) {
// 성공 처리
} else if (status == WARNING) {
// 경고 처리
} else {
// 오류 처리
}
C++20 방식
if (status == SUCCESS) [[likely]] {
// 성공 처리
} else if (status == WARNING) {
// 경고 처리
} else [[unlikely]] {
// 오류 처리
}
- 각 분기에 적절한 힌트를 제공하여 컴파일러의 최적화를 돕습니다.
2. 반복문에서의 사용
for (int i = 0; i < n; ++i) {
if (should_continue(i)) [[likely]] {
// 반복 실행되는 코드
} else {
break; // 드물게 실행되는 코드
}
}
- 반복문 내에서도 [[likely]]와 [[unlikely]]를 사용하여 분기 예측을 최적화할 수 있습니다.
주의 사항
- 과도한 사용 지양: [[likely]]와 [[unlikely]]는 힌트일 뿐이며, 컴파일러가 반드시 이를 따르는 것은 아닙니다. 과도한 사용은 오히려 최적화에 방해가 될 수 있습니다.
- 정확한 판단 필요: 해당 분기의 실행 빈도를 정확히 예측하여 사용해야 합니다. 잘못된 힌트는 성능 저하를 유발할 수 있습니다.
- 가독성 고려: 코드의 가독성을 해치지 않도록 주의해야 합니다. 필요하지 않은 경우 사용을 자제하는 것이 좋습니다.
[[likely]]와 [[unlikely]]의 동작 원리
- 컴파일러는 조건문에서 분기 예측 힌트를 받아 코드 배치와 파이프라인 최적화를 수행합니다.
- 자주 실행되는 코드를 연속적으로 배치하여 캐시 적중률을 높이고, 분기 예측 실패로 인한 성능 저하를 방지합니다.
요약
C++20의 [[likely]]와 [[unlikely]] 속성은 분기 예측에 대한 힌트를 표준화된 방식으로 제공하여 코드의 성능과 가독성을 향상시킵니다. 이전 버전에서는 비표준 확장이나 매크로를 사용해야 했지만, 이제는 표준 C++ 문법으로 안전하고 이식성 있게 분기 예측 최적화를 도울 수 있습니다. 하지만 힌트는 어디까지나 힌트일 뿐이며, 실제 성능 개선은 상황에 따라 다를 수 있으므로 주의해서 사용해야 합니다.
참고 자료:
'개발 이야기 > C++' 카테고리의 다른 글
[C++23 새기능 소개] std::print와 std::println 함수 (0) | 2024.12.08 |
---|---|
[C++20 새기능 소개] 비타입 템플릿 매개변수에 auto사용 (0) | 2024.12.08 |
[C++20 새기능 소개] constexpr의 컨테이너 (std::vector, std::string) 지원 (0) | 2024.12.08 |
[C++20 새기능 소개] 클래스 템플릿의 인자 추론 (Class Template Argument Deduction, CTAD) (0) | 2024.12.07 |
[C++20 새기능 소개] 개선된 <chrono> (0) | 2024.12.06 |