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
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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
200
Other Decks in Technology
See All in Technology
Introduction to Bill One Development Engineer
sansan33
PRO
0
470
名刺メーカーDevグループ 紹介資料
sansan33
PRO
0
1.2k
Introduction to Sansan for Engineers / エンジニア向け会社紹介
sansan33
PRO
6
77k
英語が話せなくてもKubeConスタッフに参加した話
yusuke427
2
1.1k
VLMで2.3万枚のPyCon JP写真を検索!
terapyon
1
510
Master Dataグループ紹介資料
sansan33
PRO
1
4.8k
Digital Credentials API × OpenID4VP ブラウザ完結型本人確認の実装知見(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
250
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
4
24k
AIに持続⼒を与える 判断の⻑期記憶設計
eiei114
1
710
Rust×eBPFでEDRっぽいものをつくる
sunlife3
2
970
サービス内で複数のOP・ASを連鎖させる(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
260
パスキーでドライブする アカウント統合(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
270
Featured
See All Featured
Utilizing Notion as your number one productivity tool
mfonobong
4
550
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
390
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
250
The browser strikes back
jonoalderson
0
1.5k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Prompt Engineering for Job Search
mfonobong
0
420
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.1k
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