Ruby Fiber Ring Benchmark

Share on FriendFeed
Posted by marco
Thu, 22 May 2008 17:51:00 GMT

I stole an exercise from the Erlang world: the ring benchmark

I used the exercise as a way to get acquainted with a new class in Ruby, Fiber (starting from the version 1.9). Fibers are a way to implement asymmetric coroutines in Ruby,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

#!/usr/bin/ruby1.9

require 'fiber'
require 'benchmark'

class Ring
   attr_reader :id
   attr_accessor :attach 

   def initialize(id)
      @id = id
      @fiber = Fiber.new do
         pass_message
      end
   end

   def |(other)
      other.attach = self if !other.nil?
      other
   end

   def resume
      @fiber.resume
    end

   def pass_message
      while message = message_in
         message_out(message)      
      end
   end

   def message_in
      @attach.resume if !@attach.nil?
   end

   def message_out(message)
      Fiber.yield(message)
   end

end

class RingStart < Ring
   attr_accessor :message
   def initialize(n, m, message)
      @m = m
      @message = message
      super(n)
   end
   
   def pass_message 
      loop { message_out(@message) }
   end

end


def create_chain_r(i, chain)
   # recursive version
   return chain if i<=0
   r = chain.nil? ? Ring.new(i) :  chain | Ring.new(i)
   create_chain(i-1, r)
end

def create_chain(n, chain)
   # loop version
   # needed to avoid stack overflow for high n
   n.downto(0) {
      chain = chain | Ring.new(n)
   }
   chain
end



n=ARGV[0].to_i
m=ARGV[1].to_i
mess=:hello
tm  = Benchmark.measure {
   ringu = RingStart.new(0, m, mess)
   chain = create_chain(n, ringu)
   m.times { ringu.message = chain.resume }
}.format("%10.6r\n").gsub!(/\(|\)/, "")

puts "#{n}, #{m}, #{tm}"
The comparison with the equivalent Erlang program is of course unfair, for one of the Erlang specialty is the spawning of cooperative processes. Anyway, here are the results:    
NMExecution Time
Ruby [ms]Erlang [ms]
10 10 1 0
10 20 2 0
10 50 4 10
10 100 10 0
10 200 18 0
10 500 42 0
10 1000 82 10
100 10 15 0
100 20 23 10
100 50 60 0
100 100 99 10
100 200 186 20
100 500 433 50
100 1000 805 90
1000 10 320 10
1000 20 423 20
1000 50 809 60
1000 100 1479 130
1000 200 2803 250
1000 500 6914 600
1000 1000 15410 1190
10000 10 16168 190
10000 20 17491 320
10000 50 21348 710
10000 100 28314 1480
10000 200 41547 2860
10000 500 81166 7200
10000 1000 147570 14190
Comments

Leave a response

  1. roger rubygemsThu, 03 Sep 2009 22:50:58 GMT

    Ok if I add this to the ruby benchmark suite? -r

Comment