diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d4618644..a58801b4c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,17 @@ SET (PACKAGE_INC_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/inc) option (USE_LIBFTDI "USE_LIBFTDI" OFF) option (USE_OPENMP "USE_OPENMP" OFF) option (WARNINGS_AS_ERRORS "WARNINGS_AS_ERRORS" OFF) + +if (APPLE AND USE_OPENMP) + if (NOT DEFINED OpenMP_ROOT AND NOT DEFINED ENV{OpenMP_ROOT}) + if (EXISTS "/opt/homebrew/opt/libomp") + set (OpenMP_ROOT "/opt/homebrew/opt/libomp") + elseif (EXISTS "/usr/local/opt/libomp") + set (OpenMP_ROOT "/usr/local/opt/libomp") + endif () + endif () +endif () + option (BUILD_OYMOTION_SDK "BUILD_OYMOTION_SDK" OFF) option (BUILD_SYNCHRONI_SDK "BUILD_SYNCHRONI_SDK" ON) option (BUILD_BLUETOOTH "BUILD_BLUETOOTH" OFF) diff --git a/docs/BuildBrainFlow.rst b/docs/BuildBrainFlow.rst index 6a87bdcca..8a07a7c58 100644 --- a/docs/BuildBrainFlow.rst +++ b/docs/BuildBrainFlow.rst @@ -280,6 +280,35 @@ MacOS python3 build.py --help +OpenMP Acceleration +~~~~~~~~~~~~~~~~~~~~ + +BrainFlow supports multi-core parallel execution via OpenMP for intensive data handling routines, including multi-channel signal filtering, wavelet denoising, band power calculations, and KissFFT transformations. + +To build BrainFlow with OpenMP support, first ensure that the OpenMP development package is available on your system: + +- **Linux:** Install the OpenMP development headers using your package manager, e.g. :code:`sudo apt-get install libomp-dev` on Debian/Ubuntu or :code:`sudo dnf install libgomp` on Fedora/RHEL. +- **MacOS:** Install OpenMP via Homebrew: :code:`brew install libomp`. BrainFlow's build configuration automatically discovers Homebrew's :code:`libomp` installation. +- **Windows:** OpenMP is included with MSVC in Visual Studio; no additional installation is needed. + +.. compound:: + + Using :code:`build.py`: :: + + python3 tools/build.py --use-openmp + +.. compound:: + + Using CMake directly: :: + + cmake -B build -DUSE_OPENMP=ON + cmake --build build --config Release + +.. note:: + + On Apple Silicon macOS, Homebrew's :code:`libomp` is built for the native architecture (:code:`arm64`). :code:`tools/build.py --use-openmp` automatically configures the build for your machine's native architecture. If invoking CMake directly on Apple Silicon, you can pass :code:`-DCMAKE_OSX_ARCHITECTURES=arm64` (or :code:`x86_64` on Intel Macs). + + Android --------- diff --git a/src/data_handler/build.cmake b/src/data_handler/build.cmake index 7aa3d5b50..5f4beee70 100644 --- a/src/data_handler/build.cmake +++ b/src/data_handler/build.cmake @@ -1,7 +1,12 @@ +if (USE_OPENMP) + set (KISSFFT_OPENMP ON CACHE BOOL "Build kissfft with OpenMP support" FORCE) +endif (USE_OPENMP) + include (${CMAKE_CURRENT_SOURCE_DIR}/third_party/DSPFilters/build.cmake) include (${CMAKE_CURRENT_SOURCE_DIR}/third_party/wavelib/build.cmake) include (${CMAKE_CURRENT_SOURCE_DIR}/third_party/kissfft/build.cmake) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) SET (DATA_HANDLER_NAME "DataHandler") if (APPLE) diff --git a/third_party/kissfft/build.cmake b/third_party/kissfft/build.cmake index 413e226e6..dd8cc42fd 100644 --- a/third_party/kissfft/build.cmake +++ b/third_party/kissfft/build.cmake @@ -143,7 +143,13 @@ endif() # if(KISSFFT_OPENMP) - if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang") + find_package(OpenMP) + if(TARGET OpenMP::OpenMP_C) + target_link_libraries(kissfft PRIVATE OpenMP::OpenMP_C) + elseif(OpenMP_C_FOUND) + target_compile_options(kissfft PRIVATE ${OpenMP_C_FLAGS}) + target_link_libraries(kissfft PRIVATE ${OpenMP_C_LIBRARIES}) + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang|MSVC") if (NOT MSVC) target_compile_options(kissfft PRIVATE -fopenmp) if(${CMAKE_VERSION} VERSION_LESS "3.13.0") @@ -159,11 +165,11 @@ if(KISSFFT_OPENMP) target_link_options(kissfft PRIVATE "/openmp") endif() endif() - set(KISSFFT_EXPORT_SUFFIX "-openmp") - set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}-openmp") else() message(FATAL_ERROR "Don't know how to enable OpenMP for this compiler") endif() + set(KISSFFT_EXPORT_SUFFIX "-openmp") + set(KISSFFT_OUTPUT_NAME "kissfft-${KISSFFT_DATATYPE}-openmp") endif() # @@ -227,7 +233,9 @@ function(add_kissfft_executable NAME) set_target_properties(${NAME} PROPERTIES OUTPUT_NAME "${NAME}-${KISSFFT_DATATYPE}") else() - if (NOT MSVC) + if(TARGET OpenMP::OpenMP_C) + target_link_libraries(${NAME} PRIVATE OpenMP::OpenMP_C) + elseif (NOT MSVC) target_compile_options(${NAME} PRIVATE -fopenmp) if(${CMAKE_VERSION} VERSION_LESS "3.13.0") target_link_libraries(${NAME} PRIVATE "-fopenmp") diff --git a/tools/build.py b/tools/build.py index 5a93d08bd..57d46b5f3 100644 --- a/tools/build.py +++ b/tools/build.py @@ -261,6 +261,9 @@ def config(args): if hasattr(args, 'oymotion') and args.oymotion: cmd_config.append('-DBUILD_OYMOTION_SDK=ON') if hasattr(args, 'cmake_osx_architectures') and args.cmake_osx_architectures: + if args.use_openmp and args.cmake_osx_architectures == 'arm64;x86_64': + print('Building with OpenMP on macOS: adjusting default architectures to native %s because Homebrew libomp is single-architecture.' % platform.machine()) + args.cmake_osx_architectures = platform.machine() cmd_config.append('-DCMAKE_OSX_ARCHITECTURES=%s' % args.cmake_osx_architectures) if hasattr(args, 'cmake_osx_deployment_target') and args.cmake_osx_deployment_target: