117
Over 9000 JRuby in 2015

Over 9000: JRuby in 2015

Embed Size (px)

Citation preview

Page 1: Over 9000: JRuby in 2015

Over 9000JRuby in 2015

Page 2: Over 9000: JRuby in 2015

Me

• Charles Oliver Nutter

[email protected]

• @headius

• Red Hat

Page 3: Over 9000: JRuby in 2015
Page 4: Over 9000: JRuby in 2015

Ruby on the JVM

JVM SUCKS R

OFLAbstractMetaRubyImplementationFactoryFactoryImpl

I don't like Java so I don't like JRuby

LOL applet

s

Page 5: Over 9000: JRuby in 2015

JRuby is Ruby! on the JVM... shhh!

Page 6: Over 9000: JRuby in 2015

Stable: 1.7.19

• Ruby 1.8 and 1.9 support

• AST interpreter and JVM bytecode JIT

• Easy integration with JVM libraries

• No support for MRI C ext

Page 7: Over 9000: JRuby in 2015

Oldest alternative Ruby…around for 4-5 years before any others.

Page 8: Over 9000: JRuby in 2015

Aaron PattersonAditya BhardwajAkinori MUSHA

Alan MooreAlex Coles

Alex DowadAlex Tambellini

Aliaksei PalkanauAman Gupta

Anders BengtssonAndreas WoessAndrew GrimmAndrew KiellorAndy LindemanAnil WadghuleAnoop Sankar

Anthony W. JuckelAntoine ToulmeArne HormannArun AgrawalAslak Hellesøy

Atsuhiko YamanakaBen BrowningBenoit CerrinaBenoit Daloze

Bernerd SchaeferBernhard Urban

Bill DortchBob Beaty

Bob McWhirterBob Potter

Bohuslav KabrdaBrad Heller

BrandurBrian BrowningBrice FigureauBruce Adams

Bruno OliveiraChad Fowler

Charles Oliver NutterCharlie Somerville

Chris AndrewsChris Heald

Chris Jester-YoungChris Price

Chris SeatonChris SinjakliChris White

ChristianChristian Meier

Christoffer Sawicki

Clayton O'NeillClayton Wheeler

Colin JonesConrad IrwinDaniel AzumaDaniel Hahn

Daniel LucraftDaniel Luz

Daniel MarcotteDaniel Noll

Daniel PittmanDario BertiniDave Thomas

David CalaveraDavid CorbinDavid GraysonDavid HudsonDavid Kellum

David MasoverDavid Pollak

Deepak GiridharagopalDennis Ranke

Dmitry RatnikovDon Schwartz

Douglas CamposDwayne Litzenberger

Ed SinjiashviliEdward AndersonEric Sendelbach

Erik Michaels-OberFrederic Jean

Garrett ConatyGerard FowleyGino LuceroGreg Mefford

Gustav MunkbyGustavo Frederico

Temple PedrosaHeiko W. Rupp

Hiro AsariHironobu Nishikokura

Hiroshi NakamuraHongli Lai (Phusion)

Iain BarnettIan Dees

Isaiah PengJacob Evans

Jake GouldingJames Abley

James PickeringJan Arne Petersen

Jan GraichenJan Xie

Jason KarnsJason StatenJason Voegele

JavierJay

Jeff PaceJeff SimpsonJeff Stone

Jeremy EvansJez Ng

JoeJoe KutnerJoey Gibson

John CroisantJohn F. DouthatJohn Firebaugh

John ShahidJon Zeppieri

Jonathan AdamsJordan SisselJose RiveraJosef Haider

Joseph LaFataJosh Ballanco

Josh MatthewsJoshua Go

Juergen HerzogKamil BednarzKarol Bucek

Kenichi KamiyaKetan Padegaonkar

Kevin MenardKohsuke Kawaguchi

Koichiro OhbaKonstantin Haase

Kouhei SutouKristian MeierKubo Takehiro

Kyrylo SilinLars Westergren

Lelon StoldtLeonardo Borges

Lin Jen-ShinLoren SegalLuca Simone

Lucas Allan AmorimMalte Swart

ManishMarcin Mielzynski

Marcin MielżyńskiMark McCraw

Mark RadaMark Triggs

Mark WarrenMartin Harriman

Martin OttMartin TraversoMateusz Lenik

Matjaz GregoricMatt HauckMatt WilburMatt Wilson

Matthew DennerMatthew Kerwin

Matthias GrimmerMaximilian Konzack

