On 7/31/06, Dominik Bathon <dbatml / gmx.de> wrote:
> Hi Eric,
>
> On Mon, 31 Jul 2006 05:02:08 +0200, Eric Mahurin <eric.mahurin / gmail.com>
> wrote:
>
> > ruby : 19.2s
> > rubyToAnsiC : 0.7s
> >  * assumed argument was a Fixnum
> >  * converted downto iterator to a while loop
> >  * didn't handle overflow properly and use Bignum - gave wrong answer
> > rubyToRubyC : 20.9s
> >  * converted downto iterator to a while loop
> >  * 3 messages sent (rb_funcall) per iteration of the inner loop
> > hand-optimized rubyC : 14.8s
> >  * precalculated interns/symbols for method calls
> >  * reordered operands so that a constant operand was the receiver if
> > possible
> >  * used rb_funcall2 instead of rb_funcall
> > downto iterator rubyC : 15.3s
> >  * more direct translation of original ruby
> >  * used downto iterator and block (needed a couple extra helper
> > functions)
> >  * precalculated interns/symbols for method calls
> >  * one block call and one message sent per iteration of the inner loop
> >
> > For my purposes, rubyToAnsiC is pretty much useless since I need duck
> > typing on most of my arguments (can't infer the type).  I also found
> > that rubyToC wasn't very robust - simply changing n.downto(2) to
> > n.step(2,-1) broke it.  I think a more direct translation would be
> > better.  I don't see a lot of benefit from the other solutions, so
> > I'll pursue other avenues for optimization or just wait for YARV.
>
> You could try Ruby2CExtension (http://ruby2cext.rubyforge.org/), it is
> similar to rubyToRubyC but supports blocks and closures and tries to match
> Ruby's semantics as close as possible. It can handle most Ruby code.
>
> 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*.  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.