1

I am trying to parallelize a for loop in cython using prange. My setup file is pretty basic:

from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize('my_cython_code.pyx'))

So I am using -fopenmp as a cython compiler flag, which I accomplish by having the first two lines of the my_cython_code module be:

# distutils: extra_compile_args = -fopenmp
# distutils: extra_link_args = -fopenmp

However, my machine runs on OSX, and the mac gcc compiler is essentially Clang, which does not support OpenMP. This means that when I try to build my parallelized cython extension module, I get a fatal compiler error:

ld: library not found for -lgomp
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'gcc' failed with exit status 1

Is there a way around this problem? How can I use a different compiler that will accept OpenMP when building my extension? Are there other approaches that will let me parallelize cython for loops with standard mac architecture?

3 Answers 3

3

After a lot of trial-and-error, I made cython code to actually parallelize on an M1 mac. The crucial step was supplying both -lomp and -lmpi flags during linking.

  1. Install llvm using homebrew since the version bundled by apple doesn't support openmpi:
brew install llvm open-mpi libomp
  1. The flags we need to pass to clang in order to compile openmpi code can fortunately be found out by running the command mpicc -showme:
$ mpicc -showme
clang -I/opt/homebrew/Cellar/open-mpi/4.1.2/include -L/opt/homebrew/Cellar/open-mpi/4.1.2/lib -L/opt/homebrew/opt/libevent/lib -lmpi
  1. Then, we can set the environment variables CPATH and LIBRARY_PATH accordingly:
export LIBRARY_PATH=/opt/homebrew/Cellar/open-mpi/4.1.2/lib:/opt/homebrew/opt/libevent/lib
export CPATH=/opt/homebrew/Cellar/open-mpi/4.1.2/include
  1. The setup.py must specify extra_compile_args and extra_link_args:
setup(
    ext_modules = cythonize([
        Extension(
            'foo',
            ['foo.pyx'],
            extra_compile_args=['-fopenmp'],
            extra_link_args=['-lmpi', '-lomp'],
        )
    ]
)

Here is a full MWE.

Sign up to request clarification or add additional context in comments.

2 Comments

I believe OpenMPI is pretty different OpenMP. It's more to do with distributed computing where the cores can't see each other. I suspect you can remove it and your example would still work.
Please be sure to read Stack Overflow's self-promotion policy when referencing your own content.
2

As you state, you are using a compiler that does not support OpenMP. You need to use one that does. Please look up how to install GCC with Macports or Homebrew if you want to use proper GCC that supports OpenMP.

Other solutions include:

  • Installing the (obviously commercial) Intel compiler for Mac OSX, which supports OpenMP.

  • Building the Clang-LLVM-OpenMP branch from source. This is a highly nontrivial effort and I do not recommend to a novice.

All of this presumes that you are correct that Cython uses OpenMP for parallelization. I do not use Cython and thus do not know how prange is implemented.

1 Comment

For homebrew use: brew reinstall gcc --without-multilib. Be sure to set your bash path to pick this newly installed gcc. In my case I set: ln -s /usr/local/Cellar/gcc/5.2.0/bin/gcc-5 ~/usr/bin/gcc (and I have export PATH="/Users/arokem/usr/bin:/usr/local/sbin:$PATH" in my bash_profile)
2

Apparently, Apple dropped the support of OpenMP sometime ago, therefore, you cannot compile the code that includes this dependency with a standard gcc. A good way to get around that is to install LLVM and compile with it. Here is the sequence that worked for me:

Install LLVM:

brew install llvm

Include OpenMP flags(-fopenmp -lomp) to setup.py. -lomp flag is not described anywhere for some reason, but it is important for a correct compilation:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize, build_ext


exts = [Extension(name='name_your_module',
                  sources=['your_module.pyx'],
                  extra_compile_args=['-fopenmp'],
                  extra_link_args=['-lomp']
                  )]

setup(name = 'name_your_module',
      ext_modules=cythonize(exts,
      cmdclass={'build_ext': build_ext})

And then compile the code with LLVM:

CC=/usr/local/opt/llvm/bin/clang++ python setup.py build_ext --inplace

This should result in a parallelized .so

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.