MenTaLguYMicah Martin

Michael J. CohenMichael KlishinMichael KohlMichal Papis

Mike DalessioNAKAMURANARUSE, Yui

Naoto "Kevin" IMAI TOYODA

Nicholas JeffersonNick HowardNick Klauer

Nick Klauer (a03182)Nick Muerdter

Nick SiegerOla Bini

Ole Christian RynningOlov LassusOri KremerPablo Varela

Patrick MahoneyPatrick PlenefischPatrick Toomey

Paul BrownPaul MucurPaul Phillips

Pekka EnbergPeter Suschlik

Peter VandenabeelePhil Smith

Philip JenveyPierre-Yves Ritschard

Pierrick RouxelPrathamesh Sonpatki

Rajarshi DasRhett SutphinRick Ohnemus

Riley LynchRobert GlaserRobin DupretRobin Message

Rohit ArondekarRon Dahlgren

Ryan BlueRyan BrownRyan Fowler

Sakumatti LuukkonenSamu VoutilainenSatoru Chinen

Scott BlumScott Clasen

Seamus AbshereSebastian Staudt

Sebastien Le CallonnecSeth WrightShugo Maeda

Smit ShahStefan Huber

Stefan Matthias AustStephen Bannasch

Steven CookSteven Parkes

Subramanya SastrySyver Enstad

Sébastien Le CallonnecTed Pennings

TeemuTheo

Theo HultbergThomas E EneboThomas E. EneboThomas Enebo

Thomas WuerthingerTim FelgentreffTobi VollebregtTobias Crawley

Travis TilleyTristan Hill

UnbitUwe Kubosch

Vipul A MVishnu GopalVitor de Lima

Vladimir SizikovVít Ondruch

Wayne MeissnerWilliam Thurston

Xavier ShayXb

Yoko HaradaYosuke

Zach Ankeramuinoaremanarkxudonv

elcuboeneboeregongeemus

hmalphettesjamesjc00ke

john muhljonforums

josedonizettikareskiichi

kristianlfstad-brenmkristianmohamedpeter royalqbproger

rdpretnuh

rogerdpackrohit

ryenussglee77

simonjsmithuktakerutduehr

the8472thedarkone

timfeltnarik

uid41545unknown

waynewilliamd

wpcyousukezszugyi

Page 9: Over 9000: JRuby in 2015
Page 10: Over 9000: JRuby in 2015

But why?

Page 11: Over 9000: JRuby in 2015

Ruby is not perfect.

Page 12: Over 9000: JRuby in 2015

Sometimes, Ruby is the wrong tool.

Page 13: Over 9000: JRuby in 2015

We can make Ruby the right tool for more jobs.

Page 14: Over 9000: JRuby in 2015
Page 15: Over 9000: JRuby in 2015

Preview: JRuby 9000

• Ruby 2.2 compatible

• New optimizing runtime and compiler

• Reworked IO, Process, encoding, and more

• JRuby 9.0.0.0.pre1 is already out there!

Page 16: Over 9000: JRuby in 2015

Challenges

• Concurrency

• Language and Libraries

• Straight-line Performance

• Garbage Collection

• Tooling

Page 17: Over 9000: JRuby in 2015

Concurrency

Page 18: Over 9000: JRuby in 2015

True Parallellism

Ruby Threads

NativeThreads

Ruby 1.8.7 Ruby 2.0.0

Green Threading

CPU Coresin Use

JRuby

Global LockSingle Thread Real Threading

Page 19: Over 9000: JRuby in 2015

Multicore in MRI

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

Ten-way concurrency * 200MB = 2GB

Page 20: Over 9000: JRuby in 2015

Multicore in MRI

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

100-way concurrency * 200MB = 20GB

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

200MB MRI Instance

Page 21: Over 9000: JRuby in 2015

Multicore in JRuby

300MB JRuby Instance

One instance across 10 threads = 300MB

Page 22: Over 9000: JRuby in 2015

Multicore in JRuby

300MB JRuby Instance

One instance across 100 threads = 300MB

Page 23: Over 9000: JRuby in 2015

MRI 1.9.3+, Eight Threads

Page 24: Over 9000: JRuby in 2015

JRuby, Eight Threads

Page 25: Over 9000: JRuby in 2015

Presentation:Bringing Concurrency

to Ruby

Page 26: Over 9000: JRuby in 2015

Concurrency Futures

Page 27: Over 9000: JRuby in 2015

Education

Page 28: Over 9000: JRuby in 2015

