OpenCV와 병렬 프로그래밍 (TBB, 꼭 설치해야 하나?)
Study/OpenCV 2017. 6. 28. 10:54 |OpenCV 설치와 관련된 블로그를 읽다보면 TBB를 함께 설치하라는 글을 종종 찾을 수가 있습니다. TBB는 Threading Building Blocks의 약자이고, Intel에서 만든 다중 코어, 멀티 쓰레드 라이브러리입니다. 대용량 데이터인 영상을 처리할 때 여러 개의 쓰레드를 사용하여 연산을 좀 더 빠르게 수행할 수 있게 해주는 역할을 하는 라이브러리 입니다.
https://www.threadingbuildingblocks.org/
TBB는 예전에는 GPL 라이센스를 따르다가 TBB 2017 버전부터는 Apache v2.0 라이센스를 따르기 때문에 사용하기가 좀 더 자유로와졌습니다.
그렇다면 OpenCV를 직접 빌드하여 설치할 때 TBB를 함께 설치하면 효과적이겠지요? 멀티 쓰레드를 사용하여 연산 시간이 몇 배 빨라질 수 있으니까요. 그렇지만 굳이 번거롭게 TBB를 설치하지 않아도 최신 버전의 OpenCV에서는 멀티 쓰레드 프로그래밍을 기본 지원합니다. 오늘은 이 부분에 대해 정리하려고 합니다.
http://code.opencv.org/projects/opencv/wiki/ChangeLog#243
실제로 OpenCV 소스 코드 중에서 <opencv>/modules/core/src/Parallel.cpp 파일을 보면 아래와 같은 형태로 코드가 작성이 되어 있습니다.
void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes) { CV_INSTRUMENT_REGION_MT_FORK() if (range.empty()) return; #ifdef CV_PARALLEL_FRAMEWORK if(numThreads != 0) { ProxyLoopBody pbody(body, range, nstripes); cv::Range stripeRange = pbody.stripeRange(); if( stripeRange.end - stripeRange.start == 1 ) { body(range); return; } #if defined HAVE_TBB tbb::parallel_for(tbb::blocked_range(stripeRange.start, stripeRange.end), pbody); #elif defined HAVE_CSTRIPES parallel(MAX(0, numThreads)) { int offset = stripeRange.start; int len = stripeRange.end - offset; Range r(offset + CPX_RANGE_START(len), offset + CPX_RANGE_END(len)); pbody(r); barrier(); } #elif defined HAVE_OPENMP #pragma omp parallel for schedule(dynamic) for (int i = stripeRange.start; i < stripeRange.end; ++i) pbody(Range(i, i + 1)); #elif defined HAVE_GCD dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply_f(stripeRange.end - stripeRange.start, concurrent_queue, &pbody, block_function); #elif defined WINRT Concurrency::parallel_for(stripeRange.start, stripeRange.end, pbody); #elif defined HAVE_CONCURRENCY if(!pplScheduler || pplScheduler->Id() == Concurrency::CurrentScheduler::Id()) { Concurrency::parallel_for(stripeRange.start, stripeRange.end, pbody); } else { pplScheduler->Attach(); Concurrency::parallel_for(stripeRange.start, stripeRange.end, pbody); Concurrency::CurrentScheduler::Detach(); } #elif defined HAVE_PTHREADS_PF parallel_for_pthreads(pbody.stripeRange(), pbody, pbody.stripeRange().size()); #else #error You have hacked and compiling with unsupported parallel framework #endif } else #endif // CV_PARALLEL_FRAMEWORK { (void)nstripes; body(range); } }
즉, TBB, OpenMP, GCD, Concurrency, pthread 중 어느 것 하나만이라도 있으면 OpenCV는 멀티 쓰레드 형태로 동작을 하게 되고, 병렬 처리를 하기 때문에 빠르게 동작한다는 것이죠.
참고로 Visual Studio 버전이 2010 이상 버전이면 HAVE_CONCURRENCY가 자동으로 #define 됩니다. 라즈베리파이같은 리눅스 머신에서는 pthread가 자동으로 동작합니다.
그렇다면 TBB랑 OpenMP, Concurrency 같은 것들끼리 성능 차이가 얼마나 있을까요? 같은 병렬 프로그래밍이라고 하더라도 TBB가 더 효과적으로 잘 동작한다면 Visual Studio에서 기본 지원하는 Concurrency 보다는 TBB를 깔아서 쓰는 것이 더 좋지 않을까요?? 저도 이런 의문을 가지고 구글링을 열심히 해보았는데요, 뚜렷한 성능 비교 결과를 찾지 못했습니다. 그러나 좀 더 생각을 해보니, 어차피 OpenCV에서 큰 성능 향상을 얻으려면 병렬 프로그래밍보다는 CUDA 또는 OpenCL 쪽을 더 고민해보는 것이 맞지 않을까 생각합니다.
그래서 제 결론은, "Visual Studio 사용할 때에는 그냥 기본 Concurrency 라이브러리를 사용하자"입니다. 굳이 번거롭게 TBB를 깔지 않아도 됩니다. (TBB을 이용해서 빌드하면 프로그램 배포 시 tbb.dll 파일도 함께 배포해야 합니다.)
참고로 Visual Studio의 Concurrency에 대한 내용은 아래 유투브 동영상을 참고하시면 좋습니다. 아래 동영상에서 설명하는 Auto Parallelization이라는 것이 Concurrency와 같은 내용입니다.
'Study > OpenCV' 카테고리의 다른 글
CMake에서 "The CXX compiler identification is unknown" 에러 해결하기 (5) | 2017.08.03 |
---|---|
OpenCV 3.2 vs. OpenCV 3.3 간단 성능 비교 (0) | 2017.07.12 |
OpenCV 3.3.0-rc 버전 릴리즈 & Visual Studio에서 빌드하기 (1) | 2017.07.11 |
OpenCV 3.2 Extra Module 빌드하기 (feat. Python) (1) | 2017.06.27 |
Visual Studio 2017에서 OpenCV 3.2 빌드하기 (0) | 2017.06.20 |