R Language

GraalVM implementation of R is compatible with GNU R, can run R code at unparalleled performance, integrates with the GraalVM ecosystem and provides additional R level features.

Installing

The R language can be installed to a GraalVM build with the gu command. See graalvm/bin/gu --help for more information.

Running R Code

Run R code with the R and Rscript commands:

$ R [polyglot options] [R options] [filename]
$ Rscript [polyglot options] [R options] [filename]

FastR uses the same polyglot options as other GraalVM languages and the same R options as GNU R, e.g., bin/R --vanilla. Use --help to print the list of supported options. The most important options include:

  • --jvm to enable Java interoperability
  • --polyglot to enable interoperability with other GraalVM languages
  • --jvm.Djava.net.useSystemProxies=true to pass any options to the JVM, this will be translated to -Djava.net.useSystemProxies=true.

Note: unlike other GraalVM languages, FastR does not yet ship with a native image of its runtime. Therefore the --native option, which is the default, will still start FastR on top of JVM, but for the sake of Java interoperability will not be available in such case. In future versions, FastR may ship with a native image and --native will run it.

Requirements

FastR requires the OpenMP runtime library be installed on the target system. Moreover, to install R packages that contain C/C++ or Fortran code, compilers for those languages must be present on the target system. Note that all these requirements can be satisfied by, e.g., installing the GNU Compiler Collection (GCC).

R Compatibility

GraalVM implementation of R is based on GNU R and reuses the base packages. It is currently based on R 3.4.0, and moves to new major versions of R as they become available and stable. The FastR project maintains an extensive set of unit tests for all aspects of the R language and the builtin functionality, and these tests are available as part of the FastR source code. FastR aims to be fully compatible with GNU R, including its native interface as used by R packages. It can install and run unmodified complex R packages like ggplot2, Shiny, or Rcpp. As some packages rely on unspecified behavior or implementation details of GNU R, support for packages is work in progress, and some packages might not install successfully or work as expected.

Packages can be installed using the install.packages function or the R CMD INSTALL shell command. By default, FastR uses fixed snapshot of the CRAN repository1 that is updated with every new release of FastR (once a month). This behavior can be overrideen by explicitly setting the repos argument of the install.packages function. This functionality does not interfere with the checkpoint package. If you are behind a proxy server, make sure to configure the proxy using, e.g., --jvm.Djava.net.useSystemProxies=true.

Known limitations of FastR compared to GNU R:

  • Only small parts of the low-level graphics package are functional. However, the grid package is supported and FastR can install and run packages based on it like ggplot2. Support for the graphics package in FastR is planned for future releases.
  • Encoding of character vectors. Related builtins (e.g., Encoding) are available, but do not execute any useful code. Character vectors are represented as Java Strings and therefore encoded in UTF-16 format. FastR will add support for encoding in future releases.
  • Some parts of the native API (e.g., DATAPTR) expose implementation details that are hard to emulate for alternative implementations of R. These are implemented as needed while testing FastR with various CRAN packages.

You can use the compatibility checker to find whether the CRAN packages you’re interested in are tested on GraalVM and whether the tests pass successfully.

High Performance

FastR uses the GraalVM runtime to optimize and compile R code that runs for extended periods of time. The speculative optimizations based on the runtime behavior of the R code and dynamic compilation employed by GraalVM runtime are capable of removing most of the abstraction penalty incurred by the dynamism and complexity of the R language.

Let’s look at an algorithm in R code. The following example calculates the mutual information of a large matrix:

x <- matrix(runif(1000000), 1000, 1000)
mutual_R <- function(joint_dist) {
 joint_dist <- joint_dist/sum(joint_dist)
 mutual_information <- 0
 num_rows <- nrow(joint_dist)
 num_cols <- ncol(joint_dist)
 colsums <- colSums(joint_dist)
 rowsums <- rowSums(joint_dist)
 for(i in seq_along(1:num_rows)){
  for(j in seq_along(1:num_cols)){
   temp <- log((joint_dist[i,j]/(colsums[j]*rowsums[i])))
   if(!is.finite(temp)){
    temp = 0
   }
   mutual_information <-
    mutual_information + joint_dist[i,j] * temp
  }
 }
 mutual_information
}
system.time(mutual_R(x))
#   user  system elapsed
#  1.321   0.010   1.279

Algorithms such as this one usually require C/C++ code to run efficiently:2

if (!require('RcppArmadillo')) {
    install.packages('RcppArmadillo')
    library(RcppArmadillo)
}
library(Rcpp)
sourceCpp("r_mutual.cpp")
x <- matrix(runif(1000000), 1000, 1000)
system.time(mutual_cpp(x))
#   user  system elapsed
#  0.046   0.003   0.051

(Uses r_mutual.cpp.) However, after a few iterations, FastR runs the R code efficiently enough to make the performance advantage of C/C++ negligible:

system.time(mutual_R(x))
#   user  system elapsed
#  0.063   0.001   0.077

FastR is primarily aimed at long-running applications. Therefore, peak performance is usually only achieved after a warmup period. While startup time is currently slower than GNUR’s, due to the overhead from Java class loading and compilation, future releases will contain a native image of FastR with improved startup.

GraalVM Integration

