캐시 최적화의 중요성
캐시 최적화는 프로그램의 성능을 극대화하는 데 매우 중요한 역할을 합니다. 캐시 메모리는 CPU가 메인 메모리보다 훨씬 빠르게 접근할 수 있는 작은 크기의 고속 메모리입니다. 데이터 로컬리티를 높여 캐시 히트율을 최대화하면 프로그램의 실행 속도가 크게 향상됩니다.
데이터 로컬리티
데이터 로컬리티는 CPU가 데이터를 빠르게 접근할 수 있도록 데이터를 메모리에 배치하는 방법을 의미합니다. 데이터 로컬리티에는 두 가지 유형이 있습니다.
- 시간적 로컬리티 (Temporal Locality): 최근에 접근한 데이터에 다시 접근하는 경향이 있는 경우.
- 공간적 로컬리티 (Spatial Locality): 가까운 메모리 주소에 있는 데이터에 접근하는 경향이 있는 경우.
캐시 최적화 기법
1. 연속된 메모리 할당
연속된 메모리 할당은 배열과 같이 연속적인 메모리 블록을 사용하는 것을 의미합니다. 연속된 메모리 블록을 사용하면 공간적 로컬리티가 증가하여 캐시 히트율이 높아집니다.
비최적화 코드
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
std::vector<int*> data(size);
for (int i = 0; i < size; ++i) {
data[i] = new int(i);
}
long long sum = 0;
for (int i = 0; i < size; ++i) {
sum += *data[i];
}
std::cout << "Sum: " << sum << std::endl;
for (int i = 0; i < size; ++i) {
delete data[i];
}
return 0;
}
최적화 코드
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
std::vector<int> data(size);
for (int i = 0; i < size; ++i) {
data[i] = i;
}
long long sum = 0;
for (int i = 0; i < size; ++i) {
sum += data[i];
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
2. 루프 스트라이딩 줄이기
루프 스트라이딩이란 루프에서 큰 단계로 인덱스를 증가시키는 것을 의미합니다. 작은 단계로 인덱스를 증가시키면 캐시 히트율이 높아집니다.
비최적화 코드
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
const int stride = 16;
std::vector<int> data(size, 1);
long long sum = 0;
for (int i = 0; i < size; i += stride) {
sum += data[i];
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
최적화 코드
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
std::vector<int> data(size, 1);
long long sum = 0;
for (int i = 0; i < size; ++i) {
sum += data[i];
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
3. 데이터 구조 최적화
연결 리스트와 같은 데이터 구조는 캐시 효율이 낮습니다. 배열이나 벡터와 같은 연속된 데이터 구조를 사용하는 것이 좋습니다.
비최적화 코드
#include <iostream>
#include <list>
int main() {
const int size = 1000000;
std::list<int> data;
for (int i = 0; i < size; ++i) {
data.push_back(i);
}
long long sum = 0;
for (auto& val : data) {
sum += val;
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
최적화 코드
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
std::vector<int> data(size);
for (int i = 0; i < size; ++i) {
data[i] = i;
}
long long sum = 0;
for (int i = 0; i < size; ++i) {
sum += data[i];
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
실습 문제
문제 1: 캐시 최적화 적용하기
다음 코드는 데이터 구조가 비효율적으로 사용되고 있습니다. 이를 최적화하여 캐시 효율을 높여보세요.
main.cpp
#include <iostream>
#include <vector>
#include <list>
int main() {
const int size = 1000000;
std::list<int> data;
for (int i = 0; i < size; ++i) {
data.push_back(i);
}
long long sum = 0;
for (auto& val : data) {
sum += val;
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
해답:
main.cpp (최적화)
#include <iostream>
#include <vector>
int main() {
const int size = 1000000;
std::vector<int> data(size);
for (int i = 0; i < size; ++i) {
data[i] = i;
}
long long sum = 0;
for (int i = 0; i < size; ++i) {
sum += data[i];
}
std::cout << "Sum: " << sum << std::endl;
return 0;
}
이제 네 번째 날의 학습을 마쳤습니다. 캐시 최적화의 중요성과 다양한 최적화 기법을 이해하고, 실습 문제를 통해 이해를 높였습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "메모리 관리 최적화"에 대해 학습하겠습니다.
'-----ETC----- > C++ 성능 최적화 및 고급 테크닉 시리즈' 카테고리의 다른 글
[C++ 성능 최적화 및 고급 테크닉] Day 6: 불필요한 복사 방지 (copy elision) (0) | 2024.08.01 |
---|---|
[C++ 성능 최적화 및 고급 테크닉] Day 3: 코드 프로파일링 및 벤치마킹 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 2: 컴파일러 최적화 옵션 이해하기 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 1: 성능 최적화의 중요성 및 기본 원칙 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] 목차 (0) | 2024.06.20 |