첫번째 글에서 필자의 사용자 환경에 대한 간략한(?) 소개 및 필자가 사용하던 맥에 대한 이야기를 하였습니다: https://www.clien.net/service/board/cm_mac/16140666.CLIEN
두번째 글은 기본 개발자 도구인 iTerm 2와 Emacs의 환경설정에 대해 요약해보았습니다: https://www.clien.net/service/board/cm_mac/16149146CLIEN
이번에는 필자가 수치해석에 자주 사용하는 Intel compiler와 Math Kernel Library (MKL)을 Big Sur (인텔맥)에 설치하는 것에 대해 적어보았습니다. 기회가 닿으면 다른 수칙해석 도구들에 대한 설정을 새로운 글타래로 소개해보도록 하겠습니다.
지난 글에서 말씀드렸다시피, 글의 기본틀은 개인 위키에서 기록용으로 만들어둔것을 복사해온 것입니다. 또한, 필자는 개발자분들에 비해 전문성이 떨어질 수 있다는 점을 미리 상기시켜 드립니다. 전문가분들의 피드백은 항상 환영합니다. 필자의 컴퓨터는 연구센터 소속으로 기본 셋팅에 각종 shared license및 개발자도구가 포함되어서 나옵니다. 그래서 완전한 클린 설치와는 조금 다를 수 있다는 것을 염두에 두는 것이 좋을 듯 합니다.
추신: 코드에 이미 코멘트화(#, //, ;;등)가 된 경우, 필자는 현재 사용하지 않지만 예전에 사용했거나, 혹은 경우에 따라 옵션으로 참조할 만한 부분입니다.
일전에 이야기했다시피, 기존의 2017MBP에서 새로 도착한 16인치 인텔맥으로 마이그레이션을 하기보다, 처음부터 모든 개발환경을 설정하기로 했습니다. 다양한 이유중에 가장 큰 부분은, 최근에 Big Sur로 업데이트하면서 발생한 여러가지 의존성 문제입니다. 현재는 적당한 임시방편으로 g++/clang기반으로 돌아가게 해 두었습니다만, 새로이 맥북을 받음 김에 처음부터 단계적으로 기반을 마련할 예정입니다.
필자의 경우 라이센스 때문에 기존에는 연구센터 vpn을 이용하여 2020년형 parallel_studio버전을 사용하고 있었습니다. 사실 새로운 인텔맥을 받기전, 원래 사용하던 맥북을 Big Sur로 업데이트한 다음부터 2020년 버전의 컴파일러가 Big Sur를 지원하지 않아서 발생한 문제였습니다. 그래서 새로운 맥북이 오기 전까지는 g++ 및 clang을 이용해 임시방편으로 쓰고있었습니다. 새로운 맥북에서 천천히 문제를 해결할 방법이 있을까 모색하다가 intel oneAPI가 상업용/비상업용 모두 무료로 풀려있다는것을 알게 되고 라이센스를 읽어보고 제가 사용해도 무방하다는 결론을 내렸습니다. 현재는 공식 홈페이지에서 다운받은 oneAPI를 사용하여 환경설정을 모두 해둔 상태입니다.
0. 들어가기에 앞서
수치해석에서 intel compiler나 MKL을 사용하는 근본적인 이유는 계산 속도때문입니다. 물론 프로그램에 따라 속도가 크게 중요하지 않는 경우가 많이 있지만, 이러한 경우 필자는 Python을 주로 사용합니다. 결국, C++를 사용하는 경우 이미 계산속도가 중요한 경우이고 어느정도 개발이 진행되어서 계산이 제대로 나오기 시작하면 짧은 지식이나마 최적화에 대해 고려하기 시작합니다.
g++이나 clang에 비해 얼마나 빠르냐는것을 저의 비교로 설명하는 것은 부적절한 듯 합니다. 이는, 코드의 최적화를 어떻게 하느냐, 일반적인 최적화 철학에 잘 맞추어서 코드를 작성했느냐 등에 달렸기 때문입니다. 그럼에도 불구하고, 기본적인 규칙만 지키면서 짠 개인 코드들의 경우 적으면 20-30%에서 많으면 200%정도도 차이가 나는 듯 합니다. 이는 -O level를 주지 않고 컴파일 할때나 -O2나 -O3로도 비슷한 정도의 차이가 발생해서, (제 개인적인 견해이지만) 사용하는 패키지의 인터페이스의 의존도가 높은게 아닌가 싶습니다. 예를들어 fftw나 BLAS의 경우 그냥 컴파일옵션을 바꿔주는 것만으로도 체감되는 속도향상을 불러옵니다. 물론 각기 설치할수도 있지만, 저와 비슷한 많은 분들이 그냥 GSL (GNU's Scientific Library)나 MKL의 인터페이스를 이용하실텐데, 여기서 컴파일 플래그를 gsl에서 mkl로 넘기는것으로 직접적인 비교를 할 수 있습니다. 더 자세한 이야기는, 생각이 정리되면 한 번 비교해서 새로운 글타래를 열도록 하겠습니다.
1. echo $SDKROOT
처음에는 Xcode를 배제하고 개발환경을 구성할 예정이었습니다. Command Line Tools (이하 CLT)을 통해 기본 개발자환경을 설치를 통해 간략화 할 수 있다는 생각에서였습니다. 다만, 나중에 Instruments의 Time Profiler에 생각이 미치는 바람에 결국 이를 위해서만 Xcode를 설치하게 되었습니다. 예전에 Valgrind의 Mac에 대한 지원이 중단되고 난 다음부터 이를 사용하지 않고 있어서, 현재 이쪽의 지원이 이루어지고 있는지에 대해서는 잘 모르겠습니다.
이 와중에 재미있게도, SDKROOT 환경변수는 Xcode설치 유무와 관계없이 Xcode.app를 참조해서 이루어집니다. 해당 환경변수는 여러곳에서 활용하게 되므로 만약 CLT만을 사용하게 되면 다음을 .zshrc에 추가해주는 것을 추천합니다. 굳이 코멘트화 #시켜둔 이유는 Xcode를 사용하는 경우 다음과 같은 설정이 필요하지 않기 때문입니다.
# export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
g++이나 clang을 사용할때는 내부적으로 SDKROOT을 참조하는 것 같았습니다. 다만 icpc의 경우에는 SDKROOT을 -isysroot옵션에 넣어서 사용해줘야 되는 부분이 있습니다. 다시말해 makefile에서 CFLAG와 LDFLAG에 다음 부분을 넣게 됩니다.
ifdef SDKROOT
CFLAGS += -isysroot ${SDKROOT}
LDFLAGS += -L${SDKROOT}/usr/lib
endif
2. oneAPI: setvars.sh
필자가 예전에 사용하던 Intel Composer이나 Parallel Studio의 경우 intel compiler와 MKL이 분리되어 있어서 각각의 환경변수들을 source시켜주어야 했었습니다. 보통의 경우 .zshrc에 다음과 같은 부분을 추가하고는 했었습니다 (역시 #로 코멘트화 시켜두었습니다).
# source /usr/local/intel/bin/compilervars.sh -arch intel64 -platform mac
# source /usr/local/intel/mkl/bin/mklvars.sh
새로이 사용하는 intel oneAPI의 경우 이 부분들이 setvars.sh로 통합되어있습니다. 그래서 위와는 다르게 다음 한줄을 .zshrc에 추가하게 되었습니다. 예전과는 다르게 oneAPI를 설치할 당시 아키텍쳐와 플랫폼의 환경변수가 intel64및 mac로 이미 설정되어 있으므로 특별한 추가 옵션이 필요하지 않습니다.
# source /opt/intel/oneapi/setvars.sh
다만, oneAPI을 source해오는 경우 관련된 도구 일체를 모두 자체 테스트하에 설정을 진행함으로 인해, 다음 출력과 함께 약간 체감될 정도로 시간이 걸립니다.
:: initializing oneAPI environment ...
-zsh: ZSH_VERSION = 5.8
:: advisor -- latest
:: compiler -- latest
:: dal -- latest
:: dev-utilities -- latest
:: dnnl -- latest
:: intelpython -- latest
:: ipp -- latest
:: ippcp -- latest
:: mkl -- latest
:: tbb -- latest
:: vtune_profiler -- latest
:: oneAPI environment initialized ::
이로인해 기존과는 다르게 개발자환경을 항상 source해오는게 아니라 alias로 다음을 추가해주었고 필요할때만 oneapi를 수행해 개발자도구를 로딩하도록 하였습니다. 그리고 매 세션 마다 source해오는 경우에는 ~/.oneapi_config파일에 적어둔 설정을 따르도록 하였습니다. setvar.sh에 대한 자세한 설정은 링크한 인텔 문서를 참조하시면 됩니다.
alias oneapi='source /opt/intel/oneapi/setvars.sh'
source /opt/intel/oneapi/setvars.sh --config="~/.oneapi_config"
필자의 경우 icc/icpc와 MKL만이 필요하므로 ~/.oneapi_config파일에는 다음과 같이 설정되어 있습니다.
default=exclude
mkl=latest
compiler=latest
여기서 default=exclude는 기본적으로 아래 명시된 패키지가 아니면 로딩을 하지 않는것입니다. mkl과 compiler는 버전을 입력할수도, latest (현재 symbolic link로 특정 버전으로 연결되어있습니다)로 할 수 있습니다. 이제 터미널에서 새로운 세션이 열때마다 빠른속도로 다음과 같은 출력이 나옵니다.
:: initializing oneAPI environment … -zsh: ZSH_VERSION = 5.8 :: mkl -- latest :: compiler -- latest :: oneAPI environment initialized ::
3. echo $MKLROOT
여러 조각의 코드들을 새로운 환경에서 테스트하면서 발생한 가장 흔한 문제는 다음과 같은 library not loaded 에러입니다.
dyld: Library not loaded: @rpath/libmkl_intel_lp64.1.dylib
이는 기본적으로 라이브러리가 들어있는 패스를 환경변수를 통해 인식하지 못해서 발생되는 문제인데, 현재 shell 내의 환경설정이 잘 되어있다면 큰 문제없이 넘어갈수있는 부분입니다. 다만, oneAPI를 매번 로딩하지 않고, 또한 다른 shell script내에서 현재 컴파일된 프로그램을 시행한다거나 Time Profiler등(아래 섹션 참조)을 적용하는경우 새로운 세션이 열리므로 문제가 생기는 경우가 있습니다. 이 때 제일 쉬운 방법은 아마도 -rpath옵션을 넣어서 컴파일 하는 것이라 생각합니다. 그로인해 필자는 다음컴파일 옵션을 makefile의 linker flag (LDFLAG)에 삽입하게 됩니다.
LDFLAG += -Wl,-rpath,${MKLROOT}/lib
만약 GROMACS와 같은 시뮬레이션 패키지를 여러가지 이유로 직접 빌드하여 설치하는 경우, 쉬운 방법으로는 먼저 cmake에 각종옵션등을 넣어서 설정한 다음에 ccmake ..에서 advanced mode로 들어가신 다음에 CMAKE_EXE_LINKER_FLAGS에 -Wl,-rpath,real_path_to_MKLROOT/lib를 넣으시면 됩니다.
4. Time Profiler
앞서 이야기한 것 처럼, 계산속도 분석은 본격적인 수치해석에 앞서서 필수적인 요소중 하나입니다. 본인 스스로 생각한 time complexity가 그대로 작동하는지등등을 확인하다보면 기본적으로 시간 측정을 하고 이를 사용자에게 알리는 부분이 반드시 필요하다고 생각합니다. 이는 혼자만 사용하는 코드도 제법 긴 시간을 소모한다면 예외없이 적용해야 한다고 생각합니다. 이와는 별개로, 다른사람이 짠 코드를 가져와서 쓰거나 혹은 본인 코드라도 개발중인 환경이 덕지덕지 붙어있는 경우에는 hard coding보다는 전반적으로 프로파일링을 하면서 bottleneck이 어디서 발생되는지 한번쯤 확인하는게 좋습니다.
아마 개발자라면 익숙하겠지만, 필자처럼 개발자가 아닌 사람의 경우에는 일반적으로 몇 안되는 프로그램에 의존하곤 합니다. 예전에는 valgrind를 쓰곤 했는데 지원안된 이후 (현재도 지원안되는지는 잘 모르겠습니다)에는 Xcode의 Instruments를 다음과 같이 사용하곤 했습니다 (test는 프로그램명 test.inp는 계산 조건 파싱용 input file).
instruments -t "Time Profiler" ./test test.inp
그런데 새로 설치한 이후 확인해보니 depreciated되었다는 이야기가 나오는 것을 보니, 왠지 다음 Mac OS에서부터는 지원이 안 될 것 같습니다. 메세지에서 추천한대로 xctrace를 다음처럼 사용하는 경우 실질적으로 같은 결과를 얻을 수 있습니다.
xcrun xctrace record --template 'Time Profiler' --target-stdout - --launch-- ./test test.inp
이제 코드가 길어지므로, 필자와 같이 기억력이 좋지 않고 개발일에 종사하지 않는 사람은 간단한 alias를 등록해두는게 좋습니다.
alias timeprofiler="xcrun xctrace record --template 'Time Profiler' --target-stdout - --launch --"
이제부터는 timeprofiler ./test test.inp와 간편하게 Time Profiler를 사용할 수 있습니다. 중요한 것은 3번에 설명한 것과 같이 rpath를 설정해주지 않으면 dyld 관련 문제가 발생할 수 있습니다.