Search code examples
rmacosdata.tableopenmpapple-m1

Use OpenMP on M2 Mac with R and data.table


I am struggling to use OpenMP with R and data.table on an M2 Mac Running macOS Ventura 13.3.1. I am following the instructions at https://mac.r-project.org/openmp/. Any help would be greatly appreciated.

In summary:

  1. OpenMP seems to be correctly installed
  2. I have updated ~.R/Makevars in line with the instructions
  3. It doesn't seem that ~.R/Makevars is loading in R
  4. R SessionInfo

OpenMP seems to be correctly installed

I believe that I have successfully installed OpenMP in line with the instructions as suggested by the following output:

file.exists(
  "/usr/local/lib/libomp.dylib",
  "/usr/local/include/ompt.h",
  "/usr/local/include/omp.h",
  "/usr/local/include/omp-tools.h"
  )
# TRUE TRUE TRUE TRUE

When I try to compile the following openmp_test.c

#include <stdio.h>
#include <omp.h>

int main() {
    #pragma omp parallel
    {
        int thread_id = omp_get_thread_num();
        printf("Hello from thread %d\n", thread_id);
    }
    return 0;
}

with clang -Xclang -fopenmp -lomp openmp_test.c -o openmp_test

I can run the program with ./openmp_test and get the output

Hello from thread 2
Hello from thread 0
Hello from thread 3
Hello from thread 8
Hello from thread 1
Hello from thread 4
Hello from thread 11
Hello from thread 7
Hello from thread 10
Hello from thread 6
Hello from thread 9
Hello from thread 5

I have updated ~.R/makevars in line with the instructions

readLines("~/.R/Makevars")
# [1] "CPPFLAGS += -Xclang -fopenmp"
# [2] "LDFLAGS += -lomp"            
# [3] "TEST = test1234"               

It doesn't seem that ~.R/Makevars is loading in R

I'm not sure exactly how ~.R/Makevars works, but it doesn't seem that these environment variables are loading in R:

Sys.getenv("CPPFLAGS")
# [1] ""
Sys.getenv("LDFLAGS")
# [1] ""
Sys.getenv("TEST")
# [1] ""

In shell,

ls -al ~/.R/Makevars
# -rw-------  1 chandler  62 May 31 07:08 /Users/chandler/.R/Makevars

I have also, tried to change the permissions of the file

chmod 600 ~/.R/Makevars

And I've tried to update my .Renviron to

R_MAKEVARS_USER=~/.R/Makevars

Now

Sys.getenv("R_MAKEVARS_USER")
# [1] "~/.R/Makevars"

I am not sure of the expected output, but none of these approaches seem to be solving the issue.

R SessionInfo

R version 4.3.0 (2023-04-21)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.3.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Denver
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices
[4] utils     datasets  methods  
[7] base     

loaded via a namespace (and not attached):
[1] compiler_4.3.0

Solution

  • I ended up following the instructions here and was able to get data.table working with OpenMP:

    https://github.com/Rdatatable/data.table/issues/5419#issuecomment-1465023581

    For the data.table installation, my ~/.R/Makevars file looked liked this:

    LDFLAGS += -L/opt/homebrew/opt/libomp/lib -lomp
    CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    

    To get other packages working with OpenMP, I installed the GNU Fortran compiler as suggested here: https://mac.r-project.org/tools/

    To install the fst package, I first had to uncomment out the CPPFLAGS line in ~/.R/Makevars and add the lines for fst here.

    So, my ~/.R/Makevars looked like this:

    LDFLAGS += -L/opt/homebrew/opt/libomp/lib -lomp
    ## CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    
    CXX1X=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX98=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX11=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX14=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX17=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    

    I then installed the fst package by invoking R in the terminal and using install.packages("fstcore", type="source") and `install.packages("fst", type="source").

    I similarly installed the fixest package: install.packages("fixest", type="source")

    I removed the comment in front CPPFLAGS, so my final ~/.R/Makevars looks like this:

    LDFLAGS += -L/opt/homebrew/opt/libomp/lib -lomp
    CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    
    CXX1X=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX98=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX11=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX14=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    CXX17=/opt/homebrew/Cellar/gcc/13.1.0/bin/g++-13 -fopenmp
    

    In the end, everything seems to work:

    library(data.table); library(fst); library(fixest);
    data.table::getDTthreads()
    # [1] 6
    fst::threads_fst()
    # [1] 12
    fixest::getFixest_nthreads()
    # [1] 6
    

    So, for me, in ~/.R/Makevars, the line

    CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    

    is necessary to install data.table but needs to commented out to install other packages that also rely on OpenMP

    Update: September 2024

    I re-installed these packages. I first installed data.table using install.packages("data.table", type=source) with the following ~.R/Makevars:

    LDFLAGS += -L/opt/homebrew/opt/libomp/lib -lomp
    CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    

    I then updated my ~./Makevars to the following:

    LDFLAGS += -L/opt/homebrew/opt/libomp/lib -lomp
    CPPFLAGS += -I/opt/homebrew/opt/libomp/include -Xclang -fopenmp
    
    CXX1X=/opt/homebrew/Cellar/gcc/14.2.0/bin/g++-14 -fopenmp
    CXX98=/opt/homebrew/Cellar/gcc/14.2.0/bin/g++-14 -fopenmp
    CXX11=/opt/homebrew/Cellar/gcc/14.2.0/bin/g++-14 -fopenmp
    CXX14=/opt/homebrew/Cellar/gcc/14.2.0/bin/g++-14 -fopenmp
    CXX17=/opt/homebrew/Cellar/gcc/14.2.0/bin/g++-14 -fopenmp
    

    I then installed install.packages("fstcore", type="source"), install.packages("fst", type="source"), and install.packages("fixest", type="source").