CPU에는 캐시메모리가 있죠.

캐시메모리는 간단하게 설명하면 RAM보다 더 빠른 메모리로 시간적 지역성과 공간적 지역성을 이용해 자주 쓰일 데이터를 미리 가져와 더 빠른 접근이 가능하게 합니다.

시간적 지역성은 예를들어 함수나 반복문에 있는 명령어들이 그 예로 해당 명령어들은 반복해서 참조될 가능성이 높고 시간적 지역성이 높다고 말합니다.

공간적 지역성은 예를들어 배열같은 것이 그 예로 A[0]이 참조된 경우 A[1] 또한 곧 참조될 가능성이 높고 공간적 지역성이 높다고 말합니다.

캐시 메모리에 대한 자세한 동작 원리는 https://parksb.github.io/article/29.html에서 확인하실 수 있습니다.


이번 글에서는 간단한 프로그램 두개를 만들어 캐시메모리의 효과를 확인해 보겠습니다.


첫번째는

입니다.

이 프로그램은 단순히 2차원 1000 * 64 int 배열을 0부터 99999까지 한번씩 채우는 프로그램입니다.


두번째는


입니다.


차이가 보이시나요?

이 프로그램은 위 프로그램에서 두번째와 세번째 반복문의 위치를 바꾼 것입니다.

결과적으로는 2차원 1000 * 64 int 배열을 0부터 99999까지 한번씩 채우는 것은 똑같습니다.

그러나 채우는 순서가 차이가 있는데

첫번째 프로그램은 x[0][0] -> x[0][1] -> x[0][2] -> ... -> x[0][63] -> x[1][0] -> x[1][1] -> ... -> x[999][63]의 순서로 채우고

두번째 프로그램은 x[0][0] -> x[1][0] -> x[2][0] -> ... -> x[999][0] -> x[0][1] -> x[1][1] -> ... -> x[999][63]의 순서로 채웁니다.


보통 프로그램을 짜실때 대부분 첫번째 방법으로 짜실텐데 그것이 캐시 메모리를 활용하는데 더 좋은 방법입니다.

왜냐하면 2차원 배열을 선언하면 전부 연속적인 할당되며 가장 왼쪽 인덱스의 차이가 적을수록 가까이 있기 때문입니다.

예를들어 x[1000][64]가 메모리 0x00000000부터 할당된다면

0x00000000은 x[0][0], 0x00000004은 x[0][1], 0x00000008은 x[0][2], ...

으로 할당되고 첫번째 프로그램과 같은 순서로 채우게 된다면 이는 공간적 지역성을 완벽하게 이용하고 있는 것이고 높은 캐시 히트율로 더 빠른 프로그램이 됩니다.

두번째 프로그램은 이것을 무시하고 캐시메모리의 사용을 의도적으로 방해한 것으로 공간적 지역성을 완전히 무시하고 있기 때문에 낮은 캐시 히트율로 더 느린 프로그램이 됩니다.


실제 두 프로그램을 컴파일하여 실행해 보면


첫번째는 

의 결과를 보이며

두번째는

의 결과를 보입니다.


이로써 두번째 프로그램은 첫번째 프로그램 대비 약 33% 느린 실행 시간을 보이는 것을 알 수 있고

캐시메모리를 효과적으로 이용했을때 더 빠른 프로그램이 될 수 있음을 확인할 수 있습니다.