Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixing the BLAS hot-switching mechanism #390

Closed
kforner opened this issue Mar 16, 2022 · 27 comments · Fixed by #386
Closed

fixing the BLAS hot-switching mechanism #390

kforner opened this issue Mar 16, 2022 · 27 comments · Fixed by #386

Comments

@kforner
Copy link

kforner commented Mar 16, 2022

There is a regression with the BLAS switching mechanism, as described here: https://www.rocker-project.org/use/other_topics/,
in rocker-versioned2:

%docker run --rm rocker/verse:4.1.2 bash

R -q -e 'sessionInfo()' | grep so
BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.8.so

update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/blas/libblas.so.3

# nothing changed
R -q -e 'sessionInfo()' | grep so
BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.8.so

# expected considering that
# ldd /usr/local/lib/R/lib/libR.so | grep blas
	libopenblas.so.0 => /lib/x86_64-linux-gnu/libopenblas.so.0 (0x00007f20400b0000)

This seems to be related to the auto-detection of the openblas lib during the R configuration, so that the --with-blas="-lopenblas" is used (cf https://cran.r-project.org/doc/manuals/r-devel/R-admin.html#OpenBLAS).

One simple way to fix that is to postpone the openblas installation AFTER the R compilation:

git diff scripts/install_R.sh
diff --git i/scripts/install_R.sh w/scripts/install_R.sh
index bad57c4..30f996b 100755
--- i/scripts/install_R.sh
+++ w/scripts/install_R.sh
@@ -24,11 +24,7 @@ export DEBIAN_FRONTEND=noninteractive
 R_HOME=${R_HOME:-/usr/local/lib/R}
 
 READLINE_VERSION=8
-OPENBLAS=libopenblas-dev
-if [ ${UBUNTU_VERSION} == "bionic" ]; then
-  READLINE_VERSION=7
-  OPENBLAS=libopenblas-dev
-fi
+
 
 apt-get update \
   && apt-get install -y --no-install-recommends \
@@ -46,7 +42,6 @@ apt-get update \
     libicu* \
     libpcre2* \
     libjpeg-turbo* \
-    ${OPENBLAS} \
     libpangocairo-* \
     libpng16* \
     libreadline${READLINE_VERSION} \
@@ -127,6 +122,14 @@ make
 make install
 make clean
 
+# Openblas installation: N.B: this must happen AFTER the R compilation otherwise the BLAS hot-swapping does not work
+OPENBLAS=libopenblas-dev
+if [ ${UBUNTU_VERSION} == "bionic" ]; then
+  READLINE_VERSION=7
+  OPENBLAS=libopenblas-dev
+fi
+apt-get install -y --no-install-recommends ${OPENBLAS}
+
 ## Add a default CRAN mirror
 echo "options(repos = c(CRAN = '${CRAN}'), download.file.method = 'libcurl')" >> ${R_HOME}/etc/Rprofile.site

then:

docker build -f dockerfiles/r-ver_4.1.2.Dockerfile  -t r-ver_4.1.2_fixed  .
docker run --rm -ti r-ver_4.1.2_fixed bash

R -q -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/local/lib/R/lib/libRlapack.so

update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/blas/libblas.so.3

R -q -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/local/lib/R/lib/libRlapack.so

# fixed because:
ldd /usr/local/lib/R/lib/libR.so | grep blas
	libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007febf46aa000)

So AFAIU, this restores the previous and expected behaviour (for BLAS only, not for Lapack, as pointed out by Dirk).

@eddelbuettel
Copy link
Member

Please explain why you only switch BLAS -- and not both BLAS and LAPACK as is common.

C.f. https://wiki.debian.org/DebianScience/LinearAlgebraLibraries

@kforner
Copy link
Author

kforner commented Mar 16, 2022

