티스토리 뷰


편견이 깨지는 어셈블리 프로그래밍 : 최적화 강좌 2 - 3  
 
 





버스트 모드
버 스트 모드(burst mode)란 한 마디로 블럭 단위로 된 일정량의 데이터를 전송 완료 시점까지 중단 없이 고속으로 전송하는 방식을 말한다. CPU와 노스 브릿지 그리고 메모리 사이에서 일어나는 버스트 모드는 메모리의 시작번지와 요구하는 데이터 블럭의 크기를 명시하면 전송 완료 때까지 중단 없이 데이터를 고속으로 전송하는 방식이다. 즉, 메모리로부터 데이터를 요구할 때마다 그 데이터의 주소를 전달하지 않는다는 말이다(<그림 2>).

<그림 2>는 일반적인 데이터 읽기이다. 일반적으로 데이터를 읽기 위해서는 데이터를 읽을 위치 즉 메모리 주소를 알려주면 그 메모리에서 데이터를 받을 수 있다. 버스트 모드는 어떻게 차이가 날까. 버스트 모드를 살펴보자.



<그림 2> 일반적인 데이터 읽기



<그림 3> 버스트 모드 데이터 읽기


< 그림 3>은 버스트 모드를 사용한 데이터 읽기이다. 우선 버스트 모드임을 알리고 필요한 데이터의 시작 주소를 주면 메모리는 CPU에게 32바이트씩 데이터를 전달하게 된다(데이터를 펜티엄에서는 한번에 8바이트씩 전송하므로 8바이트 × 4번 = 32바이트이다). <그림 2, 3>처럼 일반적으로 전송할 경우 8번의 작업이 필요하던 공정이 버스트 모드를 씀으로서 5번의 작업으로 줄어드는 것이다. 그렇다면 데이터 전송을 할 때마다 버스트 모드를 사용하지 못할까. 이처럼 버스트 모드는 순간적으로 빠른 데이터 전송 환경을 제공하지만 제한된 시간과 특정 조건에서만 가능하기 때문에 장기간 일정하게 이용하기에는 부적합하며 주로 대용량의 데이터 전송에 많이 쓰이게 된다.

버스트 모드에 연관되는 것은 연속되는 주소의 순서와 주소의 위치인데 일반적으로 주소의 순서는 movs 명령이 쓰기에 적합하게 되어 있다. 그러나 주소의 위치의 경우 기본적으로 4의 배수의 주소에서만 동작하게 되어있기 때문에 스트링의 중간을 복사해 오거나 하는 작업 등에서는 이 주소가 4의 배수가 아닐 확률도 크기 때문에 항상 연속된 데이터 이동이 버스트 모드의 해택을 받는 것은 아니다. 그래서 실제로 Win32 API인 CopyMemory를 보면 4의 배수 정렬을 위한 코드가 삽입되어 있는 것을 알 수 있다. 메모리 정렬을 통해 버스트 모드를 사용할 수 있게 한 것이다. 실질적으로 적은 메모리 공간이라면 별 이득이 없겠지만 버스트 모드의 잇점은 그런 조건 분기에서 걸리는 시간을 감수하고도 더 빠를 수 있다는 것이기 때문에 대용량의 메모리 복사에서는 최적화에 필수적이다.

이제 우리가 버스트 모드를 사용해 볼 시간이다. 어떻게 하면 버스트 모드를 사용할 수 있는지 코드를 통해 알아보고, 또한 일반 메모리 복사 코드와 버스트 모드를 적용한 코드와의 비교를 통하여 버스트 모드의 장점을 깊이 새겨 보자.

실전! 최적화
최 적화 테스트를 위해 작성한 두 개의 함수 <리스트 3, 4>의 Win32 API인 CopyMemory, 그리고 일반적인 C-Style의 바이트 복사 방식 등 이렇게 4가지 방법으로 동일한 크기의 메모리 블럭의 4바이트 정렬시 복사 작업과, 비정렬시 복사 작업을 실행하고 소요 클럭 수를 산출해봄으로써 어떤 함수가 어떠한 상황에서 최적의 퍼포먼스를 나타내는 지 알아보도록 하자.

