brabuhr / gmail.com wrote:
> I took a quick shot w/ duby-inline.
...
> ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]
>        user     system      total        real
>   18.210000   0.040000  18.250000 ( 21.596111)
...
> jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
> Server VM 1.6.0_18) [i386-java]
>    0.208000   0.000000   0.208000 (  0.208000)

That is a very impressive speed-up!

I see a more modest improvement going from the same original code (on 
different hardware of course) to a version written in redshift. Of 
course, redshift is using a more accurate integration algorithm (with 4 
substeps instead of 1). Plus there are costs for the availability of 
other features that are not being used in this example (e.g., a layer of 
function pointers so that variables can switch to different equations 
when a discrete state change occurs).

$ ruby bench-rb.rb
                   user     system      total        real
evolve 6s     0.710000   0.160000   0.870000 (  0.881276)
evolve 600s  15.320000   1.010000  16.330000 ( 16.366811)

$ ruby bench-rs.rb
                   user     system      total        real
evolve 6s     0.020000   0.000000   0.020000 (  0.025213)
evolve 600s   1.170000   0.000000   1.170000 (  1.178752)

$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]

Here are the sources:

$ cat bench-rb.rb
G = 9.8

def velocity(c, m, t, dt, vi)
   t += dt
   steps = t/dt

   i = 0
   while i < steps
     v = vi
     vi = v + ( G - c/m*v) * dt
     i += 1
   end

   vi
end

require 'benchmark'
Benchmark.bm(12) do |b|
   b.report("evolve 6s") do
     100000.times do
       velocity(0.5, 21.6, 6.0, 10.0, 0.0)
         # Note: I changed the t and dt to floats for a more direct
         # comparison with redshift, which uses floats for time values
     end
   end
   b.report("evolve 600s") do
     100000.times do
       velocity(0.5, 21.6, 600.0, 10.0, 0.0)
     end
   end
end

$ cat bench-rs.rb
require 'redshift'

class Thing < RedShift::Component
   continuous :v
   constant :m, :c, :G

   flow do
     differential " v' = G - c/m * v "
   end
end

def make_world(n)
   RedShift::World.new do |world|
     world.time_step = 10.0
     n.times do
       world.create Thing do |thing|
         thing.m = 21.6
         thing.c = 0.5
         thing.v = 0
         thing.G = 9.8
       end
     end
   end
end

require 'benchmark'
Benchmark.bm(12) do |b|
   n = 1000
   reps = 100
   # Note: instead of 100000 sequential runs, this benchmark is doing
   # 100 sequential runs of 1000 parallel instances of the same
   # integration problem, which is more typical of the conditions
   # redshift is optimized for

   world = make_world(n)
   b.report("evolve 6s") do
     reps.times do
       world.evolve 6.0
     end
   end

   world = make_world(n)
   b.report("evolve 600s") do
     reps.times do
       world.evolve 600.0
     end
   end
end