You are here

R

R is a language and environment for statistical computing and graphics. It is a GNU project which provides a wide variety of statistical (linear and nonlinear modelling, classical statistical tests, time-series analysis, classification, clustering, ...) and graphical techniques, and is highly extensible.

R has been installed on a variety of WestGrid systems (even though the example below is for Bugaboo).  See the Software Versions tab for a complete list.

Running R on Bugaboo

Submitting R Jobs

This section was written with Bugaboo in mind, but, most of the material applies to other installations of R. Like other jobs on WestGrid systems, R jobs are run by submitting an appropriate script for batch scheduling using the qsub command. See documentation on running batch jobs for more information.

Running a Serial R Job

Any submission script for a serial program can be used with R. For example:

#!/bin/bash 
#PBS -r n 
#PBS -m bea 
#PBS -M jsbach@nowhere.ca 
#PBS -l walltime=24:00:00 
#PBS -l procs=1
#PBS -l pmem=2000mb

# Adjust the resource parameters (walltime and mem or pmem) according to your needs.
# Leave procs=1 for a serial (non-parallel) R calculation.

echo "Running on host `hostname`"

cd $PBS_O_WORKDIR
echo "Working directory is `pwd`"

# Use a module command or absolute path if necessary to specify the particular version of R to use.

echo "Using R: `which R`"

echo "Starting R at `date`."
R --vanilla < myRscript.R
echo "Finished R at `date`."

will do for a small memory job on most WestGrid systems.

Using Rmpi for Parallel Jobs

Things get more complicated, if you want to use the Rmpi package. As with any other serial program you cannot simply do

#PBS -l procs=42 
mpiexec serial_prog

and expect that the program will run in parallel using 42 processors. Instead you need to change serial_prog into a parallel program that calls MPI functions to spread the load between the processors. R is not different in this aspect.

Thus, in order to run R in parallel you need to do at least two things:

  1. Load the Rmpi package;
  2. Use functions from the Rmpi package to distribute the workload between processors.

Rmpi contains functions that implement a master-slave algorithm:

  • Initially only the master process is started
  • Then the master process spawns the slaves handing out different tasks to each of the slaves
  • At the end the master closes down the slaves
  • And then finishes itself

Here is a submission script that uses this schema

#!/bin/bash 
#PBS -N Rmpi-hello 
#PBS -l walltime=10:00 
#PBS -l procs=10 
cd $PBS_O_WORKDIR 
mpiexec -n 1 R --vanilla < Rmpi-hello.R

Please note that on Glacier you should replace mpiexec with /global/software/bin/mpiexec in the above script.

This script requests 10 processors, but the mpiexec command only starts a single process (-n 1): the master process. The Rmpi-hello.R takes care of spawning the slaves. Here is the Rmpi-hello.R example script:

# Load the R MPI package if it is not already loaded. 
if (!is.loaded("mpi_initialize")) { 
library("Rmpi") 


library(rsprng)

# In case R exits unexpectedly, have it automatically clean up 
# resources taken up by Rmpi (slaves, memory, etc...) .

Last <- function(){ 
if (is.loaded("mpi_initialize")){ 
if (mpi.comm.size(1) > 0){ 
print("Please use mpi.close.Rslaves() to close slaves.") 
mpi.close.Rslaves() 

print("Please use mpi.quit() to quit R") 
.Call("mpi_finalize") 


# Spawn as many slaves as possible 
mpi.spawn.Rslaves() 
# Tell all slaves to return a message identifying themselves
mpi.remote.exec(paste("I am",mpi.comm.rank(),"of",mpi.comm.size())) 
# Tell all slaves to close down, and exit the program 
mpi.close.Rslaves() 
mpi.quit()

All the mpi.xxxx functions are defined in the Rmpi package. Sample code of this parallel R program is the single line:

mpi.remote.exec(paste("I am",mpi.comm.rank(),"of",mpi.comm.size()))

which prints lines like "I am 7 of 11" to the output file. Thus, your own program must have the following structure:

# Load the R MPI package if it is not already loaded. 
if (!is.loaded("mpi_initialize")) { 
library("Rmpi") 

# load all packages that are needed 
library(xyz)

# In case R exits unexpectedly, have it automatically clean up 
# resources taken up by Rmpi (slaves, memory, etc...) 
.Last <- function(){ 
if (is.loaded("mpi_initialize")){ 
if (mpi.comm.size(1) > 0){ 
print("Please use mpi.close.Rslaves() to close slaves.") 
mpi.close.Rslaves() 

print("Please use mpi.quit() to quit R") 
.Call("mpi_finalize") 


# Spawn as many slaves as possible 
mpi.spawn.Rslaves()

<insert own R MPI program code here>

# Tell all slaves to close down, and exit the program 
mpi.close.Rslaves() 
mpi.quit()

You have to provide everything that replaces <insert own R MPI program code here>  in the above.

A few remarks:

In the output you see lines like

I am 4 of 11

That is, it says "of 11" not "of 10" even though I requested only 10 processors in the R submission script. The reason for that is that the function mpi.spawn.Rslaves() spawns as many slaves as were requested by the submission script. Since the master process was started already you end up with 11 = 10 + 1 processes. This is ok as long as the master process does nothing more than spawning the slaves and all the work is done by the slaves. However, if you program is such that the master process itself does significant amounts of computing you must start only N-1 slaves. In that case use

Nprocs <- mpi.universe.size()
mpi.spawn.Rslaves(nslaves=Nprocs-1)

It is strongly suggested to experiment first before running a fullblown Rmpi calculation that is difficult to debug:

  1. Run your serial R program first before even attempting to use Rmpi. 
    Debug the serial R program until it runs without problems.
  2. Come up with a scheme of how to distribute work between slaves.
  3. Implement that scheme using Rmpi.
  4. Test the Rmpi program using only a small number of processors.
  5. Try using as many processors as appear to be reasonable.

 

For More Information

2016-05-05 - Added informational echo commands to the simple R script example and deleted the section on running R on Glacier.