small bug fix
[ebb.git] / benchmark / server_test.rb
blob0d6c0d010a88b64593d44b43c03ad57a83ba4333
1 $: << File.expand_path(File.dirname(__FILE__))
3 require 'rubygems'
4 require 'rack'
5 require 'application'
8 class Array
9   def avg
10     sum.to_f / length
11   end
12   
13   def sum
14     inject(0) { |i, s| s += i }
15   end
16   
17   def rand_each(&block)
18     sort_by{ rand }.each &block
19   end
20 end
22 class ServerTestResults
23   def self.open(filename)
24     if File.readable?(filename)
25       new(Marshal.load(File.read(filename))) 
26     else
27       new
28     end
29   end
31   def initialize(results = [])
32     @results = results
33   end
34   
35   def benchmark
36     @results.first[:benchmark]
37   end
38   
39   def write(filename='results.dump')
40     puts "writing dump file to #{filename}"
41     File.open(filename, 'w+') do |f|
42       f.write Marshal.dump(@results)
43     end
44   end
45   
46   def <<(r)
47     @results << r
48   end
49   
50   def length
51     @results.length
52   end
54   def servers
55     @results.map {|r| r[:server] }.uniq.sort
56   end
58   def data(server)
59     server_data = @results.find_all { |r| r[:server] == server }
60     ticks = server_data.map { |d| d[:input] }.uniq
61     datas = []
62     ticks.each do |c|
63       measurements = server_data.find_all { |d| d[:input] == c }.map { |d| d[:rps] }
64       datas << [c, measurements.avg]
65     end
66     datas
67   end
69 end
71 class ServerTest
72   attr_reader :name, :port, :app, :pid
73   def initialize(name, port, &start_block)
74     @name = name
75     @port = port.to_i
76   end
77   
78   def <=>(a)
79     @name <=> a.name
80   end
81   
82   def kill
83     Process.kill('KILL', @pid) if @pid
84   end
85   
86   def running?
87     !@pid.nil?
88   end
89   
90   def start
91     puts "Starting #{name}"
92     case name
93     when 'emongrel'
94       @pid = fork { start_emongrel }
95     when /^ebb(\d*)$/
96       workers = $1.to_i
97       workers = 1 if workers <= 0
98       @pid = fork { start_ebb(workers) }
99     when 'mongrel'
100       @pid = fork { start_mongrel }
101     when 'thin'
102       @pid = fork { start_thin }
103     when 'fcgi'
104       @pid = fork { start_fcgi }
105     end
106   end
107   
108   def app
109     SimpleApp.new
110   end
111   
112   def start_emongrel
113     require 'mongrel'
114     require 'swiftcore/evented_mongrel'
115     ENV['EVENT'] = "1"
116     Rack::Handler::Mongrel.run(app, :Host => '0.0.0.0', :Port => @port.to_i)
117   end
118   
119   def start_ebb(workers = 1)
120     require File.dirname(__FILE__) + '/../ruby_lib/ebb'
121     server = Ebb::start_server(app, :port => @port, :workers => workers)
122   end
123   
124   def start_mongrel
125    require 'mongrel'
126    ENV.delete('EVENT')
127    Rack::Handler::Mongrel.run(app, :Port => @port)
128   end
129   
130   def start_thin
131     require 'thin'
132     Rack::Handler::Thin.run(app, :Port => @port)
133   end
134   
135   def start_fcgi
136     Rack::Handler::FastCGI.run(app, :Port => @port)
137   end
138   
139   def trial(ab_cmd)
140     cmd = ab_cmd.sub('PORT', @port.to_s)
141     
142     puts "#{@name} (#{cmd})"
143     
144     r = %x{#{cmd}}
145     
146     return nil unless r =~ /Requests per second:\s*(\d+\.\d\d)/
147     rps = $1.to_f
148     if r =~ /Complete requests:\s*(\d+)/
149       requests_completed = $1.to_i
150     end
151     puts "   #{rps} req/sec (#{requests_completed} completed)"
152     
153     {
154       :server => @name,
155       :rps => rps,
156       :requests_completed => requests_completed,
157       :ab_cmd => cmd
158     }
159   end