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
GitHub Copilot app最速の発信の裏側
tomokusaba
1
240
Chainlitで作るお手軽チャットUI
ynt0485
0
290
「勝手に広まる」人気 AI エージェントを爆速で作ろう!(AWS Summit Japan 2026講演資料)
minorun365
PRO
10
2.4k
AI 不只幫你寫 Code: 當專案從 300 暴增到 1500, 我們如何撐住 DevOps
appleboy
0
150
AIAU_UMEMOGU_ninomiya_slide
ninomiya_ii
0
260
OTel × Datadog で 「AI活用」を計測し、改善に繋げる
shihochan
2
580
SONiCのNETCONFサーバ機能を試してみた
sonic
0
110
ぼっちではじめた登壇が「51名」「241件」の発信に化けた
subroh0508
1
300
水を運ぶ人としてのリーダーシップ
izumii19
4
900
いまさら聞けない「仕様駆動開発入門」 〜AI活用時代の開発プロセスを考える〜
findy_eventslides
2
180
“詰む”前に仕組みを作れ 〜技術の波に溺れないためのキャッチアップ術〜
takasyou
7
3.5k
SONiC実機とGNS3 SONiC VSによる事前コンフィグ検証 ― 生成AIエージェントを環境構築・検証支援に使ってみた ―
sonic
0
110
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
980
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.3k
The Cult of Friendly URLs
andyhume
79
6.9k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
360
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
430
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
210
WENDY [Excerpt]
tessaabrams
11
38k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Unsuck your backbone
ammeep
672
58k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
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