Thursday, July 27, 2006

softgear

최근의 모든 CPU에는 캐쉬를 가지고 있다. 이 캐쉬의 효율을 높힐 수록 프로그램의 성능이 높아진다. 일반적으로 컴파일러가 캐쉬를 위한 최적화를 수행하지만, 임베디드 시스템용 컴파일러나, 최적화 옵션을 하지 않은 경우의 컴파일에서는 최적화가 되지 않을 수 있다. 그러므로 프로그래머가 약간만 신경을 쓰면 캐쉬 효율을 상당히 높힐 수 있다.
캐쉬는 CPU내부에 들어 있는 메모리로 일반 RAM보다 빠르다. 그러므로, 자주 사용되는 부분을 캐쉬내에 넣어서 처리를 하면, 일반 RAM에 억세스 해서 동작하는 것보다 빠르게 명령을 수행할 수 있는 것이다.

Loop Interchage - 2중 이상의 Loop가 있을때, 그 순서를 바꾸는 방법이다. C컴파일러에서 2차원이상의 배열은 Row와 Column이 선형적으로 메모리상에 위치하는 데, 예를 들어 a[3][2] 이라는 배열은 메모리상에 a[0][0],a[0][1],a[1][0],a[1][1],a[2][0],a[2][1]과 같은 순서로 위치한다. 결국 a[M][N] 배열에서 a[i][j]의 위치는 p= i*N + j 가 된다. CPU가 특정 메모리 주소에 접근할 때 캐쉬에 없을 경우 메모리로부터 캐쉬로 데이터를 가져온다. 근데 1바이트나 워드로 가져오는 것이 아니라 왕창 즉 캐쉬 라인 사이즈 만큼 메모리로부터 캐쉬로 데이터를 가져온다. 그러므로, 프로그램은 억세스하는 메모리의 변화가 적게끔 하면 할수록, 캐쉬의 효율이 높아진다. 다음 루프 예를 보자.
for (j=0; j < N; j++)
for (i=0; i < M; i++)
a[i][j] = a[i][j] + b[i][j];
이 경우, 배열a와 배열b의 Row가 먼저 바뀌게 되므로, 메모리 접근이 왔다 갔다 하게 된다. 캐쉬의 크기는 작으므로, Cache miss가 많아져서 캐쉬 효율이 떨어진다. 다음과 같은 형태로 루프를 만들면 쉽게 문제가 해결된다.
for (i=0; i < M; i++)
for (j=0; j < N; j++)
a[i][j] = a[i][j] + b[i][j];

Loop Fusion - 동일한 메모리를 접근하는 루프가 별도로 2개가 있는 경우, 이 2개를 합치면 캐쉬효율이 높아진다. 예를 들어 다음 루프를 보자.
for (i=0; i < M; i++)
c[i] = c[i] + d[i];
for (i=0; i < M; i++)
c[i] = c[i] + e[i];
위 두 루프를 하나로 합치면 다음과 같이 다시 쓸 수 있다.
for (i=0; i < M; i++) {
c[i] = c[i] + d[i];
c[i] = c[i] + e[i];
}

기타 방법들
- 루프안에서 동일한 인덱스로 사용되는 여러 배열변수가 있을 경우에는 배열대신에 구조체를 만들어서 구조체의 배열을 사용한다.
- 다중 루프안에 여러변수가 사용되는 경우, 루프를 블럭단위로 구성하여, 접근하는 메모리 주소의 범위를 좁힌다.
- 불필요한 변수 또는 배열을 줄인다. 임시적으로 사용되는 변수가 CPU의 Register로 되도록 한다.

No comments :