• 검색 결과가 없습니다.

Instruction Set Extensions

4. 순차코드 최적화

4.5. 프로세서, I/O, 라이브러리 관련 최적화

4.5.3. Instruction Set Extensions

한 프로세서 패밀리는 대부분 아키텍처를 공유한다. 프로세서 패밀리(인텔의 펜티엄, IBM의 POWER 등)가 개발되고 이후 발전해 가면서 처음 아키텍처의 명령어 집합에서 지원하지 않던 많 은 특성과 성능이 새롭게 추가되게 된다. 이로 인해 명령어 집합을 더 확장하게 되는데, 이렇게 확장된 명령어를 사용하는 코드 생성을 위해서 컴파일러와 어셈블러의 기능 확장도 필요해진다.

확장된 명령어 집합의 예로 선인출(Prefetching)과 SIMD 명령어에 대해 소개한다.

4.5.3.1. 선인출

선인출은 Non-blocking load 명령어이다. 메모리 접근 지연을 감추기 위해 사용하는 선인출 명령 어는 그 결과가 필요한 시점 이전에 미리 실행되어 결과가 필요하기 전에 완료 된다. 대부분의 아 키텍처에서 선인출은 컴파일러 옵션 수준(대부분 –O2 또는 –O3)을 통해 처리되고 heuristics를 통해 얼마나 미리 선인출 명령어를 실행할 것인가를 결정한다. 너무 conservative한 선인출 heuristics는 선인출이 완료되기를 기다리는 의존적인 명령어 사용이 될 수 있으며 너무 aggressive한 경우 데이터가 너무 일찍 선인출 되어 사용도 되기 전에 캐시에서 삭제될 수 있다.

아키텍처가 가지는 선인출 기능을 효과적으로 활용하기 위해서 데이터의 선인출 흐름을 최적화 하도록 코드를 구성하는 것이 좋다. 이를 위해 다음과 같은 사항에 주의한다.

- 성능에 많은 영향을 주는 루프에서 흐름의 수가 너무 많거나 너무 적지 않게 한다.

- 성능에 많은 영향을 주는 루프에서 흐름의 길이를 너무 짧지 않게 한다.

- 가급적 실행순서가 예측 가능한 구조를 사용한다.

- 전역변수의 사용, aliasing, 강제 형 변환, 복잡한 제어 흐름 등을 최소화 한다.

IBM의 POWER4 프로세서에서는 선인출이 하드웨어를 통해 이루어 진다. POWER4 시스템에서 선인출은 루프 내에서 4 ~ 8개 정도의 흐름에 최적화 돼 있다. 선인출 흐름 수를 조절하기 위해 fusion이나 midpoint bisection 등의 기법을 사용할 수 있다.

DO I=1,N

S = S + B(I) * A(I) ENDDO

DO I=1,N

R(I) = C(I) + D(I) ENDDO

위의 코드에서와 같이 루프 내 흐름 수가 너무 적다면 fusion을 통해 흐름 수를 늘일 수 있다.

DO I=1,N

S = S + B(I) * A(I) R(I) = C(I) + D(I) ENDDO

루프의 중간지점을 양분(midpoint bisection)하는 방법을 통해서도 선인출 흐름의 수를 조절할 수 있다.

DO I=1,N

S = S + B(I) * A(I) ENDDO

내적 계산을 수행하는 위의 코드는 두 배열 A, B에 대해 두 개의 흐름이 존재한다. 다음과 같이 루프의 중간지점을 양분해서 흐름의 수를 두 배로 할 수 있다.

NHALF = N/2 S0=0.D0 S1=0.D0 DO I=1,NHALF

S0 = S0 + A(I)*B(I)

S1 = S1 + A(I+NHALF)*B(I+NHALF) ENDDO

IF(2*NHALF.NE.N) S0 = S0 + A(N)*B(N) S = S0+S1

또한 여기서는 벡터의 길이가 반으로 줄어서 캐시 메모리 사용을 보다 최적화 하는 효과도 얻을 수 있다.

4.5.3.2. SIMD 명령어

* The Pentium 4 and Athlon XP also support SSE instructions.

4

SIMD Instruction Set Extensions on Commodity Microprocessors

* The Pentium 4 and Athlon XP also support SSE instructions.

4

SIMD Instruction Set Extensions on Commodity Microprocessors

표 4-1. SIMD 명령어 집합

VLD &b+i,rv2 #load b(i:i+vlen) into vector register 2

VFM rv1,rv2,rv3 #multiply the contents of vector registers 1 & 2

#and store the result in vector register 3 VLD &c+i,rv4 #load c(i:i+vlen) into vector register 4 VFA rv3,rv4,rv5 #add the contents of vector registers 3 & 4

#and store the result in vector register 5 VST rv5,&x+i # store vector register 5 into x

여기서 vlen이 SIMD unit의 벡터 길이를 나타낸다. 위의 연산은 SIMD unit에서 완전히 처리되므 로 스칼라 정수와 스칼라 부동소수 처리 unit은 동시에 다른 코드를 실행하는 것이 가능해 진다.

SIMD 명령어의 사용 여부는 컴파일 단계에서 옵션을 이용해 지정할 수 있다.