Skip to content

Instantly share code, notes, and snippets.

@keithrbennett
Last active December 19, 2017 06:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keithrbennett/4580344 to your computer and use it in GitHub Desktop.
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.
# 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
@rohitn
Copy link

rohitn commented Jan 20, 2013

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

@keithrbennett
Copy link
Author

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