Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
State of JRuby 2014
Search
Hiro Asari
February 21, 2014
Technology
180
0
Share
State of JRuby 2014
RubyConf AU
21 February, 2014, Sydney, NSW, Australia
Video:
https://vimeo.com/90823948
Hiro Asari
February 21, 2014
More Decks by Hiro Asari
See All by Hiro Asari
Secrets of Regexp
banzaiman
1
190
Other Decks in Technology
See All in Technology
ワールドカフェI /チューターを改良する / World Café I and Improving the Tutors
ks91
PRO
0
320
[最強DB講義]推薦システム | 基礎編
recsyslab
PRO
1
180
弁護士ドットコム株式会社 エンジニア職向け 会社紹介資料
bengo4com
1
160
Good Enough Types: Heuristic Type Inference for Ruby
riseshia
1
250
Azure Static Web Apps の自動ビルドがタイムアウトしやすくなった状況に対応した件/global-azure2026
thara0402
0
420
Amazon S3 Filesについて
yama3133
2
210
Revisiting [CLS] and Patch Token Interaction in Vision Transformers
yu4u
0
380
AI バイブコーティングでキーボード不要?!
samakada
0
590
目的ファーストのハーネス設計 ~ハーネスの変更容易性を高めるための優先順位~
gotalab555
8
2.2k
コミュニティ・勉強会を作るのは目的じゃない
ohmori_yusuke
0
230
Chasing Real-Time Observability for CRuby
whitegreen
0
180
20年前の「OSS革命」に学ぶ AI時代の生存戦略
samakada
0
450
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Deep Space Network (abreviated)
tonyrice
0
120
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
100
Java REST API Framework Comparison - PWX 2021
mraible
34
9.3k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
220
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
180
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
520
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.2k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
[SF Ruby Conf 2025] Rails X
palkan
2
960
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.1k
The Limits of Empathy - UXLibs8
cassininazir
1
310
Transcript
State of JRuby 2014 Hiro Asari! Travis CI! ! RubyConf
Australia 2014
Have you heard of JRuby?
Have you tried JRuby?
Are you using JRuby?
JRuby is an implementation of the Ruby language
Ruby J
Ruby ust J
JRuby vs Ruby
Ruby Thread models OS Threads Green Threads Kernel GIL Ruby
interpreter Ruby 1.8 Green Threads GIL Ruby interpreter Kernel Ruby 1.9, 2.0 Green Threads Kernel JVM JRuby
JRuby is a fast implementation of the Ruby language on
the Java Virtual Machine
JRuby is fast • JVM improves over time
JRuby is fast • Faster and more mature garbage collectors
Time per GC versus heap usage Time per GC 0ms
75ms 150ms 225ms 300ms Heap usage (MRI/JRuby) 188KB/29MB 27MB/127MB 199MB/238MB Ruby 2.0.0 JRuby
0 1.5 3 4.5 6 Interpreted AST (i.e., no compiler)
Interpreted IR MRI 2.1.0 Compiled AST, no InvokeDynamic Compiled AST, with InvokeDynamic Mandelbrot
Web servers
TorqueBox • Application server with built-in support for • messaging
• scheduling • caching • daemons
Puma • Concurrent web server
Trinidad • Tomcat-based lightweight server
Deployment options • Heroku • OpenShift • Roll your own
on EC2
Web benchmarks • http://www.techempower.com/benchmarks/ #section=data-r8&hw=ec2&test=json&l=35s! • Ruby + Unicorn! •
JRuby + TorqueBox
Web Benchmarks JSON Serialization 0 5500 11000 16500 22000 rack
rails-stripped rails sinatra jruby 1.7.8 ruby 2.0.0
Web Benchmarks JSON Serialization (Log scale) 1 100 10000 rack
rails-stripped rails sinatra jruby 1.7.8 ruby 2.0.0
300 600 900 1200 sinatra rails-stripped rails jruby 1.7.8 ruby
2.0.0 Web Benchmarks Single Query
Web Benchmarks Multiple Queries 35.0 70.0 105.0 140.0 sinatra rails-stripped
rails jruby 1.7.8 ruby 2.0.0
Brief History of JRuby • 2001 — started by Jan
Arne Petersen • 2006 — Rails support • 2011 — v 1.6.0 (experimental C extension support) • 2012 — v 1.7.0 (InvokeDynamic support)
2013 • Released 1.6.8 • community-based release • Released 1.7.2
through 1.7.9 • 1.7.4 introduced experimental Ruby 2.0 support
2013 $ git checkout master Switched to branch 'master' Your
branch is up-to-date with 'origin/master'. $ git log --format='%ai %s' | grep -v Merge | grep 2013-\\d\\d-\\d\\d -c 2459 ! ! ! ! ! ! ! !
2013 $ git co jruby-1_7 Switched to branch 'jruby-1_7' Your
branch is up-to-date with 'origin/jruby-1_7'. $ git log --format='%ai %s' | grep -v Merge | grep 2013-\\d\\d-\\d\\d -c 1939 ! ! ! ! ! ! ! !
2013 commit 1176078fa56f4bf3409ba05345def99a0ee06cb2 Author: Thomas E. Enebo <
[email protected]
> Date: Tue
Oct 1 11:30:22 2013 -0500 ! The future is now? ! ! ! ! ! ! ! !
JRuby Architecture JVM FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries Compiler & Byte Code Backend Extras Ruby Application Standard Libs
JVM • Constantly evolving
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)
vs MRI 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
InvokeDynamic • New language feature in Java 7 • Optimized
any kind of calls like Java calls • Ruby as fast as Java — in theory
InvokeDynamic • Improving throughout the 7u# releases
Java 8 • Due out 18 March, 2014
Mandelbrot Java 7u51 vs Java 8 b128 0 0.2 0.4
0.6 0.8 1 7u51 8 b128
JRuby Architecture JVM FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries JRuby runtime Extras Ruby Application Standard Libs
FFI require&'ffi'& ! module&Hello& &&extend&FFI::Library& &&ffi_lib&FFI::Library::LIBC& &&attach_function&:puts,&[&:string&],&:int& end& ! Hello.puts("Hello,&World")
FFI in Java 9* FFI in Java 9* Still JEP
stage In 2016?
Startup Times • Still the biggest pain point for JRuby
programmers
Startup Times -e 1 gem --help rake -T 0 2.5
5 7.5 10 Ruby 2.0.0 JRuby
Startup Times • Some optimizations are possible via JVM tuning
Nailgun • Keep a single JVM running in background •
Toss commands over to it • It stays hot, so code starts faster • Hard to clean up all state (e.g. threads) • Can’t get access to user’s terminal
Drip • Start a new JVM after each command •
Pre-boot JVM plus optional code • Analyze command line for differences • Age out unused instances • https://github.com/flatland/drip
Rails startup time Seconds (lower is better) 0 4 8
12 16 7u51 7u51 + optimizations 8 b128 8 b128 + optimizations 7u51 + Drip 7u51 + optimizations + Drip 8 b128 + Drip 8 b128 + optimizations + Drip
export JRUBY_OPTS=" -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify"
Further optimization with Drip
public class DripMain {! public static RubyInstanceConfig DRIP_CONFIG;! public static
Ruby DRIP_RUNTIME;! ! public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRIP_WARMUP";! public static final String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1";! public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripmain.rb";! ! public static void main(String[] args) throws IOException {! // warmup JVM first! Ruby ruby = Ruby.newInstance();! ! String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);! if (envWarmup != null && envWarmup.length() > 0) {! ruby.evalScriptlet(envWarmup);! } else {! ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);! }! ! // preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);! ! RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! ! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePath(), false);! } finally {! fis.close();! }! }! ! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }! }!
public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI public static final
String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm public static void main(String[] args) throws IOException {! // warmup JVM first! Ruby ruby = Ruby.newInstance();! String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);! if (envWarmup != null && envWarmup.length() > 0) {! ruby.evalScriptlet(envWarmup);! } else {! ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);! }! // preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);! RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);!
public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI public static final
String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm public static void main(String[] args) throws IOException {! // warmup JVM first! Ruby ruby = Ruby.newInstance();! String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);! if (envWarmup != null && envWarmup.length() > 0) {! ruby.evalScriptlet(envWarmup);! } else {! ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);! }! // preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);! RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);!
public static final String JRUBY_DRIP_WARMUP_ENV = "JRUBY_DRI public static final
String JRUBY_DRIP_WARMUP_DEFAULT = "1 + 1 public static final String JRUBY_DRIP_PREBOOT_FILE = "./dripm public static void main(String[] args) throws IOException {! // warmup JVM first! Ruby ruby = Ruby.newInstance();! String envWarmup = System.getenv(JRUBY_DRIP_WARMUP_ENV);! if (envWarmup != null && envWarmup.length() > 0) {! ruby.evalScriptlet(envWarmup);! } else {! ruby.evalScriptlet(JRUBY_DRIP_WARMUP_DEFAULT);! }! // preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);! RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);!
// preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!
RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePa } finally {! fis.close();! }! }! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }!
// preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!
RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePa } finally {! fis.close();! }! }! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }!
// preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!
RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePa } finally {! fis.close();! }! }! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }!
// preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!
RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePa } finally {! fis.close();! }! }! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }!
// preboot actual runtime! Ruby.clearGlobalRuntime();! File dripMain = new File(JRUBY_DRIP_PREBOOT_FILE);!
RubyInstanceConfig config = new RubyInstanceConfig();! ruby = Ruby.newInstance(config);! if (dripMain.exists()) {! FileInputStream fis = new FileInputStream(dripMain);! try {! ruby.getLoadService().load(dripMain.getAbsolutePa } finally {! fis.close();! }! }! // use config and runtime from preboot process! DRIP_CONFIG = config;! DRIP_RUNTIME = ruby;! }!
JRuby Startup rake -T 0 2.5 5 7.5 10 C
Ruby JRuby JRuby (best) JRuby (drip) JRuby (drip init) JRuby (dripmain)
Next generation JRuby
Brief History of JRuby • 2001 — started by Jan
Arne Petersen • 2006 — Rails support • 2011 — v 1.6.0 (experimental C extension support) • 2012 — v 1.7.0 (InvokeDynamic support) • 2014 — v 9000
JRuby 9000 Version 0 20 40 60 80 100 Years
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Illustrator (Mac OS), since 1987 MRI (since 1993) JRuby (since 2001)
Why 9000?
None
Because it is over 8000.
JRuby Architecture JVM FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries Intermediate Representation Extras Ruby Application Standard Libs
Intermediate Representation Lexical! Analysis Parsing Bytecode Generation Interpret AST IR
Instructions CFG DFG … Existing New! Dalvik Generation … Semantic! Analysis Optimization
1 check_arity(2, 0, -1)! 2 a(0:0) = recv_pre_reqd_arg(0)! 3 thread_poll!
4 line_num(2)! 5 %v_2 = call(+, a(0:0), [1:Fixnum])! 6 return(%v_2) -Xir.passes=LocalOptimizationPass,DeadCodeElimination def foo(a, b)! c = 1! d = a + c! end 0 check_arity(2, 0, -1)! 1 a(0:0) = recv_pre_reqd_arg(0)! 2 b(0:1) = recv_pre_reqd_arg(1)! 3 %block(0:2) = recv_closure! 4 thread_poll! 5 line_num(1)! 6 c(0:3) = 1:fixnum! 7 line_num(2)! 8 %v_0 = call(+, a(0:0), [c(0:3)])! 9 d(0:4) = copy(%v_0)! 10 return(%v_0) propagation def foo(a)! ! a + 1! end
Truffle http://www.flickr.com/photos/qwrrty/2838741714/
JRuby Architecture JVM FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries Truffle Extras Ruby Application Standard Libs
Truffle • AST interpreting framework from Oracle Labs • Potential
alternative to: • AST interpreter • bytecode backend • IR
0 1.5 3 4.5 6 Interpreted AST (i.e., no compiler)
Interpreted IR MRI 2.1.0 Compiled AST, no InvokeDynamic Compiled AST, with InvokeDynamic Truffle Mandelbrot
JRuby Architecture Graal FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries Extras Ruby Application Standard Libs Truffle
Mandelbrot 0 1.5 3 4.5 6 Interpreted AST (i.e., no
compiler) Interpreted IR Compiled AST, no InvokeDynamic Compiled AST, with InvokeDynamic MRI 2.1.0 Truffle Truffle + Graal
None
JRuby Architecture JVM FFI JDK JRuby Core Classes Ruby Core
classes Other Java Libraries JRuby runtime Extras Ruby Application Standard Libs
2.1 Compatibility • No 2.0 mode will be provided (1.7.x
has limited support) • Some work to do on 2.1 specs
C extensions No more
Google rejected JRuby team’s application for GSoC 2014.
Contact! ! @hiro_asari! GitHub: BanzaiMan! @jruby! @travisci