concurrent-ruby

Page 29: Over 9000: JRuby in 2015

Work with ruby-core on concurrency

primitives

Page 30: Over 9000: JRuby in 2015

Mutation testing and monitoring

Page 31: Over 9000: JRuby in 2015

Object ownership and explicit transfer

Page 32: Over 9000: JRuby in 2015

Language and Libraries

Page 33: Over 9000: JRuby in 2015

In MRI, two choices

Page 34: Over 9000: JRuby in 2015

Ruby

Page 35: Over 9000: JRuby in 2015

C

Page 36: Over 9000: JRuby in 2015

In JRuby, you can use…

Page 37: Over 9000: JRuby in 2015

Ruby

Page 38: Over 9000: JRuby in 2015

Java

Page 39: Over 9000: JRuby in 2015

Scala

Page 40: Over 9000: JRuby in 2015

Clojure

Page 41: Over 9000: JRuby in 2015

Javascript

Page 42: Over 9000: JRuby in 2015

Micro FocusVisual Cobol

Page 43: Over 9000: JRuby in 2015

And dozens of others

Page 44: Over 9000: JRuby in 2015

And any language callable with FFI

Page 45: Over 9000: JRuby in 2015

JRuby 1.6 C Exts

• Limited support (now disabled)

• Removed to a separate repo

• If you want it, support it

• Some stuff worked...most didn’t

Page 46: Over 9000: JRuby in 2015

Problems

• Performance

• Data copying to emulate raw structs

• Locking to keep C code thread-safe

• Multiple JRuby instances in one JVM

• No way from C to know which one

• Huge API to support

Page 47: Over 9000: JRuby in 2015

Alternatives

Page 48: Over 9000: JRuby in 2015

Java Integration

• Call Java (Scala, Clojure, ...) from Ruby

• Smart mapping of method names

• Type conversions as appropriate

• Super easy and fun

Page 49: Over 9000: JRuby in 2015

import javax.swing.JFrameimport javax.swing.JLable

frame = JFrame.new("Window")label = JLabel.new("Hello")

frame.add(label)frame.default_close_operation = JFrame::EXIT_ON_CLOSEframe.packframe.visible = true

Page 50: Over 9000: JRuby in 2015

Java Native Extensions

• Similar to C ext for MRI, but with Java

• Fast call protocol...basically free

• Same GC for all objects

• Have to keep in sync if C version too

Page 51: Over 9000: JRuby in 2015

@JRubyMethodpublic IRubyObject each(ThreadContext context, Block block) { if (!block.isGiven()) { return enumeratorizeWithSize(context, this, "each", enumLengthFn()); } for (int i = 0; i < realLength; i++) { block.yield(context, safeArrayRef(values, begin + i)); } return this; }

Page 52: Over 9000: JRuby in 2015

FFI

• Ruby API/DSL for calling native code

• Came from Rubinius

• Runs on all Ruby impls

• Solves "access" use case

• Works well for coarse-grained calls

Page 53: Over 9000: JRuby in 2015

Ruby FFI exampleclass Timeval < FFI::Struct  layout :tv_sec => :ulong, :tv_usec => :ulongend

module LibC  extend FFI::Library  ffi_lib FFI::Library::LIBC  attach_function :gettimeofday, [ :pointer, :pointer ], :intend

t = Timeval.newLibC.gettimeofday(t.pointer, nil)

Page 54: Over 9000: JRuby in 2015

Language and Library Futures

Page 55: Over 9000: JRuby in 2015

9000 will match MRI

Page 56: Over 9000: JRuby in 2015

More core in Ruby

Page 57: Over 9000: JRuby in 2015

Eliminating object wrappers

Page 58: Over 9000: JRuby in 2015

Better two-way integration with JVM

languages

Page 59: Over 9000: JRuby in 2015

Better FFI tooling in JRuby and JVM

Page 60: Over 9000: JRuby in 2015

Performance

Page 61: Over 9000: JRuby in 2015

Steady Improvement

Page 62: Over 9000: JRuby in 2015

MRI 1.9 ~ 2-3x 1.8

Page 63: Over 9000: JRuby in 2015

MRI 2.1 ~ 2-3x 1.9

Page 64: Over 9000: JRuby in 2015

Faster than most interpreted languages

Page 65: Over 9000: JRuby in 2015

Not even close to compiled/jitted speed

Page 66: Over 9000: JRuby in 2015

JRuby

• Faster than MRI on average

• Steady improvement

• Approaching Java in some areas

