KoreanFoodie's Study

[C++ 게임 서버] 1-12. 캐시 (Temporal Locality, Spatial Locality) 본문

Game Dev/Game Server

[C++ 게임 서버] 1-12. 캐시 (Temporal Locality, Spatial Locality)

GoldGiver 2023. 7. 19. 16:35

Rookiss 님의 '[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버' 를 들으며 배운 내용을 정리하고 있습니다. 관심이 있으신 분은 꼭 한 번 들어보시기를 추천합니다!

[C++ 게임 서버] 1-12. 캐시 (Temporal Locality, Spatial Locality)

핵심 :

1. RAM 으로부터 데이터를 가져올 때, 자주 쓰일 것으로 예상되는 데이터는 캐시에 저장된다

2. 캐싱 철학에는 Temporal Locality 와 Spatial Locality 가 있는데, 각각 '최근에 사용된 녀석은 다시 사용될 확률이 높다' , '메모리상으로 가까이 있는 녀석은 함께 사용될 확률이 높다' 라는 추론을 기반으로 한다.

3. 실제 메모리 조회를 할 때는 위의 Temporal Locality 와 Spatial Locality 를 고려하여 설계를 하는 것이 좋다.

흔히 우리는 캐시를 통해 값을 조회할 때, 우리가 필요한 정보만 얻어올 것이라고 기대하지만, 실제로는 그렇지 않다.

우리가 원하는 택배 박스는 1개일지 몰라도, 택배 기사님들이 한 동 전체의 택배박스들을 전부 들고 오는 것처럼, 비슷한 위치에 배달할 박스가 같이 딸려 오는 식으로 동작한다. 😀

또한 시간 상으로도, 최근에 배달을 시킨 주소는 다시 시킬 확률이 높다고 하여 이를 캐시에 저장하기도 하는데... 이러한 캐시의 특성을 각각 Temporal Locality, Spatial Locality 라고 부른다!

 

캐시와 메모리 쪽의 구조를 간략한 모식도로 표현하면 아래와 같다 : 

즉, 어떤 연산을 위해 RAM 으로부터 CPU 로 데이터를 옮길 때, 자주 쓰일 것으로 예상되는 것들을 캐시에 저장해 놓았다가, CPU 가 이를 다시금 필요로 할때 캐시를 먼저 조회하는 것이다! 😉

 

아래 코드는 Temporal Locality 의 특성을 보여주는 예제이다. 즉, 행렬이 있다고 했을 때 순차적으로 행을 하나하나 조회하는 것이 열을 순차적으로 조회하는 것보다 더 효율적임을 알 수 있다!

int buffer[10000][10000];

int main()
{
	memset(buffer, 0, sizeof(buffer));

	{
		int64 start = GetTickCount64();

		int sum = 0;
		for (int i = 0; i < 10000; ++i)
		{
			for (int j = 0; j < 10000; ++j)
			{
				sum += buffer[i][j];
			}
		}

		int64 end = GetTickCount64();

		cout << "Tick : " << end - start << endl;
	}

	{
		int64 start = GetTickCount64();

		int sum = 0;
		for (int i = 0; i < 10000; ++i)
		{
			for (int j = 0; j < 10000; ++j)
			{
				sum += buffer[j][i];
			}
		}

		int64 end = GetTickCount64();

		cout << "Tick : " << end - start << endl;
	}

}

결과를 보면, 필요 Tick 수가 약 3배 정도 차이가 난다! 😮

Comments