From: Dominik Bathon Date: 2006-08-01T07:45:59+09:00 Subject: Re: converting some autogenerated ruby code to C On Mon, 31 Jul 2006 23:24:08 +0200, Eric Mahurin wrote: > On 7/31/06, Dominik Bathon wrote: >> You should first try the 0.1.0 release and see if it works with your >> Ruby >> code (also read the limitations document). This version doesn't have any >> real optimizations, so the compiled code will probably only be a bit >> faster than the pure Ruby version. >> >> Once that works you can try the HEAD revision of >> svn://rubyforge.org/var/svn/ruby2cext/trunk. This new version has >> constant >> lookup caching and optimizes calls to most public methods (including >> operators) of builtin classes (Array, Bignum, FalseClass, Fixnum, Float, >> Hash, NilClass, Regexp, String, Symbol, TrueClass) that don't do >> anything >> with blocks. This can produce significant speedups depending on your >> code. >> >> I am currently thinking about doing optimizations for common iterators >> like Array/Range#each, map, ... and Fixnum#times, upto, ... which should >> yield further speedups. >> >> >> Dominik > > Thanks Dominik, > > What you have sounds quite robust and able to handle a wide variety of > ruby functionality. Unfortunately, it still doesn't help much on the > performance front :( 1-1.5X just doesn't seem like enough to justify > the effort. The main problem looks to be rb_funcall*. Yes, rb_funcall seems to be slow. That's exactly what the public builtin methods optimization tries to address, it replaces the rb_funcall with (almost) only two C calls. Have you tried the svn version? > I looked > through eval.c a little and it looks to have a large amount of > overhead before you get to the final C call (if it is a C-based > method). I'm wondering how much optimization has been done there. I > also mentioned on ruby-core that it would be quite useful to be able > to separate the method lookup from the method call in C (and ruby) to > gain additional performance when you are dealing with a variable of a > constant class. I'm sure you'd agree with the ruby2C stuff you are > doing. > > Out of curiousity, could this be used with meta-classes? I do > something like this to get self-defining methods: > > def test(a) > (class << self;self;end).class_eval( " > def test(a) > #{tester("a")} > end > " ) > test > end > def tester(a) > %Q{puts("hello " + #{a})} > end > > If I were to go down the C optimization route, I would want the > ability to convert the generated ruby (from #tester) to C and > compile/load it for this object. This is the only place I really want > a lot of optimization. I'm already doing quite a bit in my ruby code > generation and have more to go. > > If possible and you don't do it already, you might want to think about > ruby2cext replacement methods (different names) for all of the eval > methods that work on strings/files: eval, instance_eval, class_eval, > require, etc. When a compiler isn't available on the system or > something goes wrong, you could revert to the original eval methods. I think it is hard to do this transparently and efficient at the same time. You would either have to generate and compile and load a C extension for _each_ call of *eval or somehow collect all the code to eval and do it all at once (but then it probably can't be done transparently). Maybe you can generate code like: module TestDefiner def self.define_tests(instances) (class << instances[0];self;end).class_eval { def test(a) puts("hello" + a) end def test2(...) ... end ... } (class << instances[1];self;end).class_eval { def test3(...) ... end def test4(...) ... end ... } ... end end Then compile that at once to an extension, require it and call (from Ruby code): TestDefiner.define_tests([instance1, instance2, ...]) This would require some changes in your code, but I think that would be the way to go once you have decided that compiling to C is worth it. Dominik