FastR’s integration with the GraalVM ecosystem includes:

To start debugging R code start FastR with --inspect option

$ Rscript --inspect myScript.R

Note that GNU R compatible debugging using, for example, debug(myFunction) is also supported.

Interoperability

GraalVM supports several other programming languages, including JavaScript, Ruby, Python 3, and LLVM. While FastR is designed to run R code, it also provides an API for programming language interoperability that lets you execute code from any other language that GraalVM supports. Note that you must start FastR with --polyglot to have access to other GraalVM languages.

FastR provides the following interoperability primitives:

  • eval.polyglot('languageId', 'code') evaluates code in some other language, the languageId can be, e.g., js.
  • eval.polyglot(path = '/path/to/file.extension') evaluates code loaded from a file. The language is recognized from the extension.
  • export('polyglot-value-name', rObject) exports an R object so that it can be imported by other languages.
  • import('exported-polyglot-value-name') imports a polyglot value exported by some other language.

Please use the ?functionName syntax to learn more. Following example demonstrates the interoperability features:

# get an array from Ruby
x <- eval.polyglot('ruby', '[1,2,3]')
print(x[[1]])
# [1] 1

# get a JavaScript object
x <- eval.polyglot(path='r_example.js')
print(x$a)
# [1] "value"

# use R vector in JavaScript
export('robj', c(1,2,3))
eval.polyglot('js', paste0(
    'rvalue = Polyglot.import("robj"); ',
    'console.log("JavaScript: " + rvalue.length);'))
# JavaScript: 3
# NULL -- the return value of eval.polyglot

(Uses r_example.js.)

See the Polyglot Reference and the Embedding documentation for more information about interoperability with other programming languages.

Interoperability with Java

FastR provides built-in interoperability with Java. Java class objects can be obtained via java.type(...). The standard new function interprets string arguments as a Java class if such class exists. new also accepts Java types returned from java.type. Fields and methods of Java objects can be accessed using the $ operator. Additionally, you can use awt(...) to open an R drawing device directly on a Java Graphics surface, for more details see Java Based Graphics.

The following example creates a new Java BufferedImage object, plots random data to it using R’s grid package, and shows the image in a window using Java’s AWT framework. Note that you must start FastR with --jvm to have access to Java interoperability.

library(grid)
openJavaWindow <- function () {
   # create image and register graphics
   imageClass <- java.type('java.awt.image.BufferedImage')
   image <- new(imageClass, 450, 450, imageClass$TYPE_INT_RGB);
   graphics <- image$getGraphics()
   graphics$setBackground(java.type('java.awt.Color')$white);
   grDevices:::awt(image$getWidth(), image$getHeight(), graphics)

   # draw image
   grid.newpage()
   pushViewport(plotViewport(margins = c(5.1, 4.1, 4.1, 2.1)))
   grid.xaxis(); grid.yaxis()
   grid.points(x = runif(10, 0, 1), y = runif(10, 0, 1),
        size = unit(0.01, "npc"))

   # open frame with image
   imageIcon <- new("javax.swing.ImageIcon", image)
   label <- new("javax.swing.JLabel", imageIcon)
   panel <- new("javax.swing.JPanel")
   panel$add(label)
   frame <- new("javax.swing.JFrame")
   frame$setMinimumSize(new("java.awt.Dimension",
                image$getWidth(), image$getHeight()))
   frame$add(panel)
   frame$setVisible(T)
   while (frame$isVisible()) Sys.sleep(1)
}
openJavaWindow()

FastR provides its own rJava compatible replacement package available at GitHub, which can be installed using:

$ R --jvm CMD INSTALL /path/to/fastr/com.oracle.truffle.r.pkgs/rJava

R Additional Features

Java Based Graphics

FastR includes its own Java based implementation of the grid package and the following graphics devices: png, jpeg, bmp, svg and awt (X11 is aliased to awt). The graphics package and most of its functions are not supported at the moment.

The awt device is based on the Java Graphics2D object and users can pass it their own Graphics2D object instance when opening the device using the awt function, as shown in the Java interop example. When the Graphics2D object is not provided to awt, it opens a new window similarly to X11.

The svg device in FastR generates more lightweight SVG code than the svg implementation in GNU R. Moreover, FastR provides functions tailored to manipulate the SVG device: svg.off and svg.string. The SVG device is demonstrated in the following code sample. Please use the ?functionName syntax to learn more.

library(lattice)
svg()
mtcars$cars <- rownames(mtcars)
print(barchart(cars~mpg, data=mtcars))
svgCode <- svg.off()
cat(svgCode)
In-Process Parallel Execution

FastR adds a new cluster type SHARED for the parallel package. This cluster starts new jobs as new threads inside the same process. Example:

library(parallel)
cl0 <- makeCluster(7, 'SHARED')
clusterApply(cl0, seq_along(cl0), function(i) i)




1 More technically, FastR uses a fixed MRAN URL from $R_HOME/etc/DEFAULT_CRAN_MIRROR, which is a snapshot of the CRAN repository as it was visible at a given date from the URL string.

2 When this example is run for the first time, it installs the RcppArmadillo package, which may take few minutes. Note that this example can be run in both FastR and GNU R.