I was just following the instructions from the rocker website: https://www.rocker-project.org/use/other_topics/ and focusing on the BLAS lib.
But you're right, this fix does not work for Lapack.
It seems now to be hard-coded to /usr/local/lib/R/lib/libRlapack.so, the internal implementation, which is not what we want.
I'll have a closer look on managing lapack as well...

@eddelbuettel
Copy link
Member

See what I stated in the other thread. If desired, using --with-blas and --with-lapack with the build-dependencies is all.

@kforner
Copy link
Author

kforner commented Mar 16, 2022

I think I got it: pre-installing a lapack lib will trigger the proper R configuration: LAPACK(generic).

The install script is modified:

  • to postpone the openblas lib install
  • to pre-install a lapack lib
▶ git diff scripts/install_R.sh
diff --git i/scripts/install_R.sh w/scripts/install_R.sh
index bad57c4..aae8549 100755
--- i/scripts/install_R.sh
+++ w/scripts/install_R.sh
@@ -24,11 +24,7 @@ export DEBIAN_FRONTEND=noninteractive
 R_HOME=${R_HOME:-/usr/local/lib/R}
 
 READLINE_VERSION=8
-OPENBLAS=libopenblas-dev
-if [ ${UBUNTU_VERSION} == "bionic" ]; then
-  READLINE_VERSION=7
-  OPENBLAS=libopenblas-dev
-fi
+
 
 apt-get update \
   && apt-get install -y --no-install-recommends \
@@ -46,7 +42,6 @@ apt-get update \
     libicu* \
     libpcre2* \
     libjpeg-turbo* \
-    ${OPENBLAS} \
     libpangocairo-* \
     libpng16* \
     libreadline${READLINE_VERSION} \
@@ -103,6 +98,10 @@ else                                                                 \
 fi &&                                                                \
     tar xzf R-${R_VERSION}.tar.gz &&
 
+
+# install a lapack so that R is configured using with "LAPACK(generic)"
+apt-get install -y --no-install-recommends liblapack-dev
+
 cd R-${R_VERSION}
 R_PAPERSIZE=letter \
 R_BATCHSAVE="--no-save --no-restore" \
@@ -127,6 +126,14 @@ make
 make install
 make clean
 
+# Openblas installation: N.B: this must happen AFTER the R compilation otherwise the BLAS hot-swapping does not work
+OPENBLAS=libopenblas-dev
+if [ ${UBUNTU_VERSION} == "bionic" ]; then
+  READLINE_VERSION=7
+  OPENBLAS=libopenblas-dev
+fi
+apt-get install -y --no-install-recommends ${OPENBLAS}
+update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
 ## Add a default CRAN mirror
 echo "options(repos = c(CRAN = '${CRAN}'), download.file.method = 'libcurl')" >> ${R_HOME}/etc/Rprofile.site

Then:

docker build -f dockerfiles/r-ver_4.1.2.Dockerfile  -t r-ver_4.1.2_fixed  .
docker run --rm -ti r-ver_4.1.2_fixed bash

# use openblas for both BLAS and lapack
R -q -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3

# hot-switch BLAS
update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/blas/libblas.so.3
R -q -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3

# hot-switch lapack
update-alternatives --set liblapack.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3
R -q -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

# ldd /usr/local/lib/R/lib/libR.so | grep blas
	libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007faa57ae0000)

for reference, the R configuration summary:

R is now configured for x86_64-pc-linux-gnu

  Source directory:            .
  Installation directory:      /usr/local

  C compiler:                  gcc  -g -O2
  Fortran fixed-form compiler: gfortran -fno-optimize-sibling-calls -g -O2

  Default C++ compiler:        g++ -std=gnu++14  -g -O2
  C++11 compiler:              g++ -std=gnu++11  -g -O2
  C++14 compiler:              g++ -std=gnu++14  -g -O2
  C++17 compiler:              g++ -std=gnu++17  -g -O2
  C++20 compiler:              g++ -std=gnu++2a  -g -O2
  Fortran free-form compiler:  gfortran -fno-optimize-sibling-calls -g -O2
  Obj-C compiler:	        

  Interfaces supported:        X11, tcltk
  External libraries:          pcre2, readline, BLAS(generic), LAPACK(generic), curl
  Additional capabilities:     PNG, JPEG, TIFF, NLS, cairo, ICU
  Options enabled:             shared R library, R profiling, memory profiling

  Capabilities skipped:        
  Options not enabled:         shared BLAS

  Recommended packages:        yes

