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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Hiro Asari
February 21, 2014
Technology
0
180
State of JRuby 2014
RubyConf AU
21 February, 2014, Sydney, NSW, Australia
Video:
https://vimeo.com/90823948
Hiro Asari
February 21, 2014
Tweet
Share
More Decks by Hiro Asari
See All by Hiro Asari
Secrets of Regexp
banzaiman
1
190
Other Decks in Technology
See All in Technology
Claude Codeベストプラクティスまとめ
minorun365
53
30k
Amazon Bedrock AgentCore 認証・認可入門
hironobuiga
1
450
VRTと真面目に向き合う
hiragram
1
510
変化するコーディングエージェントとの現実的な付き合い方 〜Cursor安定択説と、ツールに依存しない「資産」〜
empitsu
3
670
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
3.8k
BPaaSオペレーション・kubell社内 n8n活用による効率化検証事例紹介
kentarofujii
0
320
みんなだいすきALB、NLBの 仕組みから最新機能まで総おさらい / Mastering ALB & NLB: Internal Mechanics and Latest Innovations
kaminashi
0
150
開発メンバーが語るFindy Conferenceの裏側とこれから
sontixyou
2
390
2026年はチャンキングを極める!
shibuiwilliam
8
1.7k
ZOZOにおけるAI活用の現在 ~開発組織全体での取り組みと試行錯誤~
zozotech
PRO
2
1.5k
AI推進者の視点で見る、Bill OneのAI活用の今
sansantech
PRO
2
280
2人で作ったAIダッシュボードが、開発組織の次の一手を照らした話― Cursor × SpecKit × 可視化の実践 ― Qiita AI Summit
noalisaai
1
300
Featured
See All Featured
Joys of Absence: A Defence of Solitary Play
codingconduct
1
280
Art, The Web, and Tiny UX
lynnandtonic
304
21k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
600
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
0
99
The SEO identity crisis: Don't let AI make you average
varn
0
58
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
65
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.2k
New Earth Scene 8
popppiees
1
1.5k
Side Projects
sachag
455
43k
The SEO Collaboration Effect
kristinabergwall1
0
340
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
0
300
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
570
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