Summarized benchmark results of different Java interface implementation strategies using JRuby.
The idea is to see the performance impact of using different strategies to implement the java.util.Comparator interface in JRuby. The Ruby sort! method and the Java Collections::sort method are used over collections of Ruby Strings, Java Strings and Comparable Objects.
$ rake run
- default Ruby comparator: Ruby
sort!method with default comparator. - closure Ruby comparator: Ruby
sort!method with comparator block. - default Java comparator: Java
Collections::sortmethod with default comparator. - closure Java comparator: Java
Collections::sortmethod with comparator block using the closure conversion interface implementation ofjava.util.Comparator. - mixin Java comparator: Java
Collections::sortmethod with comparator class using the module mixin interface implementation ofjava.util.Comparator. - native Java comparator: Java
Collections::sortmethod with comparator native Java class implementation ofjava.util.Comparator.
4M random 4-chars strings are generated and the same base collection is used to create the following collections:
- Ruby Strings: Ruby Array of Ruby String
- Java Strings: java.util.ArrayList of java.lang.String
- Objects: Ruby Array of Comparable Ruby objects with a string attribute
| Comparator | Ruby Strings | Java Strings | Objects |
|---|---|---|---|
| default Ruby comparator | 8.15s(1) | N/A | 17.60s(3) |
| closure Ruby comparator | 18.20s | N/A | 28.78s |
| default Java comparator | 8.09s(1) | 3.54s | N/A |
| closure Java comparator | 50.05s | 46.78s | 32.06s(2) |
| mixin Java comparator | 39.14s | 35.17s | 19.06s(2)(3) |
| native Java comparator | 8.25s(1)(4) | 3.99s | N/A |
- As expected both Ruby
sort!and JavaCollections::sorton Ruby strings collection yield similar performance. - Curiously using closure/mixin comparator on Comparable Ruby objects is significantly faster than on Ruby strings. Also, using the mixin comparator is faster than using closure comparator.
- Interesting: Ruby
sort!using default comparator on Comparable objects and JavaCollections::sortusing the mixin comparator on Comparable objects has similar performance. - Implementing a custom comparator natively in Java is very fast on Ruby collections.
- Using a module mixin Java comparator on Comparable objects is the most efficient option in Ruby.
- Implementing a custom comparator natively in Java is the fastest option.
- Odly, a closure comparator is slower than mixin comparator, see profiling investigation below.
- Both closure and mixin comparators are significantly slower on Ruby strings collection than on Comparable objects which is probably explained by the String conversions when crossing the Ruby/Java boundary.
This is the relevant part of the profiling of the closure Java comparator on Ruby strings:
---------------------------------------------------------------------------------------------------------
70.23 50.56 19.67 1/1 Object#java_sort_with_closure_comparator
99% 71% 70.23 50.56 19.67 1 Java::JavaUtil::Collections.sort
19.67 15.25 4.42 82562064/82562064 #<Class:0x6e36a818>#method_missing
---------------------------------------------------------------------------------------------------------
19.67 15.25 4.42 82562064/82562064 Java::JavaUtil::Collections.sort
28% 21% 19.67 15.25 4.42 82562064 #<Class:0x6e36a818>#method_missing
4.42 4.42 0.00 82562064/82562064 String#<=>
---------------------------------------------------------------------------------------------------------
4.42 4.42 0.00 82562064/82562064 #<Class:0x6e36a818>#method_missing
6% 6% 4.42 4.42 0.00 82562064 String#<=>
We can see time is lost in #method_missing. In fact, looking at the JRuby source code in core/src/main/java/org/jruby/javasupport/JavaUtil.java we can see that the closure interface implementation is handled using a #method_missing indirection. This is probably something that could be improved.
Colin Surprenant, http://github.com/colinsurprenant/, @colinsurprenant, [email protected], http://colinsurprenant.com/
Apache License, Version 2.0. See the LICENSE.md file.