Is that the correct and intended behaviour ?

@cboettig
Copy link
Member

nice @kforner ! was just having the same thought -- I think we should probably have included an external lapack lib. Glad you got to the bottom of this! The proposed changes seem reasonable to me.

Having the openblas install in a later layer probably makes sense too.

I guess we stick with pthread as the default openblas? I'm in favor of a threaded open default, but not convinced pthread is preferable to the openmp flavor (merely chose that as it is the ubuntu repos default for openblas).

@kforner
Copy link
Author

kforner commented Mar 16, 2022

Thanks @cboettig. There's probably a problem in my changes since READLINE gets fixed AFTER being used.
Would you want me to do a MR, or will you take care of it?

I have really no informed opinion on the flavor of openblas to use.

@eitsupi
Copy link
Member

eitsupi commented Mar 16, 2022

I'm currently doing a major rewrite of the script that installs R in #386.
Do you think we can fix it in this PR?

@kforner
Copy link
Author

kforner commented Mar 16, 2022

fine with me [but I'm not sure whom you're asking]

@cboettig
Copy link
Member

@eitsupi yup, was thinking the same thing, do you want to roll @kforner 's proposed changes re blas into #386 ? That's probably the simplest.

@benz0li
Copy link
Contributor

benz0li commented Mar 17, 2022

See what I stated in the other thread. If desired, using --with-blas and --with-lapack with the build-dependencies is all.

Here's what I've noticed with Debian 11, which also seems to be the case for Ubuntu 21.10 (and 22.04?).

A build using --with-blas and --with-lapack having libopenblas-dev installed returns

> sessionInfo()
R version 4.1.3 (2022-03-10)
Platform: aarch64-unknown-linux-gnu (64-bit)
Running under: Debian GNU/Linux 11 (bullseye)

Matrix products: default
BLAS/LAPACK: /usr/lib/aarch64-linux-gnu/openblas-pthread/libopenblasp-r0.3.13.so
[...]

A build using --with-blas and --with-lapack having liblapack-dev installed and hot-switching to libopenblas-dev afterwards returns

> sessionInfo()
R version 4.1.3 (2022-03-10)
Platform: aarch64-unknown-linux-gnu (64-bit)
Running under: Debian GNU/Linux 11 (bullseye)

Matrix products: default
BLAS:   /usr/lib/aarch64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/aarch64-linux-gnu/openblas-pthread/libopenblasp-r0.3.13.so

Does anyone know what the difference is between [openblas-pthread/]libopenblasp-r0.3.13.so and [openblas-pthread/]libblas.so.3?

Is [openblas-pthread/]libopenblasp-r0.3.13.so simply the superset of [openblas-pthread/]libblas.so.3 and [openblas-pthread/]liblapack.so.3?

Is there a difference in linking? Does it cause any trouble?

@eitsupi
Copy link
Member

eitsupi commented Mar 20, 2022

I believe I made the changes proposed in #390 (comment).
dbe9026

I have not yet built and tested it.

@eitsupi
Copy link
Member

eitsupi commented Mar 20, 2022

I was able to build rocker/r-ver:4.1.3 from dbe9026.
Does this look good?

amd64

