C++ 게임 서버 프로그래밍: 캐시 효율성 이해하기

나무에물주기·2023년 6월 17일
1
post-thumbnail

필요한 헤더 파일들은 다음과 같습니다.

#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
#include <windows.h>

캐시는 프로세서 가까이에 위치하여 데이터를 임시로 저장하는 고속 메모리입니다. 이번에는 캐시의 공간 지역성(Spatial Locality) 원리를 이용하여 두 가지 다른 방식으로 2차원 배열을 순회하는 예제를 살펴보겠습니다.

int32 buffer[10000][10000];

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

    {
        uint64 start = GetTickCount64();

        int64 sum = 0;

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

        uint64 end = GetTickCount64();
        cout << "Elapsed Tick " << (end - start) << '\n';
    }

    {
        uint64 start = GetTickCount64();

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

        uint64 end = GetTickCount64();
        cout << "Elapsed Tick " << (end - start) << '\n';
    }
}

위 코드는 크게 두 가지 부분으로 나눌 수 있습니다. 첫 번째 부분은 행 우선 순회를, 두 번째 부분은 열 우선 순회를 통해 배열을 순회하며 합을 구합니다.

행 우선 순회는 캐시 메모리의 공간 지역성 원리에 따라 배열이 메모리에 연속적으로 저장되므로 캐시 효율성이 높습니다. 반면에, 열 우선 순회는 이 원리에 부합하지 않아 캐시 미스가 더 자주 발생하며, 따라서 속도가 느려집니다.

공간 지역성(Spatial Locality) 원리

공간 지역성 원리는 프로그램이 메모리에 인접한 위치에 있는 데이터를 참조할 확률이 높다는 것을 의미합니다. 이 원리를 이용하면 데이터를 미리 캐시에 불러오는 프리페치 기능 등을 통해 메모리 접근 시간을 줄일 수 있습니다.

행 우선 순회 vs 열 우선 순회

행 우선 순회

이 방식은 2차원 배열에서 행 방향으로 데이터를 읽는 방법입니다. 메모리는 일렬로 이루어져 있기 때문에, 행 우선 순회는 메모리에 연속적으로 저장된 데이터를 순차적으로 접근합니다. 따라서 캐시 효율성이 높아집니다.

아래 코드는 행 우선 순회 방식으로 2차원 배열을 순회하는 예시입니다.

uint64 start = GetTickCount64();

int64 sum = 0;

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

uint64 end = GetTickCount64();
cout << "Elapsed Tick " << (end - start) << '\n';

실행 결과를 보면, 이 방식은 열 우선 순회 방식에 비해 속도가 빠른 것을 확인할 수 있습니다.

열 우선 순회

이 방식은 2차원 배열에서 열 방향으로 데이터를 읽는 방법입니다. 메모리는 일렬로 이루어져 있기 때문에, 열 우선 순회는 메모리 접근이 불연속적이게 됩니다. 이로 인해 캐시 미스가 더 자주 발생하고, 따라서 속도가 느려집니다.

아래 코드는 열 우선 순회 방식으로 2차원 배열을 순회하는 예시입니다.

uint64 start = GetTickCount64();

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

uint64 end = GetTickCount64();
cout << "Elapsed Tick " << (end - start) << '\n';

실행 결과를 보면, 이 방식은 행 우선 순회 방식에 비해 속도가 느린 것을 확인할 수 있습니다.

캐시 메모리의 특성 이해하기

캐시 메모리는 중앙처리장치(CPU)와 주기억장치 사이에 위치하여 데이터 처리 속도의 격차를 줄이는 역할을 합니다. 캐시 메모리는 접근 속도가 빠르지만 비용이 비싸서 크기가 작습니다. 그렇기 때문에 가장 최근에 사용된 데이터 또는 가장 자주 사용되는 데이터를 저장하여 CPU가 빠르게 접근할 수 있도록 합니다.

캐시 메모리의 핵심 원리 중 하나는 '공간 지역성(Spatial Locality)'입니다. 이 원리는 프로그램이 메모리의 특정 위치에 접근했다면, 가까운 미래에 그 위치 근처에 있는 메모리에 다시 접근할 가능성이 높다는 것을 의미합니다. 따라서, 이 원리를 이해하고 있으면 캐시 메모리를 효과적으로 사용하여 프로그램의 성능을 향상시킬 수 있습니다.

profile
개인 공부를 정리함니다

0개의 댓글