Monday, August 25, 2008

Reason #1 to use FFI on JRuby - its faster

When running the FFI benchmarks on JRuby, I noticed something:

Benchmark File.umask(0777) performance, 100000x
0.998000 0.000000 0.998000 ( 0.998576)

Benchmark FFI File.umask(0777) performance, 100000x
0.942000 0.000000 0.942000 ( 0.941961)
FFI File.umask implements the same logic as File.umask - but the FFI version is pure ruby - and File.umask is implemented in java.

Why? Well, although both FFI and jna-posix currently both use JNA to call native functions, the FFI path avoids boxing up the arguments and calling via a java reflection Proxy.

The savings are enough that we can throw some ruby code into the method to make it behave exactly like File.umask should, and still be faster than the java implemented File.umask.

Thats with the same native backend. If we switch out the backend to use JFFI instead of JNA, we get:

Benchmark FFI File.umask(0777) performance, 100000x
0.382000 0.000000 0.382000 ( 0.381865)

Twice as fast, no code changes required.

Noice.

Here is the code for the FFI File.umask implementation:

module FFIFile
extend FFI::Library
if JRuby::FFI::Platform::IS_WINDOWS
attach_function :_umask, '_umask', [ :int ], :int
else
attach_function :_umask, 'umask', [ :int ], :int
end
def self.umask(mask = nil)
if mask
_umask(mask)
else
old = _umask(0)
_umask(old)
old
end
end
end

1 comment:

Roger Pack said...

how does the speed differ in MRI versus straight ruby C, is my question.

-r