Directions in Statistical Computing 2014 Renjin's JIT Thinking - - PowerPoint PPT Presentation

directions in statistical computing 2014 renjin s jit
SMART_READER_LITE
LIVE PREVIEW

Directions in Statistical Computing 2014 Renjin's JIT Thinking - - PowerPoint PPT Presentation

Directions in Statistical Computing 2014 Renjin's JIT Thinking about R as a Query Language Alexander Bertram BeDataDriven 2014 1 Quick Intro: Renjin R-language Interpreter written in Java, uses GNU R core packages (base, stats, etc)


slide-1
SLIDE 1

2014 1

Directions in Statistical Computing 2014 Renjin's JIT

Thinking about R as a Query Language Alexander Bertram BeDataDriven

slide-2
SLIDE 2

2014 2

Quick Intro: Renjin

  • R-language Interpreter written in Java, uses

GNU R core packages (base, stats, etc) as-is

  • Goals: Completeness first, performance next
  • C/Fortran: Supported with translator and

emulation layer

  • Can run roughly ~50% of CRAN packages

(see packages.renjin.org)

  • Actively user group, diverse
slide-3
SLIDE 3

2014 3

R as a “Query Language”

How can R be as fast as Fortran or C++ ? How can R be more like SQL?

– Analyst describes the what – Query planner determines the how

  • Implicit parallelism
  • Target diverse architechture (in-memory, single node,

clusters)

slide-4
SLIDE 4

2014 4

Is R dynamic? Argument: Not where/when performance matters

slide-5
SLIDE 5

2014 5

“But R is too dynamic!”

airlines <- read.bigtable(“airlines”) print(nrow(airlines)) # ~240m fit.exp <- function(x, max.iter = 10 ) { rate <- 1 / mean(x) repeat { loglik <- sum(-dexp(r = rate, x = lambda, log = T) if( goodEnough(loglik) ) break rate <- next } } Is the break() function redefined? Complicated Argument Matching sum() is group generic, dispatches based

  • n argument
slide-6
SLIDE 6

2014 6

airlines <- read.bigtable(“airlines”) delay <- airlines$delay[airlines$delay > 30] dexp <- function(x, rate=1, log = FALSE) { mean <- 1/rate d <- exp(-x / mean) / mean if(log) return(log(d)) d } fit.exp <- function(x, max.iter = 10 ) { rate <- 1 / mean(x) repeat { loglik <- sum(-dexp(r = rate, x, log = T) if( logLik > epsilon ) break rate <- update(rate) } } rate <- fit.exp

slide-7
SLIDE 7

2014 7

Real world example: Distance Correlation [ see energy package]

slide-8
SLIDE 8

2014 8

slide-9
SLIDE 9

2014 9

Optimizations: Views

x <- dist(x) y <- dist(y) x <- as.matrix(x) y <- as.matrix(y) # GNU R: x^2 + y^2 memory alloc'd # Renjin: ~ 0

slide-10
SLIDE 10

2014 10

DistanceMatrix

public class DistanceMatrix extends DoubleVector { private Vector vector; public double getElementAsDouble(int index) { int size = vector.length(); int row = index % size; int col = index / size; if(row == col) { return 0; } else { double x = vector.getElementAsDouble(row); double y = vector.getElementAsDouble(col); return Math.abs(x - y); } } public int length() { return vector.length() * vector.length(); } }

slide-11
SLIDE 11

2014 11

Deferred Evalution

  • Defer computation of pure functions when

inputs exceed some threshold:

x <- (1:100) + 4 # x is computed y <- (1:e^6) + 4 # no work done # x is a view z <- y – mean(z) z <- dnorm(z) print(z) # triggers evaluation

slide-12
SLIDE 12

2014 12

slide-13
SLIDE 13

2014 13

Query Planner

  • Once evaluation is triggered: we have a better

broad view of the calcuation to be completed

  • Computation Graph is essentially a pure

function

  • We can reorder operations, and easily see

which branches can be evaluated independently, in parallel

slide-14
SLIDE 14

2014 14

slide-15
SLIDE 15

2014 15

Loop Fusion

mean(op1(op2(op3(x)))

transformed to...

double sum = 0; for(int i..1000) { sum += op1(op2(op3)) }

slide-16
SLIDE 16

2014 16

Beyond Bytecode

JVM Byte Code → Native Machine Code JVM Byte Code → Native Machine Code SQL Query OpenCL

slide-17
SLIDE 17

2014 17

Results

slide-18
SLIDE 18

2014 18

slide-19
SLIDE 19

2014 19

Loops!

m <- 4 for (i in 1:m) { x = exp (tanh (a^2 * (b^2 + i/m))) r[i%%10+1] = r[i%%10+1] + sum(x) }

Kaboom!

(thanks Radford!)

slide-20
SLIDE 20

2014 20

Loops!

  • R gives you the flexibility to mix imperative with functional

approaches

  • In many dynamic languages (JS, Ruby), sophisticated runtime

analysis is required to identify and compile hotspots in the code.

  • In R, they're pretty easy to spot:

x <- 1:1e6 for(i in seq_along(x)) { ... }

slide-21
SLIDE 21

2014 21

for (i in 1:m) { x = exp (tanh (a^2 * (b^2 + i/m))) r[i%%10+1] = r[i%%10+1] + sum(x) }

BB1: τ ← (: 1.0d m ) ₃ ₀ Λ0 ← 0 ₁ τ ← length(τ ) ₂ ₃ BB2: [L0] r ← Φ(r , r ) ₁ ₀ ₂ Λ0 ← Φ(Λ0 , Λ0 ) ₂ ₁ ₃ i ← Φ(i , i ) ₁ ₀ ₂ x ← Φ(x , x ) ₁ ₀ ₂ if Λ0 >= τ => TRUE:L3, ₂ ₂ FALSE:L1, NA:ERROR BB3: [L1] i ← τ [Λ0 ] ₂ ₃ ₂ τ ← (^ a 2.0d) ₄ ₀ τ ← (^ b 2.0d) ₅ ₀ τ ← (/ i m ) ₆ ₂ ₀ τ ← (+ τ τ ) ₇ ₅ ₆ τ ← (* τ τ ) ₈ ₄ ₇ τ ← (tanh τ ) ₉ ₈ x ← (exp τ ) ₂ ₉ τ ← (%% i 10.0d) ₁₀ ₂ τ ← (+ τ 1.0d) ₁₁ ₁₀ τ ← ([ r τ ) ₁₂ ₁ ₁₁ τ ← (sum x ) ₁₃ ₂ τ ← (%% i 10.0d) ₁₄ ₂ τ ← (+ τ 1.0d) ₁₅ ₁₄ τ ← (%% i 10.0d) ₁₆ ₂ τ ← (+ τ 1.0d) ₁₇ ₁₆ r ← ([<- r τ ) ₂ ₁ ₁₇ BB4: [L2] Λ0 ← increment counter Λ0 ₃ ₂ goto L0 BB5: [L3] return NULL

slide-22
SLIDE 22

2014 22

Compared to other dynamic languages?

  • Argument: Speculative specialization works

very well for long-running code, but unnecessary for most statistical code with many loops:

– Simulations – Iterative algorithms – ?

  • Needs to be tested...
slide-23
SLIDE 23

2014 23

packages.renjin.org

slide-24
SLIDE 24

2014 24

Developing CI + benchmarking system for testing optimizations

slide-25
SLIDE 25

2014 25

More Information

  • http://www.renjin.org
  • http://packages.renjin.org
  • http://docs.renjin.org/en/latest/