Note: 이번 글부터는, 워드프레스의 기본 웹 에디터를 사용할 예정입니다. 이로인해 가독성이 더 좋아질 수 있기를 기대합니다. 글에 통일적으로 추가되는 코멘트화 (#, //, ;; 등 코딩 배경에 따라 다릅니다)의 경우 언급은 하나, 필요한 옵션에 해당되는 부분임을 먼저 밝혀두는 바입니다. document history initiated: 17 May 2021 last update: 18 May 2021
기존의 2017MBP에서 새로 도착한 16인치 인텔맥으로 마이그레이션을 하기보다, 처음부터 모든 개발환경을 설정하기로 했습니다. 다양한 이유중에 가장 큰 부분은, 최근에 Big Sur로 업데이트하면서 발생한 여러가지 의존성 문제입니다. 현재는 적당한 임시방편으로 g++/clang기반으로 돌아가게 해 두었습니다만, 새로이 맥북을 받음 김에 처음부터 단계적으로 기반을 마련할 예정입니다.
일전에 필자의 개인환경을 간략하게 소개한 적이 있습니다 (필자의 경우 연구센터 vpn을 (라이센스문제)통해 2020년형 parallel_studio버전을 사용하고 있었습니다. 얼마전, 원래 사용하던 맥북을 Big Sur로 업데이트 한 다음 생소한 에러가 발생해서 확인해보니 해당 버전의 intel compiler가 Big Sur를 지원하지 않아서 발생한 문제였습니다. 이후 g++/clang의 임시방편 방법을 쓰고 있었지만, 어라전 새롭게 intel 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
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 관련 문제가 발생할 수 있습니다.
Leave a Reply