Page 67: Over 9000: JRuby in 2015

JVM Over Time

0

6

12

18

24

Java 1.4 Java 5 Java 6 Java 7

JRuby 1.0.3 (bm_red_black_tree.rb)

Page 68: Over 9000: JRuby in 2015

Versus MRI 1.8

0

6

12

18

24

Java 1.4 Java 5 Java 6 Java 7

JRuby 1.0.3 (bm_red_black_tree.rb) MRI 1.8

Page 69: Over 9000: JRuby in 2015

0

0.55

1.1

1.65

2.2

1.1.6 1.4.0 1.5.6 1.6.8 1.7.0

OpenJDK 8 (bm_red_black_tree.rb)

Page 70: Over 9000: JRuby in 2015

The Good

• Method dispatch cheap or free

• Method activation cheap or free

• Languages inline together (Java, Ruby, Scala…)

• Shared resources across languages

Page 71: Over 9000: JRuby in 2015

red/black tree, pure Ruby versus native

ruby-2.0.0 + Ruby

ruby-2.0.0 + C ext

jruby + Ruby

Runtime per iteration

0 0.75 1.5 2.25 3

0.29s

0.51s

2.48s

Page 72: Over 9000: JRuby in 2015

The Bad

• Unoptimized patterns often have terrible performance characteristics

• Numeric operations allocate objects

• Instance vars require wrapper, indirection

• Java objects must be wrapped or marshaled

• Closure state is expensive

• Blah blah startup time blah blah

Page 73: Over 9000: JRuby in 2015

Performance Futures

Page 74: Over 9000: JRuby in 2015

Intermediate Representation

• Traditional compiler architecture for JRuby

• Instructions, operands, control-flow graph

• Optimization passes

• Optimize before emitting bytecode

• Closer mapping to JVM operations

Page 75: Over 9000: JRuby in 2015

def foo(a, b) c = 1 d = a + cend

0 check_arity(2, 0, -1)1 a = recv_pre_reqd_arg(0)2 b = recv_pre_reqd_arg(1)3 %block = recv_closure4 thread_poll5 line_num(1)6 c = 17 line_num(2)8 %v_0 = call(:+, a, [c])9 d = copy(%v_0)10 return(%v_0)

Register-based

3 address format

IR InstructionsSemanticAnalysis

Page 76: Over 9000: JRuby in 2015

The Good

• Well-understood techniques

• Creator worked on Java JIT years ago

• Drastically simpler JVM bytecode backend

• Less one-off opto code

• Simpler runtime

• Performance!

Page 77: Over 9000: JRuby in 2015

Numeric loop performance

0

0.9

1.8

2.7

3.6

times faster than MRI 2.1JRuby 1.7 JRuby 9k

Page 78: Over 9000: JRuby in 2015

def loop(a) i = 0 while i < a i +=1 endend

def loop(a:int) i = 0 while i < a i +=1 endend

Page 79: Over 9000: JRuby in 2015

Numeric loop performance

0

15

30

45

60

times faster than MRI 2.1JRuby 9k JRuby 1.7 9k+unbox

Page 80: Over 9000: JRuby in 2015

The Bad

• Work in progress - join us!

• Large-scale rework

• Requires knowledge of compiler design

• Doesn’t address object layout yet

Page 81: Over 9000: JRuby in 2015

Truffle

• Optimizing language framework

• Builds on Graal

• Write AST + interpreter, it builds a JIT

• Hints for object layout, unboxing

• Early days but very exciting

Page 82: Over 9000: JRuby in 2015

mandelbrot(500)

0

10

20

30

40

times faster than MRI 2.1JRuby 9k + indy JRuby 9k + unboxing JRuby 9k + Truffle

Page 83: Over 9000: JRuby in 2015

GC

Page 84: Over 9000: JRuby in 2015

Time per GC versus heap usage

Tim

e pe

r G

C

0ms

75ms

150ms

225ms

300ms

Heap usage (MRI/JRuby)

188KB/29MB

Ruby 2.0.0 JRuby

Page 85: Over 9000: JRuby in 2015

GC runs per iteration, gc_stress.rb

0

750

1500

2250

3000

Ruby 2.2 JRuby

Page 86: Over 9000: JRuby in 2015

GC time per iteration, gc_stress.rb

0

0.6

1.2

1.8

2.4

Ruby 2.2 JRuby

Page 87: Over 9000: JRuby in 2015

Many GCs

• Serial collector

• Parallel collector

