Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
State of JRuby 2014
Search
Hiro Asari
February 21, 2014
Technology
190
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
V8のArray.prototype.flatを最大約20倍速くするまでと、巨大OSSへの大規模コミットの道のり
riyaamemiya
0
290
フロントエンドカンファレンス関西2026 - 速すぎるUIに、待ち時間を
teamlab
PRO
0
130
遠藤な_めぐろLT #38 「社内のAI活用推進」@麻布台_20261009
endonanana
0
130
AIがコードを書く時代に、エンジニアは何で自分の価値を証明するのか / In an era where AI writes code how do engineers prove their value
carta_engineering
3
1.1k
Claude の新機能を、 出た日に触って社内に届けるまで
rfdnxbro
1
180
AI時代のPRレビューにどう向き合うか?
kairim0
1
240
1つのリクエストを追って理解する - llm-dのP/D分離
akhino
1
160
PagerDuty Tech Hub-鳴らすけれど、人は動かない
ezaki
0
170
10年後、Engineering 行為を剥奪されるとして、わたしたちは、どう、何を創ればいいだろうか。 / If Engineering Is Taken Away in 10 Years, How and What Should We Create?
bitkey
PRO
1
190
Temporal 最高!でも改めて「日付」について調べたら人類の負債すぎる件
riyaamemiya
0
150
AIカンパニーへの転換を支えた、エンジニアの仕事の再定義
kworkdev
PRO
2
1.2k
しろおびから始める!ログ活用の第一歩
shumei_ito
0
950
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
247
13k
Bash Introduction
62gerente
615
220k
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
950
Why Our Code Smells
bkeepers
PRO
340
58k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
730
Rails Girls Zürich Keynote
gr2m
96
14k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
2
6.3k
Building Applications with DynamoDB
mza
96
7.2k
Design in an AI World
tapps
1
350
Docker and Python
trallard
47
4.2k
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