Work in progess… (sugerencias y comentarios serán bien recibidos).
La idea es preparar R para HPSC (High Performance Statistical Computing) de forma transparente para el usuario y posteriormente ver herramientas adicionales (paquetes y funciones) para procesamiento en paralelo (con CPUs y GPUs).
Algunos paquetes se pueden configurar de forma transparente (Matrix
, TensorFlow
, …) pero otras herramientas requieren adaptar la programación.
El procedimiento habitual sería compilar las librerías de álgebra lineal (BLAS y LAPACK) y posteriormente R desde el código fuente tratando de conseguir la máxima optimización. Sin embargo compilar R de esta forma puede presentar problemas (ver R Installation and Administration) y depende de la instalación previa de BLAS/LAPACK. En la última sección se muestran algunas referencias para esta aproximación (se podrían instalar distintas versiones en distintos directorios).
Un enfoque más simple consiste en instalar R desde CRAN (siguiendo los pasos descritos en este post), que por defecto utilizará una implementación BLAS/LAPACK estable y compatible con distintas plataformas pero que no está optimizadas para el rendimiento, y posteriormente reemplazar las librerías estándar de referencia (típicamente enlazando con las proporcionadas por OpenBLAS, ATLAS o Intel MKL), como se describe en las secciones siguientes.
Otra alternativa sería instalar Microsoft R Open con MKL, aunque Microsoft retiró R Open el 1 de julio de 2022 y la última versión disponible es la 4.0.2 (Microsoft R Application Network y CRAN Time Machine se retirarán el 1 de julio de 2023, ya que SQL Server y Azure SQL pasaron a emplear la versión oficial de R).
Antes de nada, puede ser recomendable crear un directorio donde descargar archivos (si se instala RStudio, Intel MKL o se compila R desde el código fuente):
mkdir installr
cd installr
Fuentes:
Instalación de R
Como ya se comentó, el primer paso sería la instalación de R siguiendo los pasos descritos en este post.
Configurar R para HPC en Ubuntu/Debian
Después de instalar R el siguiente paso es reemplazar las librerías estándar BLAS/LAPACK por las proporcionadas por OpenBLAS, ATLAS o Intel MKL.
Posteriormente se podrá seleccionar que librerías de desea emplear, como se muestra más adelante.
Configurar R para emplear OpenBLAS o ATLAS
Instalar OpenBLAS o ATLAS
Instalar OpenBLAS:
sudo apt-get install libopenblas-base
Instalar ATLAS (Automatically Tuned Linear Algebra Software):
sudo apt-get install libatlas3-base liblapack3
Seleccionar el número de núcleos/hilos
Por defecto OpenBLAS (y OpenMP) utilizan todos los núcleos disponibles.
Nos puede interesar establecer el número de núcleos/threads que empleará OpenBLAS a través de la variable de entorno OPENBLAS_NUM_THREADS
o a través de OMP_NUM_THREADS
(el orden de prioridades es OPENBLAS_NUM_THREADS
> GOTO_NUM_THREADS
> OMP_NUM_THREADS
), e.g.:
echo "OMP_NUM_THREADS=8" | sudo tee -a /etc/environment
El código anterior no tendrá efecto hasta que se reinicie el sistema o se vuelva a iniciar sesión (temporalmente se podría ejecutar export OMP_NUM_THREADS=8
). En R se puede emplear las funciones Sys.getenv('OMP_NUM_THREADS')
y Sys.setenv(OMP_NUM_THREADS = 8)
.
El último paso sería enlazar estas librerías como se describe en esta sección.
Configurar R para emplear Intel Math Kernel Library (MKL)
Seguiremos los pasos descritos en Adding Intel MKL easily via a simple script, actualizados a la última versión y de forma interactiva.
Instalación de Intel MKL
Revisar las versiones disponibles en el repositorio: Installing Intel Performance Libraries Using APT Repository. Instalaremos únicamente la última versión de 64bits de MKL (e.g. intel-mkl-64bit-2020.0-088), por lo que añadiremos solo ese repositorio. Antes hay que descargar y añadir la llave GnuPG.
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
sudo sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list'
sudo apt update
sudo apt install intel-mkl-64bit-2020.0-088
El enlace anterior puede no estar actualizado, se pueden listar los paquetes disponibles con:
apt-cache search intel-mkl-64bit
Integrate MKL
El siguiente código de Installing Intel Performance Libraries Using APT Repository, enlaza las librerías MKL mediante código (estableciendo una prioridad alta, 150), pero puede ser recomendable saltarse este paso (no los siguientes) y hacerlo manualmente como se describe en esta sección.
One the key advantages of a Debian or Ubuntu system is the overall integration providing a raft of useful features. One of these is the seamless and automatic selection of alternatives. By declaring a particular set of BLAS and LAPACK libraries the default, all application linked against this interface will use the default.
Better still, users can switch between these as well. So here we can make the MKL default for BLAS and LAPACK:
## update alternatives
sudo update-alternatives --install /usr/lib/x86_64-linux-gnu/libblas.so libblas.so-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so 150
sudo update-alternatives --install /usr/lib/x86_64-linux-gnu/libblas.so.3 libblas.so.3-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so 150
sudo update-alternatives --install /usr/lib/x86_64-linux-gnu/liblapack.so liblapack.so-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so 150
sudo update-alternatives --install /usr/lib/x86_64-linux-gnu/liblapack.so.3 liblapack.so.3-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so 150
Next, we have to tell the dyanmic linker about two directories use by the MKL, and have it update its cache:
echo "/opt/intel/lib/intel64" | sudo tee /etc/ld.so.conf.d/mkl.conf
echo "/opt/intel/mkl/lib/intel64" | sudo tee -a /etc/ld.so.conf.d/mkl.conf
sudo ldconfig
As discussed in issue ticket #2, mixing Intel OpenMP and GNU OpenMP run-times in one application can lead to issues. Since most of the open-source performance libraries use GNU OpenMP it is safer to make the MKL library also use GNU OpenMP as well by setting
MKL_THREADING_LAYER=GNU
in either/etc/environment
or your local per-user settings. Here we use the file in/etc
:
echo "MKL_THREADING_LAYER=GNU" | sudo tee -a /etc/environment
NOTA: El código anterior no tendrá efecto hasta que se reinicie el sistema o se vuelva a iniciar sesión (temporalmente se podría ejecutar export MKL_THREADING_LAYER=GNU
).
Thanks to Evarist Fomenko from Intel’s Novosibirsk office for help with this point.
Use the MKL
Now the MKL is ‘known’ and the default. If we start R, its
sessionInfo()
shows the MKL:
Matrix products: default
BLAS/LAPACK: /opt/intel/compilers_and_libraries_2020.0.166/linux/mkl/lib/intel64_lin/libmkl_rt.so
Desinstalar o desenlazar MKL
Desenlazar (como ya se comentó, puede ser recomendable hacerlo manualmente como se describe aquí):
sudo update-alternatives --remove libblas.so-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so
sudo update-alternatives --remove libblas.so.3-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so
sudo update-alternatives --remove liblapack.so-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so
sudo update-alternatives --remove liblapack.so.3-x86_64-linux-gnu /opt/intel/mkl/lib/intel64/libmkl_rt.so
Desinstalar:
sudo apt-get autoremove intel-mkl-64bit-2020.0-088
Problemas con MKL
Al ejecutar paquetes que se compilan con LAPACK (npsp
) aparecieron algunos problemas con los resultados… Pendiente volver a testear…
Seleccionar librerías BLAS y LAPACK
R por defecto emplea las librerías dinámicas por lo que solo sería necesario enlazar libblas.so.3 y liblapack.so.3 (libblas.so.3-x86_64-linux-gnu y liblapack.so.3-x86_64-linux-gnu en la última version de Ubuntu).
Enlazar BLAS:
sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu
Existen 4 opciones para la alternativa libblas.so.3-x86_64-linux-gnu (que provee /usr/lib/x86_64-linux-gnu/libblas.so.3).
Selección Ruta Prioridad Estado
------------------------------------------------------------
* 0 /opt/intel/mkl/lib/intel64/libmkl_rt.so 150 modo automático
1 /opt/intel/mkl/lib/intel64/libmkl_rt.so 150 modo manual
2 /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3 35 modo manual
3 /usr/lib/x86_64-linux-gnu/blas/libblas.so.3 10 modo manual
4 /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3 40 modo manual
Pulse <Intro> para mantener el valor por omisión [*] o pulse un número de selección: 4
Enlazar LAPACK (si se emplea ATLAS o MKL):
sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu
Existen 4 opciones para la alternativa liblapack.so.3-x86_64-linux-gnu (que provee /usr/lib/x86_64-linux-gnu/liblapack.so.3).
Selección Ruta Prioridad Estado
------------------------------------------------------------
* 0 /opt/intel/mkl/lib/intel64/libmkl_rt.so 150 modo automático
1 /opt/intel/mkl/lib/intel64/libmkl_rt.so 150 modo manual
2 /usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3 35 modo manual
3 /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3 10 modo manual
4 /usr/lib/x86_64-linux-gnu/openblas/liblapack.so.3 40 modo manual
Pulse <Intro> para mantener el valor por omisión [*] o pulse un número de selección: 4
Para confirmar la selección, podemos ejecutar sessionInfo()
en R y nos mostrará algo de este estilo:
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
Matrix products: default
BLAS/LAPACK: /opt/intel/compilers_and_libraries_2020.0.166/linux/mkl/lib/intel64_lin/libmkl_rt.so
Si se emplean paquetes que se compilan con LAPACK (e.g. npsp
) habría que reinstalarlos si se cambia el enlace a las librerías BLAS/LAPACK.
Pendiente buscar referencia…
Se podrían seleccionar el número de núcleos/hilos como se describió aquí.
Instalación de RStudio Server
Descargar e instalar RStudio Server siguiendo los pasos en: Download RStudio Server for Debian & Ubuntu
sudo apt-get install gdebi-core
wget https://download2.rstudio.org/server/bionic/amd64/rstudio-server-1.4.1103-amd64.deb
sudo gdebi rstudio-server-1.4.1103-amd64.deb
Se recomienda crear un usuario:
sudo adduser rstudio
Para acceder (se solicitarán las credenciales):
http://<server-ip>:8787
Si aparecen problemas:
sudo rstudio-server verify-installation
Fuentes:
Problemas con RStudio Server
Desde RStudio solo se pudo ejecutar R-benchmark-25.R sin problemas con OpenBLAS (aunque al emplear la consola por SSH no hubo ningún problema con ninguna de las opciones).
ERROR: Al seleccionar MKL y testear con R-benchmark-25.R:
Error in solve(crossprod(a), crossprod(a, b)) :
the leading minor of order 1608 is not positive definite
Este tipo de errores pueden ser debidos a Open MP:
https://stat.ethz.ch/pipermail/r-sig-debian/2011-July/001638.html
pese a haber incluido MKL_THREADING_LAYER=GNU
en /etc/environment
para que MKL utilice la misma versión de R.
Este problema no apareció en la consola, pero pudo ser debido a que se inició una nueva conexión y se cargaron las variables de entorno? Pendiente volver a testear…
ERROR: Al seleccionar ATLAS y testear con R-benchmark-25.R, se queda colgado en:
Inverse of a 1600x1600 random matrix________________ (sec):
Instalación HPC compilando R desde el código fuente
Fuentes:
Benchmarking R
Fuentes:
Introducción al procesamiento en paralelo en R
En esta sección se pretenden mostrar las principales herramientas para el procesamiento en paralelo disponibles en R y dar una idea de su funcionamiento. Para más detalles se recomienda ver CRAN Task View: High-Performance and Parallel Computing with R (además de HPC, High Performance Computing, también incluye herramientas para computación distribuida)1.
Emplearemos la siguiente terminología:
Núcleo: término empleado para referirse a un procesador lógico de un equipo (un equipo puede tener un único procesador con múltiples núcleos que pueden realizar operaciones en paralelo). También podría referirse aquí a un equipo (nodo) de una red (clúster de equipos; en la práctica cada uno puede tener múltiples núcleos). Un núcleo puede ejecutar procesos en serie.
Clúster: colección de núcleos en un equipo o red de equipos. Un clúster puede ejecutar varios procesos en paralelo.
Por defecto la versión oficial de R emplea un único núcleo, aunque se puede configurar de forma que realice cálculos en paralelo (e.g. librería LAPACK).
Los métodos simples de paralelización2 disponibles en R son:
Forking: Copia el proceso de R a un nuevo núcleo (se comparte el entorno de trabajo). Es el más simple y eficiente pero no está disponible en Windows.
Socket: Lanza una nueva versión de R en cada núcleo, como si se tratase de un cluster de equipos comunicados a traves de red (hay que crear un entorno de trabajo en cada núcleo). Disponible en todos los sistemas operativos.
Paquetes de R
Hay varios paquetes que se pueden usar para el procesamiento paralelo en R, entre ellos podríamos destacar:
parallel
: forma parte de la instalación base de R y fusiona los paquetesmulticore
(forking) ysnow
(sockets; Simple Network of Workstations). Además incluye herramientas para la generación de números aleatorios en paralelo (cada proceso empleara una secuencia y los resultados serán reproducibles).Incluye versiones “paralelizadas” de la familia
*apply()
:mclapply()
(forking),parLapply()
(socket), …foreach
: permite realizar iteraciones y admite paralelización con el operador%dopar%
, aunque requiere paquetes adicionales comodoSNOW
odoParallel
(recomendado).rslurm
: permite la ejecución distribuida en clústeres Linux que implementen SLURM (Simple Linux Utility for Resource Management), un gestor de recursos de código abierto muy empleado.
Ejemplos
Si se emplea el paquete parallel
en sistemas tipo Unix (Linux, Mac OS X, …), se podría
evaluar en paralelo una función llamando directamente a mclapply()
.
Por defecto empleará todos los núcleos disponibles, pero se puede especificar un número menor
mediante el argumento mc.cores
.
library(parallel)
ncores <- detectCores()
ncores
func <- function(k) {
i_boot <- sample(nrow(iris), replace = TRUE)
lm(Petal.Width ~ Petal.Length, data = iris[i_boot, ])$coefficients
}
RNGkind("L'Ecuyer-CMRG") # Establecemos Pierre L'Ecuyer's RngStreams...
set.seed(1)
system.time(res.boot <- mclapply(1:100, func)) # En Windows llama a lapply() (mc.cores = 1)
# res.boot <- mclapply(1:100, func, mc.cores = ncores - 1) # En Windows genera un error si mc.cores > 1
En Windows habría que crear previamente un cluster, llamar a una de las funciones
par*apply()
y finalizar el cluster:
cl <- makeCluster(ncores - 1, type = "PSOCK")
clusterSetRNGStream(cl, 1) # Establecemos Pierre L'Ecuyer's RngStreams con semilla 1...
system.time(res.boot <- parSapply(cl, 1:100, func))
# stopCluster(cl)
str(res.boot)
Esto también se puede realizar en Linux (type = "FORK"
),
aunque podríamos estar trabajando ya en un cluster de equipos…
También podríamos emplear balance de carga si el tiempo de computación es variable
(e.g. parLapplyLB()
o clusterApplyLB()
) pero no sería recomendable si se emplean
números pseudo-aleatorios (los resultados no serían reproducibles).
Además, empleando las herramientas del paquete snow
se puede representar el uso
del cluster (experimental en Windows):
# library(snow)
ctime <- snow::snow.time(snow::parSapply(cl, 1:100, func))
ctime
plot(ctime)
Hay que tener en cuenta la sobrecarga adicional debida a la comunicación entre nodos al paralelizar (especialmente con el enfoque de socket).
La función boot::boot()
incluye parámetros para el procesamiento en paralelo:
parallel = c("no", "multicore", "snow")
, ncpus
, cl
.
Si parallel = "snow"
se crea un clúster en la máquina local durante la ejecución,
salvo que se establezca con el parámetro cl
.
Procesamiento en paralelo en R con GPUs
Esta sección está incompleta, en un primer intento no conseguí configurar R (era necesario que el administrador del sistema3 modificase la instalación), no tuve tiempo a volver a intentarlo. Incluyo las notas por si resultan de utilidad (avisadme si conseguís finalizar la configuración…).
La idea era emplear en R la librería NVBLAS disponible en equipos con GPUs de NVIDIA (no es necesario que sea un servidor con GPUs avanzadas) y configurar los paquetes de R que admiten procesamiento con GPUs.
Para verificar que está instalado el driver de NVIDIA, ejecutar:
nvidia-smi
y se obtendrá algo similar a esto:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.30 Driver Version: 430.30 CUDA Version: 10.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GRID P40-12Q On | 00000000:02:01.0 Off | 0 |
| N/A N/A P8 N/A / N/A | 784MiB / 11454MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
Adicionalmente se mostrará un cuadro con el uso de GPU.
Configurar R para emplear NVBLAS
The NVBLAS Library is a GPU-accelerated Libary that implements BLAS on top of the cuBLAS Library (using only the CUBLASXT API). Because NVBLAS does not support all standard BLAS routines, it might be necessary to associate it with an existing full BLAS Library.
Ubuntu/Debian installation of cuBLAS:
sudo apt-get install cublas
ERROR: No se ha podido localizar el paquete cublas
Install a full BLAS Library: OpenBLAS? MKL?
Add to you path?
export LD_LIBRARY_PATH=PATH_TO_CUBLAS/lib64:PATH_TO_SYSTEM_BLAS
NVBLAS must be configured through an ASCII text file, parsed at the time of the loading of the library. The location and name of the configuration file must be defined by the environment variable NVBLAS_CONFIG_FILE
(if it is not defined, it is assumed to be nvblas.conf in the current directory). The configuration file should have restricted write permissions.
The example below shows a typical NVBLAS configuration file:
# This is the configuration file to use NVBLAS Library
# Setup the environment variable NVBLAS_CONFIG_FILE to specify your own config file.
# By default, if NVBLAS_CONFIG_FILE is not defined,
# NVBLAS Library will try to open the file "nvblas.conf" in its current directory
# Example : NVBLAS_CONFIG_FILE /home/cuda_user/my_nvblas.conf
# The config file should have restricted write permissions accesses
# Specify which output log file (default is stderr)
NVBLAS_LOGFILE nvblas.log
# Enable trace log of every intercepted BLAS calls
NVBLAS_TRACE_LOG_ENABLED
#Put here the CPU BLAS fallback Library of your choice
#It is strongly advised to use full path to describe the location of the CPU Library
NVBLAS_CPU_BLAS_LIB /usr/lib/libopenblas.so
#NVBLAS_CPU_BLAS_LIB <mkl_path_installtion>/libmkl_rt.so
# List of GPU devices Id to participate to the computation
# Use ALL if you want all your GPUs to contribute
# Use ALL0, if you want all your GPUs of the same type as device 0 to contribute
# However, NVBLAS consider that all GPU have the same performance and PCI bandwidth
# By default if no GPU are listed, only device 0 will be used
#NVBLAS_GPU_LIST 0 2 4
#NVBLAS_GPU_LIST ALL
NVBLAS_GPU_LIST ALL0
# Tile Dimension
NVBLAS_TILE_DIM 2048
# Autopin Memory
NVBLAS_AUTOPIN_MEM_ENABLED
#List of BLAS routines that are prevented from running on GPU (use for debugging purpose
# The current list of BLAS routines supported by NVBLAS are
# GEMM, SYRK, HERK, TRSM, TRMM, SYMM, HEMM, SYR2K, HER2K
#NVBLAS_GPU_DISABLED_SGEMM
#NVBLAS_GPU_DISABLED_DGEMM
#NVBLAS_GPU_DISABLED_CGEMM
#NVBLAS_GPU_DISABLED_ZGEMM
# Computation can be optionally hybridized between CPU and GPU
# By default, GPU-supported BLAS routines are ran fully on GPU
# The option NVBLAS_CPU_RATIO_<BLAS_ROUTINE> give the ratio [0,1]
# of the amount of computation that should be done on CPU
# CAUTION : this option should be used wisely because it can actually
# significantly reduced the overall performance if too much work is given to CPU
#NVBLAS_CPU_RATIO_CGEMM 0.07
echo "NVBLAS_LOGFILE nvblas.log
NVBLAS_CPU_BLAS_LIB /usr/lib64/libopenblas.so
NVBLAS_GPU_LIST ALL" > /etc/nvblas.conf
nano /etc/nvblas.conf
Usage:
Unfortunately, it seems that R does not offer a way to specify multiple BLAS Libraries.
On Linux, an alternative way to use NVBLAS Library is to use the LD_PRELOAD environment variable; this technique has the advantage of avoiding the relinkage step. However, the user should avoid defining that environment variable globally because it will cause the NVBLAS library to be loaded by every shell command executed on the system, thus leading to a lack of responsiveness of the system.
export LD_PRELOAD=libnvblas.so
You can now run R on the command line with GPU-accelerated BLAS like this:
LD_PRELOAD=/usr/local/cuda-9.0/lib64/libnvblas.so NVBLAS_CONFIG_FILE=/etc/nvblas.conf R
Accelerated R with CUDA on Linux
Fuentes:
También puede ser de interés la presentación R y HPC (uso de R en el CESGA) de Aurelio Rodríguez en las VI Xornada de Usuarios de R en Galicia.↩︎
Realmente las herramientas estándar son OpenMP para el procesamiento en paralelo con memoria compartida en un único equipo y MPI para la computación distribuida en múltiples nodos.↩︎
En nuestro caso se emplearon máquinas virtuales (que nos proporciona el CITIC, https://citic.udc.es) en equipos con NVIDIA Tesla P40 24GB configuradas para trabajar con NVIDIA Grid.↩︎