우선 <리스트 3, 4>의 함수인 DtCopyMemory와 DtCopyMemoryMacro를 살펴보자. 두 함수는 동일하게 지정한 메모리 영역을 복사하는 기능을 구현한다. 다만 그 내부적인 로직에는 약간의 차이가 있다. <리스트 3>의 DtCopyMemory 함수는 내부적으로 함수의 인자인 목적지 주소, 소스 주소의 주소가 4의 배수인지를 검사해 4의 배수가 아닐 경우에 버스트 모드의 잇점을 최대한 활용하기 위하여 4의 배수까지 일반 바이트 복사를 한다. 4의 배수부터 마지막 4의 배수 주소까지 버스트 모드의 혜택을 받는 복사를 하고 그리고 마지막 데이터의 일반 복사를 하는 작업이 들어가 있다. 물론 그 이외에 정방향 복사일 때와 역방향 복사일 때를 구분해 처리하는 로직도 존재한다.

<리스트 3> DtCopyMemory.asm 버스트 모드를 이용한 메모리 복사 함수 구현
.model flat, c
.stack
.data
.code

;==========================================================================================
;
; Name : DtCopyMemory
; Function : 지정한 메모리 영역을 복사
; Parameter : 1. A_source:DWORD - 목적지 주소
; 2. A_dest:DWORD - 소스 주소
; 3. A_len:DWORD - 복사할 영역의 크기
; Return Value : 복사된 byte수
;
;==========================================================================================
DtCopyMemory proc uses ecx ebx edi esi A_source:DWORD,A_dest:DWORD,A_len:DWORD

mov esi, A_source
mov edi, A_dest

mov ecx, A_len

mov edx, esi
add edx, ecx

.if (esi < edi) && ( edi <= edx ) ; A_source < A_dest <= A_source + A_len
std ; 역방향 복사

.... 생략 ....

.if ecx > 4
mov edx, edi ; 주소 정렬
and edx, 3

.if !zero? ; 4의 배수일 경우 byte 복사할 필요가 없다.

.... 생략 ....

.endif
.else
cld ; 정방향 복사
.if ecx > 4

.... 생략 ....

.if ecx > 4
push ecx ; copy ecx
shr ecx,2 ; div by 4 for DWORD
rep movsd ; copy as DWORD
pop ecx
and ecx,3
.endif
.endif

rep movsb ; copy as BYTE
pop eax

ret

DtCopyMemory endp

end

< 리스트 4>의 DtCopyMemoryMacro 함수는 메모리 블럭이 4의 배수로 정렬이 되어있다는 가정 하에 주소 값을 검사하는 코드조차 존재하지 않는다. 다만 무조건 rep movsd를 통해 4바이트씩 복사하는 루틴이 들어가 있다. 만일 실제로 메모리 블럭이 4의 배수로 정렬이 되어 있다면 버스트 모드의 혜택을 받을 것이고, 메모리 블럭이 4의 배수로 정렬이 안 되어있다면 버스트 모드의 혜택을 받지 못할 것이다.

<리스트 4> DtCopyMemoryMacro.asm 버스트 모드를 이용한 메모리 복사 함수(주소가 정렬되어 있을 때)

.586
.model flat, c
.stack
.data
.code

;==========================================================================================
;
; Name : DtCopyMemoryMacro
; Function : 4의 배수로 정렬된 메모리 영역을 4바이트씩 복사
; Parameter : 1. A_source:DWORD - 목적지 주소
; 2. A_dest:DWORD - 소스 주소
; 3. A_cnt:DWORD - 복사할 횟수
; Return Value : 복사된 byte수
;
;==========================================================================================
DtCopyMemoryMacro proc uses ecx edi esi A_source:DWORD,A_dest:DWORD,A_cnt:DWORD

mov ecx, A_cnt
mov edi, A_dest
mov esi, A_source

cld
rep movsd

ret

DtCopyMemoryMacro endp


출처: http://www.imaso.co.kr/?doc=bbs/gnuboard.php&bo_table=article&wr_id=250