250 likes | 365 Views
Benchmarking in jRuby for non-Java-ists. Eric Lubow CTO, SimpleReach http:// eric.lubow.org @ elubow. Funny Image. (Pause for laughter). SimpleReach is Hiring . Isn ’ t everyone? elubow@simplereach.com. SimpleReach. Innovation in SMB advertising 10k potential impressions for $10
E N D
Benchmarking in jRuby for non-Java-ists Eric Lubow CTO, SimpleReach http://eric.lubow.org @elubow
SimpleReach is Hiring Isn’t everyone? elubow@simplereach.com
SimpleReach • Innovation in SMB advertising • 10k potential impressions for $10 • Targeted ads that don’t look like ads • Mongo, Redis, Hadoop • Rails 3, Sinatra, Ruby, jRuby • Large Datasets / Real Time Bidding/Processing • Bare metal and cloud integration
Why Benchmark (jRuby)? • Know my application in MRI, but not jRuby • Need to find problem areas in jRuby app (50ms) • Extensions in Java vs. C Extensions
Comparisons MRI 1.8.7-p302 jRuby 1.5.3 Java (Java Virtual Machine) Runs Java code Pros Optimizations Hotspotting Forced Compile vs. JIT Garbage Collection Benefits of years of Java dev Cons “Warm Up” time • Written in C • Pros • C extensions • Cons • No Java integration • No Garbage collection • Static Compilation
Hotspots Dynamic profiling is the path to excellent performance. HotSpot has the benefit of profile data from the running application to inform itself. It also has the ability to de-optimize code. When Hotspot does an optimization it puts a cheap guard in front of the optimization to make sure the rationale for the optimization still holds true. If the guard ever fails then it de-optimizes back to a slow path. Thomas Enebo (EngineYard)
JSON Pure MRI jRuby Rehearsal ------------------------------------------parse: 0.001000 0.000000 0.001000 ( 0.001000)--------------------------------- total: 0.001000sec user system total realparse: 0.001000 0.000000 0.001000 ( 0.000000)Rehearsal -------------------------------------------encode: 0.001000 0.000000 0.001000 ( 0.001000)---------------------------------- total: 0.001000sec user system total realencode: 0.000000 0.000000 0.000000 ( 0.000000) Rehearsal ------------------------------------------parse: 0.255000 0.000000 0.255000 ( 0.255000)--------------------------------- total: 0.255000sec user system total realparse: 0.017000 0.000000 0.017000 ( 0.017000)Rehearsal -------------------------------------------encode: 0.036000 0.000000 0.036000 ( 0.035000)---------------------------------- total: 0.036000sec user system total realencode: 0.006000 0.000000 0.006000 ( 0.006000)
MRI Ruby-1.8.7-p302 w/Yajl Code Results elubow@beacon json$ ruby parse.rb Rehearsal ------------------------------------------ parse: 0.240000 0.120000 0.360000 ( 0.588048) --------------------------------- total: 0.360000sec user system total real parse: 0.230000 0.110000 0.340000 ( 0.466025) Rehearsal ------------------------------------------- encode: 0.230000 0.120000 0.350000 ( 0.686670) ---------------------------------- total: 0.350000sec user system total real encode: 0.240000 0.100000 0.340000 ( 0.486075) json = File.new('bid1.json', 'r') parser = Yajl::Parser.new parser.on_parse_complete = lambda {|obj|} 100_000.times { parser.parse(json); } Benchmark.bmbm do |x| x.report("parse:") { 100_000.times { parser.parse(json); } } end parsed = parser.parse(json) 100_000.times { parsed.to_json } Benchmark.bmbm do |x| x.report("encode:") { 100_000.times { parsed.to_json } } end
MRI Ruby-1.8.7-p302 w/Yajl Code Results elubow@beacon json$ ruby parse.rb Rehearsal ------------------------------------------parse: 0.000000 0.000000 0.000000 ( 0.000159)--------------------------------- total: 0.000000sec user system total realparse: 0.000000 0.000000 0.000000 ( 0.000093)Rehearsal ------------------------------------------encode: 0.000000 0.000000 0.000000 ( 0.000088)--------------------------------- total: 0.000000sec user system total realencode: 0.000000 0.000000 0.000000 ( 0.000063) require 'yajl'parser = Yajl::Parser.new parser.on_parse_complete = lambda {|obj|} 100_000.times { parser.parse(json); } Benchmark.bm do |x| x.report("parse:") { parser.parse(json) }end parsed = parser.parse(json) 100_000.times { parsed.to_json } Benchmark.bm do |x| x.report("encode:") { parsed.to_json }end
jRuby-1.5.3 w/ JSON-jRuby Code Results elubow@beacon json$ jruby --server -J-Djruby.compile.fastops=true -S parse.rb Rehearsal ------------------------------------------ parse: 12.433000 0.000000 12.433000 ( 12.433000) -------------------------------- total: 12.433000sec user system total real parse: 11.735000 0.000000 11.735000 ( 11.735000) Rehearsal ------------------------------------------- encode: 2.840000 0.000000 2.840000 ( 2.840000) ---------------------------------- total: 2.840000sec user system total real encode: 2.868000 0.000000 2.868000 ( 2.868000) json = File.read('bid1.json') 100_000.times { JSON.parse(json) } Benchmark.bmbm do |x| x.report("parse:") { 100_000.times { JSON.parse(json) } } end parsed = JSON.parse(json) 100_000.times { parsed.to_json } Benchmark.bmbm do |x| x.report("encode:") { 100_000.times { parsed.to_json } } end
jRuby-1.5.3 w/ JSON-jRuby Code Results elubow@beacon json$ jruby --server -J-Djruby.compile.fastops=true -S parse.rb Rehearsal ------------------------------------------ parse: 0.001000 0.000000 0.001000 ( 0.000000) --------------------------------- total: 0.001000sec user system total real parse: 0.000000 0.000000 0.000000 ( 0.000000) Rehearsal ------------------------------------------- encode: 0.001000 0.000000 0.001000 ( 0.001000) ---------------------------------- total: 0.001000sec user system total real encode: 0.000000 0.000000 0.000000 ( 0.000000) json = File.read('bid1.json') 100_000.times { JSON.parse(json) } Benchmark.bmbm do |x| x.report("parse:") { JSON.parse(json) } end parsed = JSON.parse(json) 100_000.times { parsed.to_json } Benchmark.bmbm do |x| x.report("encode:") { parsed.to_json } end
JSON Comparisons Yajl JSON-jRuby Java extension Drop in replacement elubow@beaconjson$ jruby --server -J-Djruby.compile.fastops=true -S parse.rb Rehearsal ------------------------------------------ parse: 12.433000 0.000000 12.433000 ( 12.433000) -------------------------------- total: 12.433000sec user systemtotalreal parse: 11.735000 0.000000 11.735000 ( 11.735000) Rehearsal ------------------------------------------- encode: 2.840000 0.000000 2.840000 ( 2.840000) ---------------------------------- total: 2.840000sec user systemtotalreal encode: 2.868000 0.000000 2.868000 ( 2.868000) • C extension • Not a drop in replacement elubow@beaconjson$ ruby parse.rb Rehearsal ------------------------------------------ parse: 0.240000 0.120000 0.360000 ( 0.588048) --------------------------------- total: 0.360000sec user systemtotalreal parse: 0.230000 0.110000 0.340000 ( 0.466025) Rehearsal ------------------------------------------- encode: 0.230000 0.120000 0.350000 ( 0.686670) ---------------------------------- total: 0.350000sec user systemtotalreal encode: 0.240000 0.100000 0.340000 ( 0.486075)
JSON Comparisons (100k) Yajl JSON-jRuby elubow@beacon json$ jruby --server -J-Djruby.compile.fastops=true -S parse.rb Rehearsal ------------------------------------------ parse: 12.433000 0.000000 12.433000 ( 12.433000) -------------------------------- total: 12.433000sec user system total real parse: 11.735000 0.000000 11.735000 ( 11.735000) Rehearsal ------------------------------------------- encode: 2.840000 0.000000 2.840000 ( 2.840000) ---------------------------------- total: 2.840000sec user system total real encode: 2.868000 0.000000 2.868000 ( 2.868000) elubow@beacon json$ ruby parse.rb Rehearsal ------------------------------------------ parse: 0.240000 0.120000 0.360000 ( 0.588048) --------------------------------- total: 0.360000sec user system total real parse: 0.230000 0.110000 0.340000 ( 0.466025) Rehearsal ------------------------------------------- encode: 0.230000 0.120000 0.350000 ( 0.686670) ---------------------------------- total: 0.350000sec user system total real encode: 0.240000 0.100000 0.340000 ( 0.486075)
JSON Comparisons (1x) Yajl JSON-jRuby elubow@beacon json$ jruby --server -J-Djruby.compile.fastops=true -S parse.rb Rehearsal ------------------------------------------ parse: 0.001000 0.000000 0.001000 ( 0.000000) --------------------------------- total: 0.001000sec user system total real parse: 0.000000 0.000000 0.000000 ( 0.000000) Rehearsal ------------------------------------------- encode: 0.001000 0.000000 0.001000 ( 0.001000) ---------------------------------- total: 0.001000sec user system total real encode: 0.000000 0.000000 0.000000 ( 0.000000) elubow@beacon json$ ruby parse.rb Rehearsal ------------------------------------------parse: 0.000000 0.000000 0.000000 ( 0.000159)--------------------------------- total: 0.000000sec user system total realparse: 0.000000 0.000000 0.000000 ( 0.000093)Rehearsal ------------------------------------------encode: 0.000000 0.000000 0.000000 ( 0.000088)--------------------------------- total: 0.000000sec user system total realencode: 0.000000 0.000000 0.000000 ( 0.000063)
Mongo + BSON Code Results Ruby 1.8.7 + bson: 270ms Ruby 1.8.7 + bson_ext: 13ms JRuby 1.6dev + bson: 20ms JRuby 1.6dev + bson_ext: 20ms require 'mongo' require 'benchmark' @db = Mongo::Connection.new('localhost', 27017).db(‘simplereach_website_development’) 100_000.times { @db[‘ads’].find({}).to_a } Benchmark.bm do |x| x.report(”find:") { @db[’ads'].find({}).to_a } end
Conclusions • Still have lots of testing to do • Discovered JSON conversions weren’t a large problem • Discovered BSON conversions are • C extensions • FFI (Foreign Function Interface) • jRuby gets better with every release • jRuby gets better with every Java release
References • http://www.engineyard.com/blog/2009/j-is-for-jvm-why-the-j-in-jruby/ • http://eric.lubow.org/2010/ruby/jruby/json-benchmarks-in-jruby/ • http://www.infoq.com/presentations/enebo-jruby
Questions? Eric Lubow http://eric.lubow.org eric@lubow.org