• Concurrent collector (CMS)

• Concurrent region collector (G1)

• Continuously concurrent collector (Azul)

Page 88: Over 9000: JRuby in 2015

JRuby, One Thread

Page 89: Over 9000: JRuby in 2015

JRuby, One Thread

Serial GC

Parallel GC

Concurrent GC

Page 90: Over 9000: JRuby in 2015

Unlikely GC will be a problem for most apps.

Page 91: Over 9000: JRuby in 2015

Tooling

Page 92: Over 9000: JRuby in 2015

JVM tools are awesome

Page 93: Over 9000: JRuby in 2015
Page 94: Over 9000: JRuby in 2015

$ jruby --manage …

Page 95: Over 9000: JRuby in 2015
Page 96: Over 9000: JRuby in 2015
Page 97: Over 9000: JRuby in 2015

require 'jmx'def in_mb(value) format "%0.2f Mb" % (value.to_f / (1024 * 1024)) endserver = JMX.simple_serverclient = JMX.connectmemory = client["java.lang:type=Memory"] Thread.new do puts "Enter 'gc' to garbage collect or anything else to quit" while gets.chomp == "gc" memory.gc end server.stop exit 0 endwhile (true) heap = in_mb(memory.heap_memory_usage.used) non_heap = in_mb(memory.non_heap_memory_usage.used) puts "Heap: #{heap}, Non-Heap: #{non_heap}" sleep(2) end

Page 98: Over 9000: JRuby in 2015

require 'jmx'class UsefulMetrics < RubyDynamicMBean rw_attribute :name, :string, "My sample attribute" r_attribute :explicit_reader, :int, "Sample int with writer", :my_reader operation "Doubles a value" parameter :int, "a", "Value to double" returns :int def double(a) a + a endendmy_server = JMX::MBeanServer.newdyna = UsefulMetrics.new("domain.UsefulMetrics", $$.to_s)domain = my_server.default_domainmy_server.register_mbean dyna, "#{domain}:type=UsefulMetrics"

Page 99: Over 9000: JRuby in 2015

Heap Dumps

VisualVM or jmap + jhat

Page 100: Over 9000: JRuby in 2015

Useful to Us

Page 101: Over 9000: JRuby in 2015

Maybe Useful for You

Page 102: Over 9000: JRuby in 2015

Tooling Futures

Page 103: Over 9000: JRuby in 2015

Alienist

Java Heap Ruby Heaphprof JSON

https://github.com/enebo/alienist_viewer

https://github.com/enebo/alienist

Ruby HeapJSON

Rails App

Page 104: Over 9000: JRuby in 2015

More Stats

• What metrics would be interesting?

• Hook up to monitoring services?

• Remote debugging and profiling?

Page 105: Over 9000: JRuby in 2015

alienist

$ jruby -e 'gets'&

$ jmap -dump:live,file=foo.dump <pid>

$ alienist -c foo.dumpTook 33.7012s to parse 596577 objects from 5698 classes.

Ruby Instances: 11,627, Ruby Classes: 351

Page 106: Over 9000: JRuby in 2015

{ "name": "Gem::Platform", "size": 325, "id": 34200727296, "instances": [ { "id": 34211817960, "size": 40, "variables": [ ["@cpu", 34186089840], ["@os", 34211854176], ["@version", 34186089840] ], "references": [34211803176] }, ] },

Class name

ids!

Page 107: Over 9000: JRuby in 2015

alienist_viewer

Page 108: Over 9000: JRuby in 2015

alienist_viewer

Page 109: Over 9000: JRuby in 2015

alienist TODO

• Concept of Size, query language?

• Make (someone make) MRI dumper

• Allow for impl-specific data

• Specification for JSON format

Page 110: Over 9000: JRuby in 2015

Your Turn

Page 111: Over 9000: JRuby in 2015

Excluding merges, 24 authors have pushed 790 commits to master and 909

commits to all branches. On master, 1,880 files have changed and there have been 69,878 additions and 66,549 deletions.

Page 112: Over 9000: JRuby in 2015

jruby.org

Page 113: Over 9000: JRuby in 2015

Use 'jruby-9000'in Ruby installers

Page 114: Over 9000: JRuby in 2015

Test with 'jruby-head'on TravisCI

Page 115: Over 9000: JRuby in 2015

File bugs atbugs.jruby.org

Page 116: Over 9000: JRuby in 2015

Help us buildRuby’s Future!

Page 117: Over 9000: JRuby in 2015

Thank you!