struct linked { struct linked *next; int data[7]; int big_data[1000]; };이런 자료 구조가 있다고 해봅니다.
struct linked { struct linked *next; int data[7]; int *big_data; };그렇다면 data 멤버까지 포인터로 바꾸면 어떨까요?
struct linked { struct linked *next; int *data; int *big_data; };이 경우엔 처음 최적화한 것보다 성능이 떨어집니다. 기억하세요. 리스트를 탐색하면서 next와 data 멤버에 접근한다고 얘기했습니다. data 멤버를 포인터로 변경할 경우 포인터 주소를 해석하는 과정이 추가로 발생하기 때문에 오히려 성능이 떨어집니다. 구조체의 크기가 매우 큰 경우에 배열 요소를 포인터로 변경하는 방법으로 크기를 최적화하면 성능이 향상됩니다.
struct linked { struct linked *next; int data; }이 구조체의 경우엔 모두 캐시 사이즈에 들어갑니다. 이 때에는 data 멤버 리스트를 분할해서 최대한 많은 개수의 next 멤버가 같은 캐시 라인에 올라가게 하는 방법을 사용합니다. 이 때에는 다른 멤버에는 접근하지 않는 경우에만 적용됩니다. 그러니, 매우 한정적인 방법입니다.
struct linked { struct linked *next; int *data; }이와 같이 선언하여 리스트를 두 가지로 나누는 방법을 사용합니다.
list[ indx ].next = value; list[ indx ].data = value;와 같은 형태의 접근을 다음과 같이 변경합니다.
list.next[ indx ] = value; list.data[ indx ] = value;긴 리스트를 짧은 리스트로 바꾸는 방법으로 메모리 접근을 최적화하는 방법입니다. L2 캐시 라인은 최소 32 바이트입니다. 만약, 데이터가 32 바이트를 넘어간다면 다음 캐시 라인으로 이동하게 되는데 이는 메모리에서 라인을 변경하는 데 따른 지연시간이 있기 때문에 같은 캐시 라인을 접근하는 것에 비해 더 많은 시간이 걸립니다.
struct linked *list = malloc( 100000 * sizeof( struct linked );와 같이 선언하고 10만개의 리스트를 탐색한다면 코드는 다음과 같습니다.(초기화는 생략했습니다)
struct linked *current = NULL; current = list; while( current = current[0].next ); // 리스트 탐색두번째와 같은 형태를 사용하게 되면 다음과 같습니다.
while( current = current.next[0] ); // 리스트 탐색이런 종류의 최적화는 CPU 아키텍처에 따라 편차가 큽니다. P-III 아키텍처에서는 70%의 성능 향상이 있지만, 코어2듀오에서는 10% 정도의 성능 향상이 있습니다.
이전 글 : Stripes로 하는 자바 웹 개발 - 2
다음 글 : ASP.NET - 데이터베이스에서 이미지를 가져오기
최신 콘텐츠