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
···
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: