Parallel R: Introduction

Goal: Introduction some high-level aspects of using R in parallel relating to the cluster.

In the same spirit as this is not a course on learning the R language, this is not a section on developing parallelized code with any of the 10s of parallel related packages.

Instead it will detail some aspects to consider regards using our cluster.



Parallel Programming with R

The are 10s of potential packages that could be used, as a starting point we’d direct your to here: CRAN Task View: High-Performance and Parallel Computing with R.

One thing to consider with respect to what package you wish to explore is whether it provides multi-node functionality (such as Rmpi) or just multicore (parallel) on a single compute node, and/or cluster features.

Remember: Just asking for multiple nodes (and GPUs) won’t actually make your code run faster unless the underlying package can actually utilize them.


R parallel Package: Overview

The parallel package is now part of the core R installation and is a base package.

It does not need to be installed.


Building Rmpi from Source

If you wish to try to install Rmpi, you should use the latest implementation of OpenMPI on the cluster to build against.


Multicore: Detecting Cores

Typically, using parallel::detectCores() to detect the number of available cores on a cluster node is a slight red herring. This returns the entire total number of cores of the node your job is allocated and not the actual number of cores you requested/allocated.

For example, if you're sbatch script defines the following,

#SBATCH --nodes=1 #SBATCH --cpus-per-task=8

and you're allocated a standard compute node that has 32 cores, parallel::detectCores() will return a value of 32 and not 8 which is what you requested!
This will probably lead to unexpected results/failures when you try and run a function expecting 32 cores when only 8 are actually available.
To remove this problem you can use, and need to pass into your R script, the value of the $SLURM_JOB_CPUS_PER_NODE slurm environment variable.


Detect Cores Example

args <- commandArgs(trailingOnly = TRUE) if (!is.na(args[1])) { num_of_cores <- args[1] print(paste0("Num of Cores: ", num_of_cores)) } print(paste0("detectCores: ", parallel::detectCores())) options(mc.cores = num_of_cores) print(paste0("mc.cores: ", getOption("mc.cores", 1L)))
# Create an interactive session that uses 8 cores: []$ salloc -A arcc -t 10:00 -c 8 salloc: Granted job allocation 861904 salloc: Nodes mbcpu-001 are ready for job [@mbcpu-001 ~]$ module load gcc/13.2.0 r/4.4.0 # Check the slurm environment variable: SLURM_JOB_CPUS_PER_NODE [@mbcpu-001 ~]$ echo $SLURM_JOB_CPUS_PER_NODE 8 # What does R detect? [@mbcpu-001 ~]$ Rscript r_multicore.R $SLURM_JOB_CPUS_PER_NODE [1] "Num of Cores: 8" [1] "detectCores: 96" [1] "mc.cores: 8"