public
Last active

Shows the performance effects of crossing the JRuby <--> Java bridge, and using JRuby's java_method.

  • Download Gist
jruby_java_max_benchmark.rb
Ruby
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
# Illustrates the overhead of the JRuby <--> Java bridge
# parameter and return value type conversions, and the
# dramatic performance improvement that can be had by
# specifying the Java overload using java_method.
 
require 'java'
require 'benchmark'
 
ITERATION_COUNT = ARGV.empty? ? 100_000 : ARGV.first.to_i
JMath = java.lang.Math
 
# Test the max strategy, which is passed as a block taking x and y params.
def test
ITERATION_COUNT.times do
x = rand(1_000_000)
y = rand(1_000_000)
max = yield(x, y)
max.class # do something w/max so Java optimizer doesn't eliminate it
end
end
def java_test
test { |x,y| java.lang.Math.max(x, y) }
end
 
def java_test_with_alias
java_long_max = java.lang.Math.java_method(:max, [Java::long, Java::long])
test { |x,y| java_long_max.(x, y) }
end
 
def java_test_with_math_alias
test { |x,y| JMath.max(x, y) }
end
 
def ruby_test_inline
test { |x, y| x >= y ? x : y }
end
 
def ruby_max(x, y)
x >= y ? x : y
end
 
def ruby_test_with_function
test { |x, y| ruby_max(x, y) }
end
 
def main
iteration_count_str = java.text.NumberFormat.instance.format(ITERATION_COUNT)
puts "Performing #{iteration_count_str} iterations for tests.\n"
java_time = Benchmark.measure { java_test }.real
java_alias_time = Benchmark.measure { java_test_with_alias }.real
java_math_alias_time = Benchmark.measure { java_test_with_math_alias }.real
ruby_inline_time = Benchmark.measure { ruby_test_inline }.real
ruby_function_time = Benchmark.measure { ruby_test_with_function }.real
fastest_time = [java_time, java_alias_time, java_math_alias_time, \
ruby_inline_time, ruby_function_time].min
 
puts '%-24.24s%+16s%+16s%+16s' % ['', 'Total', 'Average', 'X / Min'] # header
puts '%-24.24s%+16s%+16s%+16s' % ['', '(sec)', '(nsec)', '']
 
output = ->(label, time) do
average_time = 1_000_000_000 * time / ITERATION_COUNT
relative_time = time / fastest_time
puts '%-24.24s%16.4f%16.4f%16.4f' % [label, time, average_time, relative_time]
end
 
output.('Using Java:', java_time)
output.('Using Java w/alias:', java_alias_time)
output.('Using Java w/math alias:', java_math_alias_time)
output.('Using Ruby inline:', ruby_inline_time)
output.('Using Ruby w/function:', ruby_function_time)
end
 
main
 
 
 
=begin
 
 
On Mac OS, Java version 1.6.0_37:
 
>ruby max_example.rb 100_000 2> /dev/null
Performing 100,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 1.2030 12029.9983 29.3415
Using Java w/alias: 0.0880 880.0006 2.1463
Using Java w/math alias: 0.0690 690.0001 1.6829
Using Ruby inline: 0.0410 409.9989 1.0000
Using Ruby w/function: 0.0510 510.0012 1.2439
 
 
>ruby max_example.rb 2_000_000 2> /dev/null
Performing 2,000,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 6.1250 3062.5000 9.5703
Using Java w/alias: 1.2600 630.0000 1.9687
Using Java w/math alias: 1.3790 689.5001 2.1547
Using Ruby inline: 0.7200 360.0000 1.1250
Using Ruby w/function: 0.6400 320.0001 1.0000
 
 
>ruby max_example.rb 100_000_000 2> /dev/null
Performing 100,000,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 123.6610 1236.6100 4.7720
Using Java w/alias: 39.1120 391.1200 1.5093
Using Java w/math alias: 43.0850 430.8500 1.6626
Using Ruby inline: 25.9140 259.1400 1.0000
Using Ruby w/function: 30.5850 305.8500 1.1803
 
 
On Linux (Mint, Ubuntu-based, 3.2.0-23-generic),
------------------------------------------------
 
[0] 12:47 toshiba-mint /home/kbennett/work/jruby-test
>ruby jruby_java_max_benchmark.rb 2> /dev/null
Performing 100,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 0.9680 9679.9994 22.5116
Using Java w/alias: 0.0940 939.9986 2.1860
Using Java w/math alias: 0.0830 829.9994 1.9302
Using Ruby inline: 0.0430 429.9998 1.0000
Using Ruby w/function: 0.0500 500.0019 1.1628
 
[0] 13:04 toshiba-mint /home/kbennett/work/jruby-test
>ruby jruby_java_max_benchmark.rb 2_000_000 2> /dev/null
Performing 2,000,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 3.0020 1501.0000 5.8863
Using Java w/alias: 0.8300 415.0000 1.6275
Using Java w/math alias: 0.9270 463.5000 1.8176
Using Ruby inline: 0.5100 255.0000 1.0000
Using Ruby w/function: 0.5370 268.5001 1.0529
 
[0] 13:04 toshiba-mint /home/kbennett/work/jruby-test
>ruby jruby_java_max_benchmark.rb 100_000_000 2> /dev/null
Performing 100,000,000 iterations for tests.
Total Average X / Min
(sec) (nsec)
Using Java: 87.8330 878.3300 3.7964
Using Java w/alias: 36.9640 369.6400 1.5977
Using Java w/math alias: 40.8660 408.6600 1.7663
Using Ruby inline: 23.1360 231.3600 1.0000
Using Ruby w/function: 24.5630 245.6300 1.0617
 
I use the 2>/dev/null to suppress the output of the ambiguous function
warning, but that's not necessary, and shouldn't be used as is w/Windows.
 
=end

Doubt it changes the results but line 31 should be test { |x, y| x >= y ? x : y }

Thanks for catching that! I've corrected the code.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.