반응형



엔진 프로그래밍 공부를 하다가 SIMD 관련된 파트가 나와서 어셈블리란에 정리해보려고 한다.

목표는 SIMD를 이용해서 수학 라이브러리를 만드는 것이다.

이번에 배울 목표이다.

1. 최적화
2. SIMD란?
3. SIMD의 간단한 역사
4. 마무리


 
1. 최적화

SIMD란? 이란 제목으로 글을 올려놓고 갑자기 최적화부터 이야기가 나오니 황당할 수도 있다.
일단 SIMD에 대해서 알아보기 전에 최적화에 대해서 개념을 잘 잡아놔야 된다고 생각이 들었고 책 순서 또한 그렇다. 
SIMD가 뭔지는 몰라도 어셈블리란에 글이 올라오고 있고 이를 이용해 수학 라이브러리를 만든다고 하니
SIMD를 이용하면 보통보다 연산이 빠른 수학 라이브러리를 만들 수 있을 거라고 예상할 수 있을 것이다.
그렇다. SIMD를 이용하면 평범하게 프로그래밍을 했을 때 보다 더 빠른 연산을 할 수 있다. 

즉 최적화에 SIMD를 이용하면 성능개선을 할 수 있다는 것이다.
하지만 모든 소스를 SIMD로 만들수는 없기 때문에...
최적화를 언제 어디서 해야하는지를 먼저 알아야한다.

최적화를 하려고 할 때 먼저 해봐야 할 것은 프로파일링이다.
프로그램이 실행중일 때 어느 부분이 가장 자주 실행이 되는지 어느 부분에서 병목현상이 일어나는지를 파악해야 한다.
그 지점부터 조금씩 최적화해 나가면서 테스트해보고 다음 병목현상을 찾고 수정하고를 반복한다.

최적화를 할 때 생각해봐야 할 것이 있는데 프로그래밍적인 트릭이나 데이터 타입을 현란하게 사용하거나 이상한 어셈블리 코드를 짠다거나 이런 시도는 안하는 것이 좋다. 차라리 로직에서 사용한 자료구조나 알고리즘부분을 확인하고 문제점은 없는지 더 빠른 알고리즘은 없는지 확인하고 적용하는것이 이후 처리에 도움이 된다.

가슴 아픈 이야기지만 요즘 컴파일러들이 많이 발전해서 어정쩡하게 어셈블리 코드로 최적화 하는 것 보다 컴파일러들이 더 CPU 친화적으로 최적화를 해준다고 한다. 직접 최적화를 할 것이면 이와 비교해 보면서 해보면 될 것 같다.;;

이 다음에는 책 순서상 어셈블리의 기본에 대해서 나오는데 이는 생략하도록 하겠다.
별 내용이 없기 때문이다.



2. SIMD란?

SIMDSingle Instruction Multiple Data의 약자로 이름 그대로의 일을 해준다.
하나의 명령으로 여러개의 데이터를 처리한다는 이야기이다.

기존의 처리방식은 순차적이였기 때문에 복잡한 연산을 할 때 속도를 올리는 방법은 
CPU의 클럭 속도를 높이는 정도였다.

하지만 SIMD를 사용하면 하나의 명령으로 여러개의 데이터를 처리.. 즉, 병렬로 처리가 가능하다는 이야기다.

예를 들어보자.

3차원 벡터의 합을 구하는 연산을 해야 한다고 했을 때 기존 방식은 순차적으로 이루어 질 것이다.

1) 각각의 x값들을 레지스터에 옮긴다. (32bits)
2) 더하기 명령을 실행한다.
3) 각각의 y값들을 레지스터에 옮긴다. (32bits)
4) 더하기 명령을 실행한다.
5) 각각의 z값들을 레지스터에 옮긴다. (32bits)
6) 더하기 명령을 실행한다.


데이터들의 오고 감을 간략화 해도 최소 x, y, z에 대해서 따로 처리를 했어야 했다.

SIMD를 사용했을 때의 방식을 보자.

1) x, y, z를 배열로 만들어 레지스터에 옮긴다. (96bits)
2) 더하기 명령을 실행한다.


이게 끝이다. 대신 앞에 레지스터로 옮기는 과정에서 배열을 이용하는 데이터 패킹 과정이 있지만
한번의 명령으로 동시에 처리됨을 알 수 있다.

기존 레지스터 크기보다 큰 레지스터에 값들을 패킹하여 담고 한번의 연산을 통해 여러개의 결과를 얻어내는 것.
이것이 SIMD의 기본적인 내용이다.


 
3. SIMD의 간단한 역사