$ R -s -e "sessionInfo()"
R version 4.1.3 (2022-03-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

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

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

arm64

$ R -s -e "sessionInfo()"
R version 4.1.3 (2022-03-10)
Platform: aarch64-unknown-linux-gnu (64-bit)
Running under: Ubuntu 20.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/aarch64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/aarch64-linux-gnu/openblas-pthread/liblapack.so.3

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

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

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

@kforner
Copy link
Author

kforner commented Mar 21, 2022

Could you share the output of ldd /usr/local/lib/R/lib/libR.so | grep blas ?

And check that it correctly switches when you do:

update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/blas/libblas.so.3
update-alternatives --set liblapack.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3

@kforner
Copy link
Author

kforner commented Mar 21, 2022

@benz0li

Is [openblas-pthread/]libopenblasp-r0.3.13.so simply the superset of [openblas-pthread/]libblas.so.3 and [openblas-pthread/]liblapack.so.3?

according to this (message 5) it seems so

The problem is that libopenblasp-r0.3.5.so contains exactly the same
symbols as libblas.so and liblapack.so. This seems to be confusing
linkers, e.g. see Bug#914655 for python-scipy.

and that it should NOT be used, cf message 12

libopenblasp-r0.3.5.so should never be used as BLAS / LAPACK provider
as it's SONAME unmatches the depencency template and would incur
breakage to our dependency tree.

and even be deleted:

I'm sure libopenblasp-r0.3.5.so cannot be removed. Every OpenBLAS
flavor will ship 3 shared objects:

Is there a difference in linking?
yes. The SONAME seems to have an impact.

@benz0li
Copy link
Contributor

benz0li commented Mar 21, 2022

@kforner Thank you for the feedback. /usr/lib/aarch64-linux-gnu/openblas-pthread/libopenblasp-r0.3.13.so can't be deleted, though.

root@295f1f17b708:/# ldd /usr/local/lib/R/lib/libR.so | grep blas
	libblas.so.3 => /usr/lib/aarch64-linux-gnu/libblas.so.3 (0x0000ffff8af1b000)
	libopenblas.so.0 => /usr/lib/aarch64-linux-gnu/libopenblas.so.0 (0x0000ffff894a3000)
root@295f1f17b708:/#
root@295f1f17b708:/# ls -al /usr/lib/aarch64-linux-gnu/openblas-pthread/
total 54476
drwxr-xr-x 4 root root     4096 Mar 21 09:15 .
drwxr-xr-x 1 root root    12288 Mar 21 09:15 ..
drwxr-xr-x 3 root root     4096 Mar 21 09:15 cmake
lrwxrwxrwx 1 root root       13 Apr 18  2021 libblas.a -> libopenblas.a
lrwxrwxrwx 1 root root       12 Apr 18  2021 libblas.so -> libblas.so.3
-rw-r--r-- 1 root root   399904 Apr 18  2021 libblas.so.3
lrwxrwxrwx 1 root root       13 Apr 18  2021 liblapack.a -> libopenblas.a
lrwxrwxrwx 1 root root       14 Apr 18  2021 liblapack.so -> liblapack.so.3
-rw-r--r-- 1 root root  5418760 Apr 18  2021 liblapack.so.3
lrwxrwxrwx 1 root root       22 Apr 18  2021 libopenblas.a -> libopenblasp-r0.3.13.a
-rw-r--r-- 1 root root 31903102 Apr 18  2021 libopenblasp-r0.3.13.a
-rw-r--r-- 1 root root 18031736 Apr 18  2021 libopenblasp-r0.3.13.so
lrwxrwxrwx 1 root root       23 Apr 18  2021 libopenblas.so -> libopenblasp-r0.3.13.so
lrwxrwxrwx 1 root root       23 Apr 18  2021 libopenblas.so.0 -> libopenblasp-r0.3.13.so
drwxr-xr-x 2 root root     4096 Mar 21 09:15 pkgconfig
root@295f1f17b708:/#

@kforner
Copy link
Author

kforner commented Mar 21, 2022

@benz0li With the above proposed changes, libR.so should no longer be linked to libopenblas.so.0, but instead to libblas.so and liblapack.so

@eitsupi
Copy link
Member

eitsupi commented Mar 21, 2022

Could you share the output of ldd /usr/local/lib/R/lib/libR.so | grep blas ?

And check that it correctly switches when you do:

update-alternatives --set libblas.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/blas/libblas.so.3
update-alternatives --set liblapack.so.3-x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3

Of course, those commands seem to work.

$ ldd /usr/local/lib/R/lib/libR.so | grep blas
        libblas.so.3 => /lib/aarch64-linux-gnu/libblas.so.3 (0x0000ffff8d14f000)

$ R -s -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/aarch64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/aarch64-linux-gnu/openblas-pthread/liblapack.so.3

$ update-alternatives --set libblas.so.3-aarch64-linux-gnu /usr/lib/aarch64-linux-gnu/blas/libblas.so
.3
update-alternatives: using /usr/lib/aarch64-linux-gnu/blas/libblas.so.3 to provide /usr/lib/aarch64-linux-gnu/libblas.so.3 (libblas.so.3-aarch64-linux-gnu) in manual mode

$ R -s -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/aarch64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/aarch64-linux-gnu/openblas-pthread/liblapack.so.3

$ update-alternatives --set liblapack.so.3-aarch64-linux-gnu /usr/lib/aarch64-linux-gnu/lapack/liblap
ack.so.3
update-alternatives: using /usr/lib/aarch64-linux-gnu/lapack/liblapack.so.3 to provide /usr/lib/aarch64-linux-gnu/liblapack.so.3 (liblapack.so.3-aarch64-linux-gnu) in manual mode

$ R -s -e 'sessionInfo()' | grep so
BLAS:   /usr/lib/aarch64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/aarch64-linux-gnu/lapack/liblapack.so.3.9.0

@kforner
Copy link
Author

kforner commented Mar 21, 2022

@eitsupi That looks good !

@kforner
Copy link
Author

kforner commented Mar 21, 2022

@eitsupi Any idea about when your dev will be available ?

@eitsupi
Copy link
Member

eitsupi commented Mar 22, 2022

Sorry for the delay in work.
It appears to be functionally fine, so I will complete the minor work and merge #386 today or tomorrow.

@eitsupi
Copy link
Member

eitsupi commented Mar 23, 2022

Note that rocker/r-ver:4.1.3 and rocker/rstudio:4.1.3, which reflect this fix, will be pushed to DockerHub today, but the other images will not be built due to the rocker/tidyverse build failure (#393).

@eitsupi
Copy link
Member

eitsupi commented Apr 11, 2022

@kforner We have no problem uninstalling liblapack-dev after installing R, right?
If we can uninstall it, we can reduce the size of the rocker/r-ver by 30 MB.

@kforner
Copy link
Author

kforner commented Apr 11, 2022

I think so, if it's not set to be used via the update-alternatives mechanism.

@eitsupi
Copy link
Member

eitsupi commented Apr 11, 2022

Even after uninstalling liblapack-dev on current rocker/r-ver:latest, update-alternatives seems to be running fine.

@eitsupi
Copy link
Member

eitsupi commented Apr 11, 2022

Sorry, as I wrote in #412, I was mistaken.
It does not seem to be possible to remove it.

@kforner
Copy link
Author

kforner commented Apr 14, 2022

I've noticed that the latest (as of today) rocker/verse:4.1.3 has these changes, but not the latest rocker/verse:4.1.2.
Is this expected ?

@eitsupi
Copy link
Member

eitsupi commented Apr 14, 2022

@kforner Please check the README

Latest R version images will be built on a rolling basis; when the definition files or Rocker scripts are updated, they are immediately built by GitHub Actions.

Non-latest R version images will be built when a new R version is released. At this time, a tag and a GitHub release will also be created.

All currently tagged images are listed on the wiki as to which commits they were built from.
https://github.com/rocker-org/rocker-versioned2/wiki

(However, due to a GitHub Actions error that has been occurring since yesterday #420, images built yesterday have not been reflected.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants