File reorganization
[ebb.git] / benchmark / server_test.rb
blobc44c041b3bbc8e872bc97bb6282f2b3ec7b5aecb
1 $: << File.expand_path(File.dirname(__FILE__) + '/..')
3 require 'rubygems'
4 require 'rack'
5 require 'application'
7 module Bytes
8   def bytes
9     self
10   end
11   alias :byte :bytes
13   def kilobytes
14     self * 1024
15   end
16   alias :kilobyte :kilobytes
18   def megabytes
19     self * 1024.kilobytes
20   end
21   alias :megabyte :megabytes
23   def gigabytes
24     self * 1024.megabytes 
25   end
26   alias :gigabyte :gigabytes
28   def terabytes
29     self * 1024.gigabytes
30   end
31   alias :terabyte :terabytes
32   
33   def petabytes
34     self * 1024.terabytes
35   end
36   alias :petabyte :petabytes
37   
38   def exabytes
39     self * 1024.petabytes
40   end
41   alias :exabyte :exabytes
42   
43 end
44 class Fixnum
45   include Bytes
46 end
48 def number_to_human_size(size, precision=1)
49   size = Kernel.Float(size)
50   case
51     when size.to_i == 1;    "1 Byte"
52     when size < 1.kilobyte; "%d Bytes" % size
53     when size < 1.megabyte; "%.#{precision}f KB"  % (size / 1.0.kilobyte)
54     when size < 1.gigabyte; "%.#{precision}f MB"  % (size / 1.0.megabyte)
55     when size < 1.terabyte; "%.#{precision}f GB"  % (size / 1.0.gigabyte)
56     else                    "%.#{precision}f TB"  % (size / 1.0.terabyte)
57   end.sub(/([0-9])\.?0+ /, '\1 ' )
58 rescue
59   nil
60 end
62 class Array
63   def avg
64     sum.to_f / length
65   end
66   
67   def sum
68     inject(0) { |i, s| s += i }
69   end
70   
71   def rand_each(&block)
72     sort_by{ rand }.each &block
73   end
74 end
76 class ServerTestResults
77   def self.open(filename)
78     if File.readable?(filename)
79       new(Marshal.load(File.read(filename))) 
80     else
81       new
82     end
83   end
85   def initialize(results = [])
86     @results = results
87   end
88   
89   def write(filename='results.dump')
90     puts "writing dump file to #{filename}"
91     File.open(filename, 'w+') do |f|
92       f.write Marshal.dump(@results)
93     end
94   end
95   
96   def <<(r)
97     @results << r
98   end
99   
100   def length
101     @results.length
102   end
104   def servers
105     @results.map {|r| r[:server] }.uniq.sort
106   end
108   def data(server, what=:size)
109     server_data = @results.find_all { |r| r[:server] == server }
110     ticks = server_data.map { |d| d[what] }.uniq
111     datas = []
112     ticks.each do |c|
113       measurements = server_data.find_all { |d| d[what] == c }.map { |d| d[:rps] }
114       datas << [c, measurements.avg]
115     end
116     datas
117   end
121 class ServerTest
122   attr_reader :name, :port, :app, :pid
123   def initialize(name, port, &start_block)
124     @name = name
125     @port = port
126     @start_block = start_block
127   end
128   
129   def <=>(a)
130     @name <=> a.name
131   end
132   
133   def kill
134     Process.kill('KILL', @pid)
135   end
136   
137   def running?
138     !@pid.nil?
139   end
140   
141   def start
142     puts "Starting #{name}"
143     @pid = fork { @start_block.call }
144   end
145   
146   def trial(options = {})
147     concurrency = options[:concurrency] || 50
148     size = options[:size] || 20 * 1.kilobyte
149     requests = options[:requests] || 500
150     
151     print "#{@name} (c=#{concurrency},s=#{size})  "
152     $stdout.flush
153     r = %x{ab -t 3 -q -c #{concurrency} http://0.0.0.0:#{@port}/bytes/#{size}}
154     # Complete requests:      1000
156     return nil unless r =~ /Requests per second:\s*(\d+\.\d\d)/
157     rps = $1.to_f
158     if r =~ /Complete requests:\s*(\d+)/
159       completed_requests = $1.to_i
160     end
161     puts "#{rps} req/sec (#{completed_requests} completed)"
162     {
163       :test => 'get',
164       :server=> @name, 
165       :concurrency => concurrency, 
166       :size => size,
167       :rps => rps,
168       :requests => requests,
169       :requests_completed => completed_requests,
170       :time => Time.now
171     }
172   end
173   
174   def wait_trial(wait, concurrency = 50)
175     
176     print "#{@name} (c=#{concurrency},wait=#{wait})  "
177     $stdout.flush
178     r = %x{ab -t #{wait*3} -q -c #{concurrency} http://0.0.0.0:#{@port}/periodical_activity/fibonacci/#{wait}}
179     # Complete requests:      1000
181     return nil unless r =~ /Requests per second:\s*(\d+\.\d\d)/
182     rps = $1.to_f
183     if r =~ /Complete requests:\s*(\d+)/
184       completed_requests = $1.to_i
185     end
186     puts "#{rps} req/sec (#{completed_requests} completed)"
187     {
188       :test => 'get',
189       :server=> @name, 
190       :concurrency => concurrency,
191       :wait => wait,
192       :rps => rps,
193       :requests_completed => completed_requests,
194       :time => Time.now
195     }
196   end
197   
199   def post_trial(size = 1, concurrency = 10)
200     
201     print "#{@name} (c=#{concurrency},posting=#{size})  "
202     $stdout.flush
203     
204     fn = "/tmp/ebb_post_trial_#{size}"
205     unless FileTest.exists?(fn)
206       File.open(fn, 'w+') { |f| f.write("C"*size) }
207     end
208     
209     r = %x{ab -t 6 -q -c #{concurrency} -p #{fn} http://0.0.0.0:#{@port}/test_post_length}
210     
211     return nil unless r =~ /Requests per second:\s*(\d+\.\d\d)/
212     rps = $1.to_f
213     if r =~ /Complete requests:\s*(\d+)/
214       completed_requests = $1.to_i
215     end
216     puts "#{rps} req/sec (#{completed_requests} completed)"
217     {
218       :test => 'camping1',
219       :server=> @name, 
220       :concurrency => concurrency, 
221       :size => size,
222       :rps => rps,
223       :requests_completed => completed_requests,
224       :time => Time.now
225     }
226   end
227   
230 $servers = []
231 app = SimpleApp.new
232 $servers << ServerTest.new('evented mongrel', 4001) do
233   require 'mongrel'
234   require 'swiftcore/evented_mongrel'
235   ENV['EVENT'] = "1"
236   Rack::Handler::Mongrel.run(app, :Port => 4001)
239 $servers << ServerTest.new('ebb', 4002) do
240   require File.dirname(__FILE__) + '/../ruby_lib/ebb'
241   server = Ebb::Server.new(app, :port => 4002)
242   server.start
245 $servers << ServerTest.new('mongrel', 4003) do
246  require 'mongrel'
247  Rack::Handler::Mongrel.run(app, :Port => 4003)
250 $servers << ServerTest.new('thin', 4004) do
251   require 'thin'
252   Rack::Handler::Thin.run(app, :Port => 4004)