Pure Single Precision Math-Library

  써 놓고 보니 제목이 그럴싸하다.
  ARM Cortex-M4 코어가 들어가는 STM32F429 보드를 가지고 놀던중 수학함수(sin(), cos(), sqrt() 등등)를 사용할 필요가 있어 sin() 함수를 호출 했더니 CPU가 죽는다.
  Cortex-M4 FPU는 double precision을 지원 하지 않는 다는걸 알았다. 그래서 이번엔 sinf()를 호출 해 봤더니 역시 또 CPU가 죽는다.
  나는 보통 Embedded System용 툴체인은 직접 빌드해서 사용한다. 내가 만든 툴체인에 문제가 있나 싶어 FPU관련 옵션을 이리저리 바꿔가면서 툴체인을 다시 빌드해봤으나 역시 증상이 동일 하다. 해본 사람은 알겠지만 툴체인 한번 빌드하는데 적게는 30분에서 많게는 2~3시간이 걸린다. 더 많은 옵션으로 테스트를 해보고 싶지만 툴체인 빌드하느라 시간을 다 까먹고 있어서 툴체인 빌드 삽질을 중지 하고 수학함수(libm) 소스를 열어 봤다. arm-unknown-eabihf(bare-metal)로 빌드 할 경우 newlib가 사용되고 arm-unknown-linux-gnueabihf로 빌드 할 경우 glibc가 사용된다(툴체인 뒤에 붙는 hf는 hardware FPU라는 뜻임). newlib의 경우 수학함수가 모두 double precision으로만 빌드 되고 sinf()나 cosf()와 같은 single precision 함수는 껍데기만 single precision일뿐 정작 함수 내부 구현시 double precision을 사용한다. 그러니 CPU가 죽을 수 밖에...
  glibc소스 확인 결과 삼각함수나 sqrtf(), powf()등은 함수 이름에 걸맞게 내부 구현도 pure single precision으로 구현되어 있었다. 그런데 왜 CPU가 죽는 것일까? 툴체인 빌드시 명확하게 single precision으로만 수학 함수가 빌드되도록 옵션을 설정 해야 한다. 또한 gcc 버전이 올라 갈 수록 하위 호환이 필요한 함수들의 경우 실제 테스트를 해보지 않는 이상 잠정적인 버그로 남아 있을 수 있다. 실제로 ARMv4로 빌드 옵션을 주고 컴파일 해도 최근 gcc의 경우 ARMv7로만 빌드 되는 경우도 있다. 아마 낮은 버전의 gcc와 glibc의 조합을 이용하면 Cortex-M4용 수학함수 툴체인을 만들 수 있을 것이나, 시간 소모가 많다.
  이번 문제는 툴체인을 다시 빌드하지 않고 필요한 수학 함수를 소스 수준에서 포팅하여 완전한 'pure single precision'으로 빌드 하여 사용하기로 하였다.
  openlibm, fdlibm, glibc, yeppp등을 검토하여봤다. openlibm의 경우 ***f()함수는 대부분 single precision으로 구성되어 있으나 삼각함수는 double precision으로만 구현되어 적용이 불가 하였다. sinf(), cosf()등이 있으나 함수 껍데기만 float이고 내부 상수 및 수치 연산은 모두 double로 구성되어 있었다. fdlibm은 오직 double precision만 사용 가능하다(readme에 언급되어 있음). yeppp의 경우 소스크기가 큰편이라 자세히 보지 못했다. architecture별로 FPU사용에 최적화가 되어 사용시 큰 잇점이 있을 것으로 보이나 일반적인 libm 형태 소스 구성이 아니라 분석하는데 시간이 걸려 pass함(나중에 속도 최적화시 다시 봐야 할거 같다). 마지막으로 glibc는 대부분 내가 필요로 하는 함수는 single precision으로 구현되어 있었다. 역시 구관이 명관이라... glibc의 libm중에도 expf()와 같은 일부 함수는 내부에 double precision 연산이 들어가 있는 것도 있었다. glibc 버전중에 찾아보면 single precision으로 구현된 소스가 있을 텐데 일단 지금은 필요한 함수가 아니라 우선 아래 함수만 포팅하여 사용하였다.

  - sqrtf()
  - sinf()
  - cosf()
  - tanf()
  - asinf()
  - acosf()
  - atanf()
  - atan2f()

  pure single precision으로 구성한 소스를 첨부합니다. 필요하신 분은 가져다 활용 하시기 바랍니다. libm 소스는 glibc-2.21에서 발췌 하였습니다. 첨부된 소스 이외 의존성은 없습니다. standalone으로 빌드하여 사용 하시면 됩니다. *.c 파일은 프로젝트에 포함 시켜서 빌드하면 되고 사용시 math.h 헤더파일만 포함하여 사용 하면 됩니다.
  IEEE754(부동 소숫점 연산 표준) 함수를 발췌 하여 사용하였으므로 각 architecture별 FPU가 가지고 있는 최대 성능이 나오지 않을 수 있습니다.

소스다운로드

  

댓글 없음:

댓글 쓰기