SIMD 이야기를 듣다보면 MMX, 3DNow!, SSE 막 이런 이야기들이 나온다.

처음 들어보면 SSE라는 거에 SIMD가 들어있는건가? SIMD가 SSE라는 건가? 헷갈릴 수도 있을 것이다. (내가 그랬다..) 

이번 기회로 SIMD가 어떤식으로 발전해 왔는지 간단하게 집고 넘어가보자.

SIMD라는 개념이 나왔고 이를 각각의 CPU 회사에서 자신의 CPU에 적용하기 시작했다. 

그래서 먼저 나온 것이 MMX이다.

1) MMX

MMXMultimedia Extensions의 약자로 이름 그대로 멀티미디어 처리를 위해서 나온 확장 명령어이다.

MMX도 SIMD의 기본개념을 구현하기 위해 기존의 32bits보다 큰 64bits짜리 레지스터를 이용했다.
32bits짜리를 동시에 2개를 계산할 수 있었다. 1개 계산하는 것보다야 동시에 2개씩 하니까 더 좋다.

근데 가슴이 아팠던 사실이 있는게.. 이 레지스터로 정수형 처리를 했다!!
3D 실시간 게임에서는 실수형 연산이 필수적인데 정수형이라니..

심지어 이론상은 64bits 레지스터를 이용한다라고 했지만 MMX가 나올 당시의 Intel은 64bits짜리 레지스터를 넣지못했고
기존 FPU 스택에서 쓰던 80bits짜리 레지스터를 공유하여 사용하여 정수형 연산을 하였다.

2) 3DNow!

Intel에서 먼저 냈으니 AMD도 질 수 없다. 역시 80bits짜리 실수형 레지스터를 공유하되 실수형 연산이 되게 만들었다.
근데 정수형 연산은 안되었다. 그래도 float을 바로 넣을 수 있다는게 어디인가?
다음버전 3DNow에는 정수형 연산까지 되게끔 만들었다고 한다.

3DNow Professional인가까지 더 나왔었는데 현재 나오는 CPU에는 3DNow를 다 빼버리고 SSE쪽이 지원되게 한 모양이다.

3) SSE

MMX와 3DNow을 지나오면서 Intel이 다음 SIMD 명령어를 만들어내었다. 그것이 바로 SSE이다.
SSEStreaming SIMD Extensions의 줄임말로 현재 많이 사용되는 SIMD 명령어이다.
책에서도 SSE 계열을 기준으로 설명해준다.

게임에서는 3D지만 계산의 편의성등에 의해서 4개까지 계산에 들어가곤한다.
이를 고려한것인지는 모르겠지만 SSE는 128bits까지 지원하는 새로운 레지스터를 추가해버려서 3DNow를 보내버렸다.
128bits면 float 4개까지 커버가 가능하니까 딱 우리가 원하는 사이즈라 할 수 있다.

여기가 펜티엄 3이다.

4) SSE2

펜티엄 4에서 처음 지원된 SIMD 명령어로 SSE에 캐시 제어등 기타 제어 명령이 추가되었다고 한다.

5) SSE3

기존까지 수직적인 계산 명령어만 지원되었다면 SSE3부터는 어느 부분은 더하고 어느 부분은 빼고 하는 수평적인 명령어나 연산 조합 순서가 다양한 명령어들이 제공되었다.

6) SSSE3

SSE3의 개정판?? 정도로 오버플로우시 보정 옵션이 들어간 것이 가장 큰 특징이라고 한다.

7) SSE4

내적등 수학적인 연산 명령이 추가되었다고 한다.

8) SSE5

곱하면서 더해버리기 명령등이 추가되어서 내적구할 때나 행렬곱셈등등 수학적 연산에 속도 향상이 될만한 명령어들이 추가되었다고 함.

9) AVX

Advanced Vector eXteionsions의 줄임말로 256bits짜리 레지스터로 바꿔버린 녀석.. SSE5와 같은 수학적 연산에 도움이 되는 명령어들 까지 지원된다고 하니 다양한 활용이 가능할 것 같아보인다.



4. 마무리 

아직 해보지는 않았지만 Visual Studio 2010에서 SSE2까지 지원한다고 찾아보니 나왔다.

다시 찾아보긴 해야 할듯...

다음부터는 SSE기준으로 하나씩 정리해보자.


 
반응형
Posted by msparkms
,