From: Jan Wedekind Date: 2008-12-08T00:45:53+09:00 Subject: [ruby-core:20409] Re: Achieving C-like performance with more indirection? > x = 0.to_lint > for i in UBYTE(0)...UBYTE(255) > x = x + i > end I'd like to elaborate on the idea because the code shown above rather looks offensive. Here's an example what I currently can do with Ruby and libJIT: s1 = Sequence.object( 10_000 ).fill!( RGB( 2.0, 3.0, 5.0 ) ) # Sequenceobject(10000): # [RGB( 2.0, 3.0, 5.0 ), RGB( 2.0, 3.0, 5.0 ), RGB( 2.0, 3.0, 5.0 ), ....] s2 = Sequence.dfloatrgb( 10_000 ).fill!( RGB( 2.0, 3.0, 5.0 ) ) # Sequencedfloatrgb(10000): # [RGB( 2.0, 3.0, 5.0 ), RGB( 2.0, 3.0, 5.0 ), RGB( 2.0, 3.0, 5.0 ), ....] Sequence.define_injection( :addition ) { |r,x| r + x } # # Sequence.define_jit_injection( :addition ) { |r,x| r + x } # Hornetseye::Sequence s1.addition # RGB( 20000.0, 30000.0, 50000.0 ) s2.addition # RGB( 20000.0, 30000.0, 50000.0 ) t = Time.new.to_f; s1.addition; Time.new.to_f - t # 0.512867212295532 t = Time.new.to_f; s2.addition; Time.new.to_f - t # 0.0024111270904541 The code block "{ |r,x| r + x }" gets compiled by evaluating it using JITTerm-objects as parameters "r" and "x". However I can't for example apply this to a code block containing a conditional because conditional statements are static and their behaviour can't be changed: # Loading ... ready Sequence.lint( 1_000 ).indgen! # Sequencelint(1000): # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, ....] Sequence.define_injection( :maximum ) { |r,x| r > x ? r : x } # # Sequence.lint( 1_000 ).indgen!.maximum # 999 Sequence.define_jit_injection( :maximum ) { |r,x| r > x ? r : x } # Hornetseye::Sequence Sequence.lint( 1_000 ).indgen!.maximum # 0 The result of the comparison "r > x" is evaluated to a JITTerm which gives access to the JIT-variable containing the result of the comparison. Since this object is neither "false" or "nil", the code block evaluates to a piece of machine code which always returns "r". Therefore the current implementation of HornetsEye has to avoid "if-then-else" statements in this situations as well as overload parts of the Complex class which are using this as well. For similar reasons one cannot currently JIT compile the method Sequence::inject itself. class Sequence def inject( retval = nil, &action ) if retval == nil and not empty? retval = self[0] start = 1 else start = 0 end for i in start...size retval = action.call( retval, self[i] ) end retval end end I am posting this to the Ruby-core mailing list because I wonder whether there could be broader interest in this (or whether there are other plans in place already). Of course there are more instructions in Ruby one would need to think about: * control statements (if-then-else, while, unless, ... (for already maps to Range::each)) * accessing classes (String,File) * constructing constants (3,"str") * variable assignment (x=x+1) * using member variables ("@m","@@s") Of course this is not only about programming with native datatypes. If completeness in metaprogramming facilities is reached, one could implement VM optimisation such as explained in [1] without having to work on the code of the VM itself. I.e. the share of the work which has to be taken on by the VM developers for architectural reasons would be reduced! If I find the time to work on this, I could - as Paul Brannan pointed out - use something like RedParse or Ripper to implement a prototype. Without trying this out for real it is difficult for me to see what set of indirections is required at a minimum and whether this will play well with the core classes. [1] http://rubyconf2008.confreaks.com/how-ruby-can-be-fast.html