2015년 9월 6일 일요일

라즈베리파이2에서 NEON을 사용하기 위해 gcc-5.1.0 컴파일하기

라즈베리 파이에 사용된 프로세서에는 NEON이라는 SIMD (Single Instruction Multiple Data)처리 유닛이 들어있다. 이 NEON을 사용하면 최대 128비트까지 동시에 처리가 가능해 지기 때문에 프로그램 실행에 상당한 성능 향상을 가져올 수 있게 된다. x86계열로 치면 MMX, SSE, AVX 명령등에 이에 해당한다.


char 타입의 연산인 경우 약 5배, short 타입 연산은 약 3배, int 타입 연산은 약 1.7배, float 타입 연산은 약 2.3배 정도로 실행 속도가 향상된다. 즉 반복적인 연산이 많은 scientific computation이나 signal processing, 암호화, 압축, 인코딩 등에 사용하면 매우 유용하다.



부동 소수점만 보면 단정도(single precision)의 경우 라즈베리 파이1이 약 70 MFlops, 라즈베리 파이2에서 NEON을 사용하지 않으며 약 150 MFlops, NEON을 사용하면 약 310 MFlops의 속도가 나온다. 부동 소수점 배정도(double precision)의 경우 라즈베리 파이1이 약 35 MFlops, 라즈베리 파이2에서는 약 150 MFlops정도의 속도가 나오게 된다. (부동소수점 연산에서 배정도의 경우 NEON이 지원하지 않음)

단 컴파일 시 NEON 명령을 지원하도록 하려면 현재 distribution에 포함되어 있는 gcc로는 안되고 NEON을 지원하도록 gcc-5.1.0을 설치해 줘야 한다.

먼저 gcc-5.1.0 소스코드를 다운로드 한다.

$ curl -O http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-5.1.0/gcc-5.1.0.tar.bz2
$ tar xvf gcc-5.1.0.tar.bz2

gcc를 컴파일 하기 위해서는 디폴트 swap 파티션 용량이 부족하기 때문에 swap 파티션 용량을 늘려줘야 한다.

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile

현재 apt-get으로 설치되는 autoconf 버젼은 2.69인데 gcc-5.1.0은 2.64를 사용하도록 설정되어 있다. 그래서 이걸 2.69를 사용하도록 수정해 줘야 한다.

(1) gcc-5.1.0 디렉토리에 있는 configure.ac 파일 안의 AC_PREREQ 값을 '2.64'에서 '2.69'로 수정
(2) gcc-5.1.0/config 디렉토리에 있는 override.m4 파일 안의 _GCC_AUTOCONF_VERSION 값을  '2.64'에서 '2.69'로 수정

GCC-5.1.0에서는 병렬화를 위해 언어확장으로 cilk를 표준으로 사용하므로 cilk도 활성화 시켜 줌

(1) gcc-5.1.0/libcilkrts 디렉토리에 있는 configure.tgt 안의 UNSUPPORTED=1 을 앞에 '#'를 붙여 comment out 시킴 ('1'을 '0'으로 바꾸는건 안됨)
(2) gcc-5.1.0/libcilkrts/runtime/config/generic 디렉토리에 있는 cilk-abi-vla.c 안의 vla_internal_heap_free 함수를 호출하는 부분에서 첫번째 인자를 't'에서 'p'로 수정
(3) gcc-5.1.0/libcilkrts/runtime/config/generic 디렉토리에 있는 os_fence.h 안의 __cilkrts_fence의 정의 부분의 맨 앞에 '//'를 추가해 comment out 시킴
COMMON_SYSDEP void __cilkrts_fence(void); /// < MFENCE instruction
(4) gcc-5.1.0/libcilkrts/runtime/config/generic 디렉토리에 있는 os_fence.h 파일에 아래줄을 추가
#define __cilkrts_fence() __asm__ volatile ("DSB")

빌드를 위해 GMP, MPFR, LIBMPC가 필요하므로 설치해 줌

$ sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev

빌드를 시작

$ mkdir b; cd b
$ ../configure --enable-languages=c,c++ \
--prefix=/usr/local/gcc-5.1.0 \
--target=arm-linux-gnueabihf \
--with-arch=armv7-a \
--with-fpu=vfp \
--with-float=hard \
--build=arm-linux-gnueabihf \
--host=arm-linux-gnueabihf
$ make
$ sudo make install

설치가 완료된 후 gcc-5.1.0을 사용하도록 환경변수를 설정해 준다. '.profile' 또는 '.bashrc' 파일의 맨 마지막에 다음 두 줄을 추가한다.

export PATH=/usr/local/gcc-5.1.0/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/gcc-5.1.0/lib:$LD_LIBRARY_PATH

라즈베리파이1에서 컴파일 하는 경우 configure 옵션을 다르게 줘야 한다.

$ ../configure --enable-languages=c,c++ \
--prefix=/usr/local/gcc-5.1.0 \
--target=arm-linux-gnueabihf \ 
--with-fpu=vfp \
--with-float=hard \
--build=arm-linux-gnueabihf \
--host=arm-linux-gnueabihf

빌드에는 상당한 인내심이 필요하다. 'make' 명령으로 빌드하는데 라즈베리파이2에서 대략 30시간 정도 걸렸다.

바로 사용하고 싶은 사람들은 아래 링크에서 컴파일 된 gcc-5.1.0을 받아 /usr/local 디렉토리에 풀어주고 환경변수 설정만 하면 된다.

gcc-5.1.0.compiled_for_rpi2.tgz

댓글 2개:

  1. 좋은 글 감사합니다. 질문이 있어 남깁니다.
    올려주신 파일로 설치후 컴파일된 프로그램을 실행시, libstdc++.so.6: version ``GLIBCXX_3.4.21' not found 에러가 발생합니다.
    /usr/lib/arm-linux-gnueabihf/ 폴더의 libstdc++.so.6 파일을 보면GLIB가 18버전까지만 기재되어있고,
    gcc-5.1.0 폴더에서 libstdc++.so.6 파일을 보면 정상적으로 21 버전까지 기재되어 있습니다.

    일단은 위의 lib 폴더를 5.1.0 폴더의 lib 폴더에 붙여넣기했더니 정상적으로 동작합니다만, 이 방법이 옳은 방법인지 에러가 생긴 원인이 무엇인지 궁금합니다.

    답글삭제
    답글
    1. export LD_LIBRARY_PATH=/usr/local/gcc-5.1.0/lib:$LD_LIBRARY_PATH

      이 내용을 ~/.bashrc 또는 ~/.profile에 추가해 놓으셨나요?

      삭제