Sunteți pe pagina 1din 38

FFI

MAKING CROSS ENGINE EXTENSIONS

Jeremy Hinegardner
jeremy@copiousfreetime.org
twitter: copiousfreetime

Tuesday, November 24, 2009 1


I LOVE RUBY

Tuesday, November 24, 2009 2


I LIKE C

Tuesday, November 24, 2009 3


SURVEY TIME

Tuesday, November 24, 2009 4


RUBY DEVELOPERS?

Tuesday, November 24, 2009 5


WRITER OF LIBRARIES?

Tuesday, November 24, 2009 6


WRITER OF EXTENSIONS?

Tuesday, November 24, 2009 7


USED BY MULTIPLE ENGINES?

Tuesday, November 24, 2009 8


WHAT IS FFI?

Tuesday, November 24, 2009 9


LIBFFI
http://sourceware.org/libffi/

“A foreign function interface is the


popular name for the interface that
allows code written in one language
to call code written in another
language.”

Tuesday, November 24, 2009 10


FOR RUBYISTS

The Goal :

An extension based upon FFI should


be compatible with many ruby
engines.

Tuesday, November 24, 2009 11


libfoo.so

Tuesday, November 24, 2009 12


Application
uses
libfoo_bar()

libfoo.so

Tuesday, November 24, 2009 12


Application
uses
libfoo_bar()

FFI

libfoo.so

Tuesday, November 24, 2009 12


m e
i
Application
t
n
uses

R u
libfoo_bar()

FFI

libfoo.so

Tuesday, November 24, 2009 12


App
Matz Ruby
Interpreter

ruby-foo C extension

libfoo.so

Tuesday, November 24, 2009 13


App App
JRuby Rubinius
Interpreter Interpreter
App
Matz Ruby
Interpreter

ruby-foo C extension

libfoo.so

Tuesday, November 24, 2009 13


App App
JRuby Rubinius
Interpreter Interpreter
App
Matz Ruby
Interpreter

libfoo.so

Tuesday, November 24, 2009 13


App App App
JRuby Matz Ruby Rubinius
Interpreter Interpreter Interpreter

libfoo.so

Tuesday, November 24, 2009 13


App App App
JRuby Matz Ruby Rubinius
Interpreter Interpreter Interpreter

built-in libffi or ffi gem

libfoo.so

Tuesday, November 24, 2009 13


App App App
JRuby Matz Ruby Rubinius
Interpreter Interpreter Interpreter

foo-ffi (pure ruby)

built-in libffi or ffi gem

libfoo.so

Tuesday, November 24, 2009 13


LIBSIMPLE_METRICS
http://github.com/copiousfreetime/libsimple_metrics

Tuesday, November 24, 2009 14


 1 #ifndef __SIMPLE_METRICS_H__
 2 #define __SIMPLE_METRICS_H__
 3 #include <stdlib.h>
 4 #include <math.h>
 5
 6 typedef struct _simple_metrics{
 7     double min;
 8     double max;
 9     double sum;
10     double sumsq;
11     long   count;
12 } simple_metrics ;
13
14 simple_metrics* simple_metrics_new();
15 void            simple_metrics_free(   simple_metrics* sm );
16 void            simple_metrics_update( simple_metrics* sm, double value );
17 double          simple_metrics_mean(   simple_metrics* sm );
18 double          simple_metrics_min(    simple_metrics* sm );
19 double          simple_metrics_max(    simple_metrics* sm );
20 double          simple_metrics_sum(    simple_metrics* sm );
21 long            simple_metrics_count(  simple_metrics* sm );
22 double          simple_metrics_stddev( simple_metrics* sm );
23 double          simple_metrics_rate(   simple_metrics* sm );
24
25 #endif

Tuesday, November 24, 2009 15


 1 class Metric
 2   attr_reader :name
 3   def initialize( name )
 4     @name
 5   end
 6
 7   def update( new_value) ... end
 8   def count  ... end
 9   def max    ... end
10   def mean   ... end
11   def min    ... end
12   def rate   ... end
13   def sum    ... end
14   def stddev ... end
15 end

Tuesday, November 24, 2009 16


