SIMD란 Single Instruction Multiple Data의 약자로, 하나의 명령어로 여러개의 데이터를 한번에 처리하는 기법입니다. 일반적인 프로그램의 경우 대부분 SISD(Single Instruction Single Data)으로 구현되어 있고, 이것은 기본적인 폰노이만 컴퓨터가 사용하는 방식입니다. 하지만 동영상 인코딩, 그래픽 렌더링 등의 작업에 SIMD를 적용하였을 때는 성능적으로 큰 이득을 취할 수 있습니다.
CPU-Z같은 프로그램에서 CPU가 지원하는 명령어 셋들을 확인할 수 있는데, Intel의 경우 MMX(SSE2), AMD는 3D Now!같은 기술들이 SIMD를 의미합니다.
SISD VS SIMD
위의 예는 우리가 일반적으로 사고하는 SISD 방식과 이제부터 알아볼 SIMD 연산에 대한 차이를 나타낸 것입니다. Vector4 + Vector4를 간단하게 SISD와 SIMD로 표현한다면 다음과 같습니다.
게임을 만들기 위해선 벡터, 행렬 연산은 피할 수 없습니다. 그래서 더욱 SIMD를 이용해 코드를 작성하면 좋겠지만, 그것은 쉽지 않은 작업일 것입니다. 하지만 대표적인 그래픽 라이브러리인 DirectX와 OpenGL은 SIMD를 지원합니다.
- DirectX 11부터 제공되는 XNAMath 라이브러리가 SSE2(SIMD)명령어 셋을 이용해 구현되었습니다
- ex) XMLoadFloat3, XMVector3Transform, …
어떻게 구현하죠?
SIMD는 직접 어셈블리로 구현하거나, Intrinsic Function을 이용하여 구현할 수 있습니다. * Intrinsic Function은 inline function으로, 모습은 함수와 동일하지만 어셈블리 명령어와 1:1로 매칭되어 좀 더 쉽게 SSE를 이용할 수 있게 해주는 내장 함수입니다. 어셈블리어로 코드를 짜는건 모두에게 쉽지 않은 일이기 때문에 Intrinsic function을 이용해 코드를 작성하도록 하겠습니다. (하지만 Intrinsic function을 이용하면 직접 어셈블리어로 코드를 작성하는 것보다 필요없는 명령어들이 조금 더 생성됩니다)
* _mm_set_ss가 Intrinsic Function이며, 어셈블리어에 함수 호출에 대한 명령어가 없습니다.
프로그래머가 SIMD로 변환되기 쉽도록 코드를 작성하였다면, 요즘의 최신 컴파일러들은 설정에 따라 자체적으로 SIMD Instruction을 사용한 코드로 변환해줍니다.
그리고 SIMD를 제대로 사용하기 위해서는 정렬된 메모리(aligned memory)를 사용해야 합니다. 정렬된 메모리가 어떤 의미인지 다음 코드에 주석으로 설명하도록 하겠습니다.
(1)의 경우에는 그냥 고개를 끄덕거릴 수 있다고 생각합니다. 하지만 (2)의 경우는 왜 정렬되지 않았다고 표현하고 (3)은 왜 정렬되었다고 표현하는걸까요?
그림을 보니 이해가 조금 되시나요? Align의 정의는 메모리 시작지점을 align한 숫자의 배수로 맞추고, 내부 원소 하나하나의 크기를 align한 크기로 맞추는 것을 뜻합니다.
Intrinsic Function
- 위의 제목을 클릭하면 Intel의 Intrinsic Function들에 대한 목록이 나옵니다.
Intrinsic 함수의 명명법은 위의 그림과 같습니다.
저는 위의 함수 목록을 참고하여 두 배열에서 각 항목의 최댓값을 구하는 코드를 SISD, SIMD로 작성하려고 합니다.
저도 직접 실행하기 전까진 신뢰할 수 없었는데 정말 놀라운 결과를 보게 되었습니다.
정리
이해하기 어렵고, 공부해야할 분야가 많은 주제이다보니 저도 제대로 설명했는지 조금 걱정이 됩니다. 그리고 예제가 너무 빈약했지만 이 글은 SIMD 기초의 일부만을 다뤘을 뿐이고, 훨씬 더 깊은 내용을 공부해야하는 분야입니다.
사실 라이브러리나 프레임워크 개발하는 분이 아닌 이상 이렇게까지 최적화를 할 필요가 있을까 싶지만 앞으로 SIMD는 더더욱 많은 곳에서 쓰일 것이라 생각합니다. 또한 최적화할 부분을 잘 판단하여 적용한다면 힘들지만 정말로 큰 성과를 얻을 수 있지 않을까요?
Reference
- http://msparkms.tistory.com/entry/SIMD%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%88%98%ED%95%99-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-SIMD%EB%9E%80
- https://msdn.microsoft.com/en-us/library/windows/desktop/ee415571(v=vs.85).aspx
- http://www.slideshare.net/KooKyeongWon/0204-sse?qid=59f2c516-76bf-4f04-8977-d2ae7c5745db&v=&b=&from_search=1
- https://developer.mozilla.org/ko/docs/Web/JavaScript/SIMD_types
- http://ftp.cvut.cz/kernel/people/geoff/cell/ps3-linux-docs/CellProgrammingTutorial/BasicsOfSIMDProgramming.html
- https://en.wikipedia.org/wiki/SIMD
- https://namu.wiki/w/%ED%94%8C%EB%A6%B0%20%EB%B6%84%EB%A5%98
- https://courses.engr.illinois.edu/ece390/books/labmanual/inst-ref-simd.html
- http://www.slideshare.net/zupet/sse-8157725
- http://blackreas.tistory.com/entry/SIMD
- https://software.intel.com/sites/landingpage/IntrinsicsGuide/
-
Thinking About CPU 최적화 프로그래밍 노트 - 김안석 저 한빛미디어