Description:
load test reads site_url from command line
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r315:faf1f66729ca - - 5 files changed: 28 inserted, 182 deleted

@@ -1,7 +1,7
1 How to call
1 How to call
2 ===========
2 ===========
3
3
4 Load test for front page:
4 Load test for front page:
5
5
6 - ruby runner.rb common_visitors.rb FirstPageViewer 10 -t 10
6 + ruby runner.rb common_visitors.rb FirstPageViewer 20 -t 10 --site_url=http://localhost/cafe
7
7
@@ -1,7 +1,8
1 - visitor "FirstPageViewer" do
1 + if !defined? VISITOR_OPTION_LIST
2 - stores_cookies
2 + VISITOR_OPTION_LIST = {}
3 + end
3
4
4 - site_url "http://localhost:3000"
5 + visitor "FirstPageViewer", VISITOR_OPTION_LIST do
5 -
6 + stores_cookies
6 get "/"
7 get "/"
7 end
8 end
@@ -37,121 +37,131
37 if !FileTest.exists? TEMP_DIR
37 if !FileTest.exists? TEMP_DIR
38 Dir.mkdir TEMP_DIR
38 Dir.mkdir TEMP_DIR
39 end
39 end
40 end
40 end
41
41
42 def runner(visitor_lists, load_time=60, options={})
42 def runner(visitor_lists, load_time=60, options={})
43 visitors = []
43 visitors = []
44 vcount = 0
44 vcount = 0
45
45
46 visitor_lists.each do |cname, num|
46 visitor_lists.each do |cname, num|
47 begin
47 begin
48 c = Kernel.const_get(cname)
48 c = Kernel.const_get(cname)
49
49
50 num.times do
50 num.times do
51 visitors[vcount] = c.new(vcount+1, TEMP_DIR)
51 visitors[vcount] = c.new(vcount+1, TEMP_DIR)
52 visitors[vcount].talkative = true
52 visitors[vcount].talkative = true
53 vcount += 1
53 vcount += 1
54 end
54 end
55 rescue NameError
55 rescue NameError
56 puts "Can't find class #{cname}"
56 puts "Can't find class #{cname}"
57 show_usage
57 show_usage
58 exit(0)
58 exit(0)
59 end
59 end
60 end
60 end
61
61
62 puts "Having #{vcount} visitors"
62 puts "Having #{vcount} visitors"
63
63
64 vthread = []
64 vthread = []
65
65
66 all_start_time = Time.new
66 all_start_time = Time.new
67
67
68 # start all visitors
68 # start all visitors
69 vcount.times do |i|
69 vcount.times do |i|
70 vthread[i] = Thread.new do
70 vthread[i] = Thread.new do
71 visitors[i].run(:forever,options)
71 visitors[i].run(:forever,options)
72 end
72 end
73 end
73 end
74
74
75 # wait for load_time seconds
75 # wait for load_time seconds
76 sleep load_time
76 sleep load_time
77
77
78 visitors.each do |visitor| visitor.stop! end
78 visitors.each do |visitor| visitor.stop! end
79
79
80 all_finish_time = Time.new
80 all_finish_time = Time.new
81
81
82 begin
82 begin
83 # wait for all threads to stop
83 # wait for all threads to stop
84 vcount.times do |i|
84 vcount.times do |i|
85 #puts "Waiting for thread #{i}, #{vthread[i].alive?}"
85 #puts "Waiting for thread #{i}, #{vthread[i].alive?}"
86 vthread[i].join
86 vthread[i].join
87 end
87 end
88
88
89 rescue Interrupt
89 rescue Interrupt
90 # kill all remaining threads
90 # kill all remaining threads
91 vcount.times do |i|
91 vcount.times do |i|
92 vthread[i].kill if vthread[i].alive?
92 vthread[i].kill if vthread[i].alive?
93 end
93 end
94 end
94 end
95
95
96 # clean up
96 # clean up
97 visitors.each do |visitor|
97 visitors.each do |visitor|
98 #puts "Clean up: #{visitor.id}"
98 #puts "Clean up: #{visitor.id}"
99 visitor.cleanup
99 visitor.cleanup
100 end
100 end
101
101
102 #all_finish_time = Time.new
102 #all_finish_time = Time.new
103
103
104 total_req = 0
104 total_req = 0
105
105
106 vcount.times do |i|
106 vcount.times do |i|
107 stat = visitors[i].statistics
107 stat = visitors[i].statistics
108 # puts "TYPE: #{visitors[i].class}"
108 # puts "TYPE: #{visitors[i].class}"
109 # puts "Total requested = #{stat[:num_requested]}"
109 # puts "Total requested = #{stat[:num_requested]}"
110 # puts "Average = #{stat[:avg_request_time]}"
110 # puts "Average = #{stat[:avg_request_time]}"
111 # puts "S.D. = #{stat[:std_dev]}"
111 # puts "S.D. = #{stat[:std_dev]}"
112 total_req += stat[:num_requested]
112 total_req += stat[:num_requested]
113 end
113 end
114
114
115 elapsed_time = all_finish_time - all_start_time
115 elapsed_time = all_finish_time - all_start_time
116
116
117 puts
117 puts
118 puts "Total time = #{elapsed_time} sec."
118 puts "Total time = #{elapsed_time} sec."
119 puts "Total requests = #{total_req}"
119 puts "Total requests = #{total_req}"
120 puts "Trans. per sec = #{total_req/elapsed_time}"
120 puts "Trans. per sec = #{total_req/elapsed_time}"
121 end
121 end
122
122
123 ###########################
123 ###########################
124 # MAIN
124 # MAIN
125 ###########################
125 ###########################
126
126
127 if ARGV.length==0
127 if ARGV.length==0
128 show_usage
128 show_usage
129 exit(0)
129 exit(0)
130 end
130 end
131
131
132 visitor_file = ARGV.shift
132 visitor_file = ARGV.shift
133 - require visitor_file
134
133
135 load_time = 60
134 load_time = 60
136 dry_run = false
135 dry_run = false
137
136
138 - #build visitor list
137 + #build visitor/option list
139 visitor_list = {}
138 visitor_list = {}
139 + visitor_option_list = {}
140 while ARGV.length>0
140 while ARGV.length>0
141 key = ARGV.shift
141 key = ARGV.shift
142
142
143 case key
143 case key
144 when '-d'
144 when '-d'
145 dry_run = true
145 dry_run = true
146 when '-t'
146 when '-t'
147 num = ARGV.shift.to_i
147 num = ARGV.shift.to_i
148 load_time = num
148 load_time = num
149 else
149 else
150 - num = ARGV.shift.to_i
150 + if key =~ /--(\w+)=(.*)/
151 - visitor_list[key] = num
151 + # options
152 + lm = Regexp.last_match
153 + visitor_option_list[lm[1]] = lm[2]
154 + else
155 + # new visitor
156 + num = ARGV.shift.to_i
157 + visitor_list[key] = num
158 + end
152 end
159 end
153 end
160 end
154
161
162 + VISITOR_OPTION_LIST = visitor_option_list
163 + require visitor_file
164 +
155 initialize_temp_dir
165 initialize_temp_dir
156 runner visitor_list, load_time, {:dry_run => dry_run}
166 runner visitor_list, load_time, {:dry_run => dry_run}
157
167
@@ -27,259 +27,266
27
27
28 class << self
28 class << self
29 attr_accessor :commands
29 attr_accessor :commands
30 attr_accessor :base_url
30 attr_accessor :base_url
31 attr_accessor :cookies_stored
31 attr_accessor :cookies_stored
32 end
32 end
33
33
34 def get_cookie_fname
34 def get_cookie_fname
35 "#{@base_dir}/cookies.#{@id}"
35 "#{@base_dir}/cookies.#{@id}"
36 end
36 end
37
37
38 def get_output_fname
38 def get_output_fname
39 "#{@base_dir}/output.#{@id}"
39 "#{@base_dir}/output.#{@id}"
40 end
40 end
41
41
42 def id
42 def id
43 @id
43 @id
44 end
44 end
45
45
46 def initialize(id=0, base_dir='.')
46 def initialize(id=0, base_dir='.')
47 # initialize nil class variable
47 # initialize nil class variable
48 self.class.base_url = "" if (self.class.base_url) == nil
48 self.class.base_url = "" if (self.class.base_url) == nil
49 self.class.cookies_stored = false if self.class.cookies_stored == nil
49 self.class.cookies_stored = false if self.class.cookies_stored == nil
50
50
51 @id = id
51 @id = id
52 @base_dir = base_dir
52 @base_dir = base_dir
53 @cookies_fname = get_cookie_fname
53 @cookies_fname = get_cookie_fname
54 @output_fname = get_output_fname
54 @output_fname = get_output_fname
55 @statistics = Array.new
55 @statistics = Array.new
56 @talkative = false
56 @talkative = false
57
57
58 @stopped = false
58 @stopped = false
59 end
59 end
60
60
61 def cleanup
61 def cleanup
62 trial = 0
62 trial = 0
63 while FileTest.exists?(@cookies_fname)
63 while FileTest.exists?(@cookies_fname)
64 File.delete(@cookies_fname)
64 File.delete(@cookies_fname)
65 if FileTest.exists?(@cookies_fname)
65 if FileTest.exists?(@cookies_fname)
66 # wait until system returns
66 # wait until system returns
67 puts "STILL HERE"
67 puts "STILL HERE"
68 sleep 1
68 sleep 1
69 trial += 1
69 trial += 1
70 break if trial>10
70 break if trial>10
71 end
71 end
72 end
72 end
73
73
74 while FileTest.exists?(@output_fname)
74 while FileTest.exists?(@output_fname)
75 File.delete(@output_fname)
75 File.delete(@output_fname)
76 if FileTest.exists?(@output_fname)
76 if FileTest.exists?(@output_fname)
77 # wait until system returns
77 # wait until system returns
78 sleep 1
78 sleep 1
79 trial += 1
79 trial += 1
80 break if trial>10
80 break if trial>10
81 end
81 end
82 end
82 end
83 end
83 end
84
84
85 def self.site_url(url)
85 def self.site_url(url)
86 self.base_url = url
86 self.base_url = url
87 end
87 end
88
88
89 def self.stores_cookies
89 def self.stores_cookies
90 self.cookies_stored = true
90 self.cookies_stored = true
91 end
91 end
92
92
93 def self.preprocess_param_hash(params)
93 def self.preprocess_param_hash(params)
94 return {} if params==nil
94 return {} if params==nil
95 plist = {}
95 plist = {}
96 params.each do |key,val|
96 params.each do |key,val|
97 if key.is_a? Symbol
97 if key.is_a? Symbol
98 key_s = key.to_s
98 key_s = key.to_s
99 else
99 else
100 key_s = key
100 key_s = key
101 end
101 end
102 plist[key_s] = val
102 plist[key_s] = val
103 end
103 end
104 plist
104 plist
105 end
105 end
106
106
107 def self.get(url,params=nil)
107 def self.get(url,params=nil)
108 self.commands = [] if self.commands==nil
108 self.commands = [] if self.commands==nil
109 self.commands << {
109 self.commands << {
110 :command => :get,
110 :command => :get,
111 :url => url,
111 :url => url,
112 :params => Visitor.preprocess_param_hash(params) }
112 :params => Visitor.preprocess_param_hash(params) }
113 end
113 end
114
114
115 def self.post(url,params=nil,options=nil)
115 def self.post(url,params=nil,options=nil)
116 self.commands = [] if self.commands==nil
116 self.commands = [] if self.commands==nil
117 self.commands << { :command => :post,
117 self.commands << { :command => :post,
118 :url => url,
118 :url => url,
119 :params => Visitor.preprocess_param_hash(params),
119 :params => Visitor.preprocess_param_hash(params),
120 :options => options }
120 :options => options }
121 end
121 end
122
122
123 + def self.process_options(options)
124 + if options.has_key? "site_url"
125 + self.base_url = options["site_url"]
126 + end
127 + end
128 +
123 def substitute_id(st)
129 def substitute_id(st)
124 return st if !(st.is_a? String)
130 return st if !(st.is_a? String)
125 st.gsub(/(()|(\$))\$\{id\}/) do |s|
131 st.gsub(/(()|(\$))\$\{id\}/) do |s|
126 if s=="${id}"
132 if s=="${id}"
127 @id.to_s
133 @id.to_s
128 else
134 else
129 "${id}"
135 "${id}"
130 end
136 end
131 end
137 end
132 end
138 end
133
139
134 def encode_params(params)
140 def encode_params(params)
135 enc = ""
141 enc = ""
136 if params!=nil and params.length!=0
142 if params!=nil and params.length!=0
137 params.each do |key,val|
143 params.each do |key,val|
138 if enc != ""
144 if enc != ""
139 enc += '&'
145 enc += '&'
140 end
146 end
141 val = substitute_id(val)
147 val = substitute_id(val)
142 enc += URI.escape(key) + '=' + URI.escape(val.to_s)
148 enc += URI.escape(key) + '=' + URI.escape(val.to_s)
143 end
149 end
144 end
150 end
145 enc
151 enc
146 end
152 end
147
153
148 def get(url,params)
154 def get(url,params)
149 #build url
155 #build url
150
156
151 #puts "----------------------cookies-----------"
157 #puts "----------------------cookies-----------"
152 #system("cat #{@cookies_fname}")
158 #system("cat #{@cookies_fname}")
153 #puts "----------------------cookies-----------"
159 #puts "----------------------cookies-----------"
154
160
155 full_url = "#{self.class.base_url}#{url}"
161 full_url = "#{self.class.base_url}#{url}"
156 if params!=nil and params.length!=0
162 if params!=nil and params.length!=0
157 full_url += '?' + encode_params(params)
163 full_url += '?' + encode_params(params)
158 end
164 end
159
165
160 cmd = "curl -k -b #{@cookies_fname} -D #{@cookies_fname} #{full_url} " +
166 cmd = "curl -k -b #{@cookies_fname} -D #{@cookies_fname} #{full_url} " +
161 " -s -L -o #{@output_fname}"
167 " -s -L -o #{@output_fname}"
162 #puts ">>>>>>>>>>>>>>>>>> " + cmd
168 #puts ">>>>>>>>>>>>>>>>>> " + cmd
163 system(cmd)
169 system(cmd)
164 #system("cat #{@output_fname}")
170 #system("cat #{@output_fname}")
165 end
171 end
166
172
167 def post(url,params,options)
173 def post(url,params,options)
168 #puts "----------------------cookies-----------"
174 #puts "----------------------cookies-----------"
169 #system("cat #{@cookies_fname}")
175 #system("cat #{@cookies_fname}")
170 #puts "----------------------cookies-----------"
176 #puts "----------------------cookies-----------"
171
177
172 full_url = "#{self.class.base_url}#{url}"
178 full_url = "#{self.class.base_url}#{url}"
173 params_str = ""
179 params_str = ""
174 if options!=nil and options[:multipart]==true
180 if options!=nil and options[:multipart]==true
175 params.each do |key,val|
181 params.each do |key,val|
176 if val.is_a? Hash
182 if val.is_a? Hash
177 case val[:type]
183 case val[:type]
178 when :file
184 when :file
179 dval = substitute_id(val[:data])
185 dval = substitute_id(val[:data])
180 params_str += " -F \"#{key}=@#{dval.to_s}\""
186 params_str += " -F \"#{key}=@#{dval.to_s}\""
181 end
187 end
182 else
188 else
183 val = substitute_id(val)
189 val = substitute_id(val)
184 params_str += " -F \"#{key}=#{URI.escape(val.to_s)}\""
190 params_str += " -F \"#{key}=#{URI.escape(val.to_s)}\""
185 end
191 end
186 end
192 end
187 else
193 else
188 params_str += "-d \"#{encode_params(params)}\""
194 params_str += "-d \"#{encode_params(params)}\""
189 end
195 end
190
196
191 #puts params_str
197 #puts params_str
192
198
193 cmd = "curl -L -k -b #{@cookies_fname} -D #{@cookies_fname} " +
199 cmd = "curl -L -k -b #{@cookies_fname} -D #{@cookies_fname} " +
194 " #{params_str} #{full_url} -s -o #{@output_fname}"
200 " #{params_str} #{full_url} -s -o #{@output_fname}"
195 #puts ">>>>>>>>>>>>>>>>>>>>>>>>>>> POST: " + cmd
201 #puts ">>>>>>>>>>>>>>>>>>>>>>>>>>> POST: " + cmd
196 system(cmd)
202 system(cmd)
197 #system("cat #{@output_fname}")
203 #system("cat #{@output_fname}")
198 end
204 end
199
205
200 def stop!
206 def stop!
201 @stopped = true
207 @stopped = true
202 end
208 end
203
209
204 def run(times=nil, options={})
210 def run(times=nil, options={})
205 times = 1 if times == :once
211 times = 1 if times == :once
206
212
207 @stopped = false
213 @stopped = false
208 while times!=0
214 while times!=0
209 self.class.commands.each do |cmd|
215 self.class.commands.each do |cmd|
210 puts "#{@id}: #{cmd[:command]} #{cmd[:url]}" if @talkative
216 puts "#{@id}: #{cmd[:command]} #{cmd[:url]}" if @talkative
211
217
212 start_time = Time.new
218 start_time = Time.new
213
219
214 if !options[:dry_run]
220 if !options[:dry_run]
215 case cmd[:command]
221 case cmd[:command]
216 when :get
222 when :get
217 get cmd[:url], cmd[:params]
223 get cmd[:url], cmd[:params]
218 when :post
224 when :post
219 post cmd[:url], cmd[:params], cmd[:options]
225 post cmd[:url], cmd[:params], cmd[:options]
220 end
226 end
221 end
227 end
222
228
223 finish_time = Time.new
229 finish_time = Time.new
224
230
225 break if @stopped
231 break if @stopped
226
232
227 @statistics << {
233 @statistics << {
228 :url => "#{cmd[:command]}:#{cmd[:url]}",
234 :url => "#{cmd[:command]}:#{cmd[:url]}",
229 :time => finish_time - start_time }
235 :time => finish_time - start_time }
230 end
236 end
231
237
232 times -= 1 if times.is_a? Integer #otherwise, run forever
238 times -= 1 if times.is_a? Integer #otherwise, run forever
233
239
234 break if @stopped
240 break if @stopped
235 end
241 end
236 end
242 end
237
243
238 def show_raw_stat
244 def show_raw_stat
239 @statistics.each do |stat|
245 @statistics.each do |stat|
240 puts "#{stat[:url]} => #{stat[:time]}"
246 puts "#{stat[:url]} => #{stat[:time]}"
241 end
247 end
242 end
248 end
243
249
244 def statistics
250 def statistics
245 num_requested = @statistics.length
251 num_requested = @statistics.length
246 totaltime = 0.0
252 totaltime = 0.0
247 @statistics.each { |stat| totaltime += stat[:time] }
253 @statistics.each { |stat| totaltime += stat[:time] }
248
254
249 if num_requested>0
255 if num_requested>0
250 average_request_time = totaltime / num_requested
256 average_request_time = totaltime / num_requested
251 else
257 else
252 average_request_time = 0
258 average_request_time = 0
253 end
259 end
254
260
255 sq_sum = 0.0
261 sq_sum = 0.0
256 @statistics.each do |stat|
262 @statistics.each do |stat|
257 sq_sum += (stat[:time]-average_request_time) ** 2
263 sq_sum += (stat[:time]-average_request_time) ** 2
258 end
264 end
259 if num_requested>1
265 if num_requested>1
260 sd = Math.sqrt(sq_sum/(num_requested-1))
266 sd = Math.sqrt(sq_sum/(num_requested-1))
261 else
267 else
262 sd = 0
268 sd = 0
263 end
269 end
264
270
265 return {
271 return {
266 :num_requested => num_requested,
272 :num_requested => num_requested,
267 :avg_request_time => average_request_time,
273 :avg_request_time => average_request_time,
268 :std_dev => sd
274 :std_dev => sd
269 }
275 }
270 end
276 end
271 end
277 end
272
278
273 - def visitor(cname,&blk)
279 + def visitor(cname,options={},&blk)
274 c = Class.new(Visitor)
280 c = Class.new(Visitor)
275 begin
281 begin
276 Object.const_set(cname,c)
282 Object.const_set(cname,c)
277 rescue NameError
283 rescue NameError
278 puts <<ERROR
284 puts <<ERROR
279 Error on type #{cname}.
285 Error on type #{cname}.
280 Type name should be capitalized and follow Ruby constant naming rule.
286 Type name should be capitalized and follow Ruby constant naming rule.
281 ERROR
287 ERROR
282 exit(0)
288 exit(0)
283 end
289 end
290 + c.process_options(options)
284 c.instance_eval(&blk)
291 c.instance_eval(&blk)
285 end
292 end
deleted file
You need to be logged in to leave comments. Login now