142 void Init_simple_metrics_ext()
143 {
144     VALUE cSM_Common;
145
146     mSM  = rb_define_module( "SimpleMetrics" );
147     mSME = rb_define_module_under( mSM, "Ext" );
148
149     /* load the class we inherit from */
150     rb_require("simplemetrics/common");
151
152     cSM_Common = rb_const_get( mSM, rb_intern( "Common" ) );
153
154     cSME_Metric = rb_define_class_under( mSME, "Metric", cSM_Common );
155
156     rb_define_alloc_func(cSME_Metric, sm_alloc);
157     rb_define_method( cSME_Metric, "initialize", sm_initialize, 1 );
158     rb_define_method( cSME_Metric, "update", sm_update, 1 );
159     rb_define_method( cSME_Metric, "count", sm_count, 0 );
160     rb_define_method( cSME_Metric, "max", sm_max, 0 );
161     rb_define_method( cSME_Metric, "min", sm_min, 0 );
162     rb_define_method( cSME_Metric, "mean", sm_mean, 0 );
163     rb_define_method( cSME_Metric, "rate", sm_rate, 0 );
164     rb_define_method( cSME_Metric, "sum", sm_sum, 0 );
165     rb_define_method( cSME_Metric, "stddev", sm_stddev, 0 );
166
167 }

Tuesday, November 24, 2009 17


142 void Init_simple_metrics_ext()
143 {
144     VALUE cSM_Common;
145
146     mSM  = rb_define_module( "SimpleMetrics" );
147     mSME = rb_define_module_under( mSM, "Ext" );
148
149     /* load the class we inherit from */
150     rb_require("simplemetrics/common");
151
152     cSM_Common = rb_const_get( mSM, rb_intern( "Common" ) );
153
154     cSME_Metric = rb_define_class_under( mSME, "Metric", cSM_Common );
155
156     rb_define_alloc_func(cSME_Metric, sm_alloc);
157     rb_define_method( cSME_Metric, "initialize", sm_initialize, 1 );
158     rb_define_method( cSME_Metric, "update", sm_update, 1 );
159     rb_define_method( cSME_Metric, "count", sm_count, 0 );
160     rb_define_method( cSME_Metric, "max", sm_max, 0 );
161     rb_define_method( cSME_Metric, "min", sm_min, 0 );
162     rb_define_method( cSME_Metric, "mean", sm_mean, 0 );
163     rb_define_method( cSME_Metric, "rate", sm_rate, 0 );
164     rb_define_method( cSME_Metric, "sum", sm_sum, 0 );
165     rb_define_method( cSME_Metric, "stddev", sm_stddev, 0 );
166
167 }

Tuesday, November 24, 2009 17


7 module SimpleMetrics
 8   module FFI
 9
10     class Struct < ::FFI::ManagedStruct
11       layout :min, :double, :max, :double, :sum, :double,
12              :sumsq, :double, :count, :long
13       def self.release( ptr )
14         SimpleMetrics::FFI.simple_metrics_free( ptr )
15       end
16     end
17
18     extend ::FFI::Library
19     ffi_lib "libsimple_metrics"
20
21     attach_function :simple_metrics_new,   [          ], :pointer
22     attach_function :simple_metrics_free,  [ :pointer ], :void
23     attach_function :simple_metrics_update,[ :pointer, :double  ], :void
24     attach_function :simple_metrics_min,   [ :pointer ], :double
25     attach_function :simple_metrics_max,   [ :pointer ], :double
26     attach_function :simple_metrics_mean,  [ :pointer ], :double
27     attach_function :simple_metrics_sum,   [ :pointer ], :double
28     attach_function :simple_metrics_count, [ :pointer ], :long
29     attach_function :simple_metrics_stddev,[ :pointer ], :double
30     attach_function :simple_metrics_rate,  [ :pointer ], :double
31
32   end
33 end

Tuesday, November 24, 2009 18


7 module SimpleMetrics
 8   module FFI
 9
10     class Struct < ::FFI::ManagedStruct
11       layout :min, :double, :max, :double, :sum, :double,
12              :sumsq, :double, :count, :long
13       def self.release( ptr )
14         SimpleMetrics::FFI.simple_metrics_free( ptr )
15       end
16     end library function parameters return type
17
18     extend ::FFI::Library
19     ffi_lib "libsimple_metrics"
20
21     attach_function :simple_metrics_new,   [          ], :pointer
22     attach_function :simple_metrics_free,  [ :pointer ], :void
23     attach_function :simple_metrics_update,[ :pointer, :double  ], :void
24     attach_function :simple_metrics_min,   [ :pointer ], :double
25     attach_function :simple_metrics_max,   [ :pointer ], :double
26     attach_function :simple_metrics_mean,  [ :pointer ], :double
27     attach_function :simple_metrics_sum,   [ :pointer ], :double
28     attach_function :simple_metrics_count, [ :pointer ], :long
29     attach_function :simple_metrics_stddev,[ :pointer ], :double
30     attach_function :simple_metrics_rate,  [ :pointer ], :double
31
32   end
33 end

Tuesday, November 24, 2009 18


