Last active
December 19, 2017 06:03
-
-
Save keithrbennett/4580344 to your computer and use it in GitHub Desktop.
Shows the performance effects of crossing the JRuby <--> Java bridge, and using JRuby's java_method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Thanks for catching that! I've corrected the code.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Doubt it changes the results but line 31 should be
test { |x, y| x >= y ? x : y }