I have a Rails application that should show the results of the Monte Carlo simulator, and for the first time, Ruby is simply not fast enough for my needs. So, I started digging around to see if I could rewrite my simulation in C and use these results in Ruby, and some googling turned RubyInline gem to easily write faster C code directly in Ruby. Simple things work fine, for example, some basic functions written in both Ruby and C:
class FasterFunctions inline do |builder| builder.c ' double rand_sum(int trials) { double sum = 0.0; for (int i = 0; i<trials; i++) { sum += (double)rand()/(double)RAND_MAX; } return sum; }' builder.c ' long loop_sum(long trials) { long sum = 0; for (long i = 0; i<trials; i++) { sum+=i; } return sum; }' end end #the C version is 4 orders of magnitude faster trials = 1_000_000 ruby_sum = 0 trials.times {|i| ruby_sum += i} c_sum = FasterRand.new.loop_sum(trials) # the C version is 1 order of magnitude faster ruby_sum = 0.0 trials.times {ruby_sum += rand} c_sum = FasterRand.new.rand_sum(trials)
So great, this will definitely speed up my sim, as it pretty much just generates random numbers and adds stuff based on these results. Unfortunately, besides basic things like this, I can't figure out how to write my program. I need to pass some structures in order to act as state variables, so the first order of business is figuring out how to create a C structure. Reading the documentation seems to be pretty simple.
accessor (method, type, member = method)
Adds a reader and writer for a C structure element wrapped through Data_Wrap_Struct. method is the name of the ruby ββthat the accessory gives, type is type C. If member name C is not redefined by member, the method name is used as a member of the structure.
builder.struct_name = 'MyStruct' builder.accessor :title, 'char *' builder.accessor :stream_index, 'int', :index
I donβt quite understand the documentation, but I assume that I put it in a class similar to the previous one and do something like the following to access it:
class MyStructClass inline do |builder| builder.struct_name = 'MyStruct' builder.accessor :title, 'char *' builder.accessor :stream_index, 'int', :index end end
Sorry, I can't even go this far
.* / rbenv / version / 2.1.2 / Library / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 456: 3: Error: using an undeclared identifier Pointer MyStruct MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 456: 13: error: using an undeclared identifier pointer "pointer" MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 458: 35: error: use of undeclared identifier 'pointer' Data_Get_Struct (self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 458: 25: error: using the undeclared identifier 'MyStruct' Data_Get_Struct (self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^. * / Rbenv / version / 2.1.2 / Library / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 458: 3: error: expected expression Data_Get_Struct (self, MyStruct, pointer ); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 460: 23: error: using an undeclared identifier Returning a pointer (rb_str_new2 (pointer- > title)); ^ * /. rbenv / versions / 2.1.2 / include / ruby-2.1.0 / ruby ββ/intern.h: 786: 27: note: extended from the macro 'rb_str_new_cstr' (__builtin_constant_p (str))? \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 460: 23: error: use of undeclared identifier 'pointer' * /. rbenv / versions / 2.1.2 / include / ruby-2.1.0 / ruby ββ/intern.h: 787: 14: note: extended from the macro 'rb_str_new_cstr' rb_str_new ((str), (long) strlen (str)) : \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 460: 23: error: use of undeclared identifier 'pointer' * /. rbenv / versions / 2.1.2 / include / ruby-2.1.0 / ruby ββ/intern.h: 787: 33: note: extended from the macro 'rb_str_new_cstr' rb_str_new ((str), (long) strlen (str)) : \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 460: 23: error: use of undeclared identifier 'pointer' * /. rbenv / versions / 2.1.2 / include / ruby-2.1.0 / ruby ββ/intern.h: 788: 18: note: extended from the macro 'rb_str_new_cstr' rb_str_new_cstr (str); \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 460: 10: error: returning 'void' from a function with an incompatible result type "VALUE" (aka "unsigned long") return (rb_str_new2 (pointer-> title)); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~. * / Rbenv / version / 2.1.2 / Lib / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 478: 3: Error: using an undeclared identifier Pointer MyStruct MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 478: 13: error: use of undeclared identifier pointer "pointer" MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 480: 35: error: use of undeclared identifier 'pointer' Data_Get_Struct (self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 480: 25: error: using undeclared identifier 'MyStruct' Data_Get_Struct (self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^. * / Rbenv / version / 2.1.2 / Lib / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 480: 3: error: expected expression Data_Get_Struct (self, MyStruct, pointer ); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby /ruby.h: 1038: 20: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj) ; \ ^. * / Rbenv / version / 2.1.2 / Lib / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 482: 3: Error: using undeclared identifier 'pointer' pointer-> title = StringValuePtr (value); ^. * / Rbenv / version / 2.1.2 / Lib / ruby ββ/ stones / 2.1.0 / gems / RubyInline -3.12.4 / Library / inline.rb: 456: 3: Error: using an undeclared identifier Pointer MyStruct MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 456: 13: error: using an undeclared identifier pointer "pointer" MyStruct *; ^ * /. rbenv / versions / 2.1.2 / lib / ruby ββ/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb: 458: 35: error: use of undeclared identifier 'pointer' Data_Get_Struct (self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: extended from the macro 'Data_Get_Struct' (sval) = (type) DATA_PTR (obj); \ ^ fatal error: too many errors have been emitted, now stops [-ferror-limit =]
I did a bunch of googling, but almost every example I found relates only to the simple use case that I set out at the beginning. The first error he sent was that MyStruct was not declared, so I tried to add a structure definition before the access methods, for example:
builder.c ' typedef struct { char *title; int index; } MyStruct; '
This does nothing, and the documentation seems clear that the c method is only for declaring functions, not structures. I'm not quite sure what to try next, does anyone else have experience with this?