35 module SimpleMetrics
36   module FFI
37     class Metric < ::SimpleMetrics::Common
38       include ::SimpleMetrics::FFI
39       def initialize( name )
40         super
41         @impl = FFI.simple_metrics_new
42       end
43
44       def update( v )
45         simple_metrics_update( @impl, v )
46       end
47
48       self.keys.each do |f|
49         module_eval <<-code
50         def #{f}
51           simple_metrics_#{f}( @impl )
52         end
53         code
54       end
55     end
56   end
57 end

Tuesday, November 24, 2009 19


10 class Struct < ::FFI::ManagedStruct  6 typedef struct _simple_metrics{
11   layout :min, :double,  7     double min;
12          :max, :double,  8     double max;
13          :sum, :double,  9     double sum;
14          :sumsq, :double, 10     double sumsq;
15          :count, :long 11     long   count;
16   def self.release( ptr ) 12 } simple_metrics ;
17     SimpleMetrics::FFI.simple_metrics_free( ptr )
18   end
19 end

Tuesday, November 24, 2009 20


21 extend ::FFI::Library
22 ffi_lib "libsimple_metrics"
23
24 attach_function :simple_metrics_new,   [          ], :pointer
25 attach_function :simple_metrics_free,  [ :pointer ], :void
26 attach_function :simple_metrics_update,[ :pointer, :double  ], :void
27 attach_function :simple_metrics_mean,  [ :pointer ], :double
28 attach_function :simple_metrics_min,   [ :pointer ], :double
29 attach_function :simple_metrics_max,   [ :pointer ], :double
30 attach_function :simple_metrics_sum,   [ :pointer ], :double
31 attach_function :simple_metrics_count, [ :pointer ], :long
32 attach_function :simple_metrics_stddev,[ :pointer ], :double
33 attach_function :simple_metrics_rate,  [ :pointer ], :double

14 simple_metrics* simple_metrics_new();
15 void            simple_metrics_free(   simple_metrics* sm );
16 void            simple_metrics_update( simple_metrics* sm, double value );
17 double          simple_metrics_mean(   simple_metrics* sm );
18 double          simple_metrics_min(    simple_metrics* sm );
19 double          simple_metrics_max(    simple_metrics* sm );
20 double          simple_metrics_sum(    simple_metrics* sm );
21 long            simple_metrics_count(  simple_metrics* sm );
22 double          simple_metrics_stddev( simple_metrics* sm );
23 double          simple_metrics_rate(   simple_metrics* sm );

Tuesday, November 24, 2009 21


MEANINGLESS METRICS
Traditional C
FFI
Extension

Jeremy’s Time 40 minutes 70 minutes

1 Million update()
1.16 sec 0.42 sec
calls

Will it Blend run


Yes No
on JRuby?

Tuesday, November 24, 2009 22


DEMO

Tuesday, November 24, 2009 23


% ruby example/bench.rb 1000000
generating 1000000 random numbers between 0 and 10,000
Rehearsal -----------------------------------------------
ext 0.500000 0.000000 0.500000 ( 0.504501)
ffi 0.960000 0.000000 0.960000 ( 0.956847)
-------------------------------------- total: 1.460000sec

user system total real


ext 0.510000 0.000000 0.510000 ( 0.521388)
ffi 0.940000 0.000000 0.940000 ( 0.946538)

% ~/pkgs/jruby-1.4.0/bin/jruby example/bench.rb 1000000


generating 1000000 random numbers between 0 and 10,000
Rehearsal -----------------------------------------------
ffi 0.697000 0.000000 0.697000 ( 0.696000)
-------------------------------------- total: 0.697000sec

user system total real


ffi 0.493000 0.000000 0.493000 ( 0.493000)

Tuesday, November 24, 2009 24


FFI BASED PROJECTS
ffi-opengl Johnson FFI port
ffi-tk ffi-tcc

Nokogiri Ruby-SDL-FFI
ffi-wiiuse
ffi-life ffi-opencl rufus-tokyo
ffi-inliner
Rubygame
Ruby-GIR-FFI
Gnu Linear Programming Toolkit NiceFFI

Tuesday, November 24, 2009 25


THANKS

• Wayne Meissner - adding libffi to JRuby and providing the


ffi gem for MRI.

• Evan Phoenix - using libffi in Rubinius

• Authors of the examples on the ffi project wiki

Tuesday, November 24, 2009 26


LINKS

• http://github.com/ffi/ffi

• http://wmeissner.blogspot.com/

• http://groups.google.com/group/ruby-ffi

Tuesday, November 24, 2009 27


QUESTIONS?

Tuesday, November 24, 2009 28

S-ar putea să vă placă și