Dominik Bathon
7/31/2006 10:46:00 PM
On Mon, 31 Jul 2006 23:24:08 +0200, Eric Mahurin <eric.mahurin@gmail.com>
wrote:
> On 7/31/06, Dominik Bathon <dbatml@gmx.de> 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