herokubench 0.0.9 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/lib/herokubench/cli.rb +60 -134
- data/lib/herokubench/result.rb +118 -84
- data/lib/herokubench/version.rb +1 -1
- data/spec/cli_spec.rb +7 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1991f6c51c9f3abcdd15975c79aaa8cad9ab970a
|
4
|
+
data.tar.gz: 125fa53e62a2ca9189dab4af4a64fcfd1ec6f3db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23b53138b1c1ec6ed1926ebb01194b41956ff1aeaab2c10b92cd4a0cc207d9becef7f7ebd6dc39f0222d7c677f663052d271ffc21a84f34b68d1450362579e3e
|
7
|
+
data.tar.gz: 76e4c1fae840664be549815e7ae54064bf77ef21e65d8c0d03cfc882e79682da55e26be75238131ac66d8e30dcde8fc9a1bf7a336418a62737d13548eab327c5
|
data/README.md
CHANGED
@@ -8,29 +8,29 @@ A build server in the cloud, heavily inspired by Vulcan.
|
|
8
8
|
|
9
9
|
## Usage
|
10
10
|
|
11
|
-
$
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
$ hbench help
|
12
|
+
commands:
|
13
|
+
hbench ab [options] [http[s]://]hostname[:port]/path # Run apache-bench using a single one-off dyno
|
14
|
+
hbench create APP_NAME # Create your personal bench-server on Heroku
|
15
|
+
hbench help [COMMAND] # Describe available commands or one specific command
|
16
|
+
hbench multi NUMBER [options] [http[s]://]hostname[:port]/path # Run apache-bench, using multiple one-off dynos
|
17
|
+
hbench update # Updates your remote bench server
|
18
|
+
|
18
19
|
Options:
|
19
20
|
[--verbose]
|
20
21
|
|
21
22
|
|
22
|
-
|
23
23
|
## Examples
|
24
24
|
|
25
25
|
### Create a Bench Server
|
26
|
-
$
|
26
|
+
$ hbench create hbench-david
|
27
27
|
Creating hbench-david... done, stack is cedar
|
28
28
|
http://hbench-david.herokuapp.com/ | git@heroku.com:hbench-david.git
|
29
29
|
...
|
30
30
|
|
31
31
|
### Bench
|
32
32
|
|
33
|
-
$
|
33
|
+
$ hbench -c 100 -n 1000 http://nodejssimple.herokuapp.com/
|
34
34
|
Running one-off dyno, please be patient
|
35
35
|
Running `ab -c 1000 -n 10000 http://nodejssimple.herokuapp.com/` attached to terminal... up, run.4045
|
36
36
|
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
|
data/lib/herokubench/cli.rb
CHANGED
@@ -21,10 +21,9 @@ require 'herokubench/result'
|
|
21
21
|
# This class is based upon Vulcan, and copies heavily.
|
22
22
|
|
23
23
|
class HerokuBench::CLI < Thor
|
24
|
-
class_option
|
24
|
+
class_option :verbose, :type => :boolean
|
25
25
|
check_unknown_options! :except => [:ab, :multi]
|
26
26
|
default_task :ab
|
27
|
-
class_options["verbose"] = false if class_options["verbose"].nil?
|
28
27
|
Heroku.user_agent = "heroku-gem/#{Heroku::VERSION} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
|
29
28
|
Heroku::Command.load
|
30
29
|
|
@@ -45,87 +44,87 @@ class HerokuBench::CLI < Thor
|
|
45
44
|
update
|
46
45
|
end
|
47
46
|
|
48
|
-
|
49
|
-
desc "ab [options] [http[s]://]hostname[:port]/path", "Run apache-bench using a single one-off dyno"
|
47
|
+
desc "ab [options] [http[s]://]hostname[:port]/path", "Run apache-bench automatically spreading over dynos as necessary"
|
50
48
|
long_desc <<-LONGDESC
|
51
|
-
'hb ab' will run apache-bench,
|
52
|
-
|
49
|
+
'hb ab' will run apache-bench, splitting the work between up between as many dynos as necessary, for a maximum of
|
50
|
+
100 concurrent connections per dyno. The arguments are passed directly to ab.
|
53
51
|
|
54
52
|
For more information, run `hb ab help`
|
55
53
|
|
56
|
-
> $
|
54
|
+
> $ hbench ab -c 100 -n 1000 http://www.google.com
|
57
55
|
LONGDESC
|
58
56
|
|
59
57
|
def ab(*args)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
num_requests_index = args.index("-n") #hack to extract number of requests from the ab arguments.
|
59
|
+
concurrency_level_index = args.index("-c") #hack to extract number of requests from the ab arguments.
|
60
|
+
unless concurrency_level_index.nil? or num_requests_index.nil? then
|
61
|
+
num_requests = args[num_requests_index + 1].to_i
|
62
|
+
concurrency_level = args[concurrency_level_index + 1].to_i
|
63
|
+
|
64
|
+
num_dynos = (concurrency_level/100.0).ceil
|
65
|
+
num_dynos = 1 if num_dynos ==0
|
66
|
+
|
67
|
+
say "Inferred #{num_dynos} instances" if options[:verbose]
|
68
|
+
args[args.index("-n") + 1] = (num_requests / num_dynos).to_i
|
69
|
+
args[args.index("-c") + 1] = (concurrency_level / num_dynos).to_i
|
70
|
+
end
|
71
|
+
num_dynos ||= 1
|
72
|
+
multi(num_dynos, *args)
|
64
73
|
end
|
65
74
|
|
66
|
-
|
67
|
-
desc "multi NUMBER [options] [http[s]://]hostname[:port]/path", "Run apache-bench, using multiple one-off dynos"
|
75
|
+
desc "multi NUMDYNOS [options] [http[s]://]hostname[:port]/path", "Run apache-bench, using multiple one-off dynos"
|
68
76
|
long_desc <<-LONGDESC
|
69
|
-
'
|
77
|
+
'hbench multi' will run apache-bench, using a specfied number of dynos in order
|
70
78
|
to incrase the throughput of your benchmark.
|
71
79
|
|
72
80
|
The arguments are identical to that of 'hb ab' with the addition
|
73
|
-
of the '
|
81
|
+
of the 'NUMDYNOS' argument, representing the number of one-off dynos
|
74
82
|
to execute your benchmark on.
|
75
83
|
|
76
|
-
> $
|
84
|
+
> $ hbench multi 5 http://www.google.com
|
77
85
|
LONGDESC
|
78
86
|
def multi(dynos, *args)
|
79
87
|
error "no app yet, create first" unless config[:app]
|
80
88
|
error "Number of dynos must be an integer greater than 1" unless dynos.to_i >= 1
|
89
|
+
|
81
90
|
begin
|
82
|
-
|
91
|
+
say "Using #{config[:app]}" if options[:verbose]
|
92
|
+
say "Benching with #{dynos} dynos and arguments #{args}" if options[:verbose]
|
83
93
|
|
84
94
|
bencher_path = File.expand_path("../bencher.rb",__FILE__)
|
95
|
+
num_dynos = dynos.to_i
|
85
96
|
|
86
|
-
numdynos = dynos.to_i
|
87
|
-
results = []
|
88
97
|
running_procs = {}
|
89
|
-
progesses = {}
|
90
98
|
ab_command = "ab #{args.join(' ')}"
|
91
99
|
|
92
|
-
p_bar = ProgressBar.create(:title=>'Benching',:total=>
|
100
|
+
p_bar = ProgressBar.create(:title=>'Benching',:total=>1 + num_dynos*100)
|
101
|
+
summary_result = ApacheBenchSummaryResult.new
|
93
102
|
|
94
|
-
|
103
|
+
num_dynos.times do |n|
|
95
104
|
t_file = Tempfile.new("hbench_out_#{n}")
|
96
105
|
pid = spawn( "ruby #{bencher_path} \"#{ab_command} \" --app #{config[:app]}", :out=>t_file.path, :err=>null_dev)
|
106
|
+
|
97
107
|
running_procs[pid] = t_file
|
98
|
-
|
99
|
-
puts t_file.path
|
108
|
+
summary_result.add_result(ApacheBenchResult.new(t_file))
|
109
|
+
puts t_file.path if options[:verbose]
|
100
110
|
end
|
101
111
|
|
102
112
|
|
103
113
|
until running_procs.empty?
|
104
114
|
begin
|
105
|
-
complete_results = Timeout.timeout(
|
115
|
+
complete_results = Timeout.timeout(0.5) do
|
106
116
|
pid = Process.wait
|
107
|
-
|
108
|
-
p_bar.progress += num_requests - progesses[pid]
|
109
|
-
progesses[pid] = num_requests
|
117
|
+
running_procs.delete(pid)
|
110
118
|
end
|
111
119
|
rescue Timeout::Error
|
112
|
-
|
113
|
-
|
114
|
-
p_bar.progress += progress - progesses[pid]
|
115
|
-
progesses[pid] = progress
|
116
|
-
end
|
120
|
+
diff = summary_result.get_progress() - p_bar.progress
|
121
|
+
p_bar.progress+= diff
|
117
122
|
end
|
118
123
|
end
|
119
|
-
|
120
|
-
summary_result = ApacheBenchSummaryResult.new
|
121
124
|
|
122
|
-
|
123
|
-
results.each do |tfile|
|
124
|
-
summary_result.add_result(ApacheBenchResult.new(tfile))
|
125
|
-
end
|
125
|
+
p_bar.finish
|
126
126
|
summary_result.print()
|
127
127
|
|
128
|
-
|
129
128
|
rescue Interrupt
|
130
129
|
say "Exiting...Please be patient"
|
131
130
|
kill_running_procs(running_procs)
|
@@ -133,71 +132,37 @@ class HerokuBench::CLI < Thor
|
|
133
132
|
say "Done"
|
134
133
|
rescue => exception
|
135
134
|
say("HerokuBench ran into an unexpected exception. Please contact @wcdolphin",:red)
|
135
|
+
|
136
|
+
begin
|
137
|
+
kill_running_procs(running_procs)
|
138
|
+
kill_running_dynos()
|
139
|
+
rescue
|
140
|
+
end #squelch exceptions when killing procs
|
141
|
+
|
136
142
|
say(exception,:red)
|
137
143
|
puts exception.backtrace
|
138
144
|
end
|
139
145
|
end
|
140
146
|
|
141
|
-
private
|
142
147
|
|
143
|
-
# Attemptes to parse a value as a Float or integer, defaulting to the original
|
144
|
-
# string if unsuccesful.
|
145
|
-
def parse(v)
|
146
|
-
((float = Float(v)) && (float % 1.0 == 0) ? float.to_i : float) rescue v
|
147
|
-
end
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
((float = v.round(1)) && (float % 1.0 == 0) ? float.to_i.to_s : float.to_s) rescue v.to_s
|
153
|
-
end
|
154
|
-
|
155
|
-
def get_progress(tfile)
|
156
|
-
tfile.rewind
|
149
|
+
desc "update", "Updates your remote bench server"
|
150
|
+
def update
|
151
|
+
error "No app yet, create first" unless config[:app]
|
157
152
|
|
158
|
-
|
159
|
-
|
160
|
-
|
153
|
+
Dir.mktmpdir do |dir|
|
154
|
+
Dir.chdir(dir) do
|
155
|
+
system "git init -q"
|
156
|
+
system "git remote add origin git@github.com:wcdolphin/heroku-benchserver.git"
|
157
|
+
system "git remote add heroku git@#{heroku_git_domain}:#{config[:app]}.git"
|
158
|
+
pullres = capture { system "git pull --quiet origin master"}
|
159
|
+
pushres = capture { system "git push heroku master --quiet"}
|
160
|
+
end
|
161
161
|
end
|
162
|
-
progress = progress.last.to_i
|
163
162
|
end
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
# results.each do |result|
|
168
|
-
# result.each do |type, hash|
|
169
|
-
# summary[type] = {} if summary[type].nil?
|
170
|
-
# hash.each do |k,v|
|
171
|
-
# summary[type][k] = [0.0] * v.length if summary[type][k].nil?
|
172
|
-
# v.each_index do |i|
|
173
|
-
# if not @@summable_fields.index(k).nil?
|
174
|
-
# summary[type][k][i] += v[i]
|
175
|
-
# elsif not @@medianable_fields.index(k).nil?
|
176
|
-
# summary[type][k][i] += v[i] / results.length.to_f
|
177
|
-
# elsif not @@maxable_fields.index(k).nil?
|
178
|
-
# summary[type][k][i] = [v[i], summary[type][k][i]].max
|
179
|
-
# else
|
180
|
-
# summary[type][k][i] = v[i]
|
181
|
-
# end
|
182
|
-
# end
|
183
|
-
# end
|
184
|
-
# end
|
185
|
-
# end
|
186
|
-
|
187
|
-
# say "\tCumulative results, summed across dynos"
|
188
|
-
# say ""
|
189
|
-
# summary[:generic_result].each{|k,v| say format(k+":",v, 25)}
|
190
|
-
|
191
|
-
# say ""
|
192
|
-
# say "\t Connection Times (ms), median across dynos"
|
193
|
-
# say format("",["min", "mean", "[+/-sd]" ,"median","max"],15)
|
194
|
-
# summary[:connection_times].each{|k,v| say format(k+":",v, 15)}
|
195
|
-
|
196
|
-
# say ""
|
197
|
-
# say "\t Percentage of the requests served within a certain time (ms)"
|
198
|
-
# say "\t across dynos"
|
199
|
-
# summary[:response_time_cdf].each{|k,v| say format(k+"",v, 15)}
|
200
|
-
# end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
201
166
|
|
202
167
|
def kill_running_procs(running_procs)
|
203
168
|
print "Killing running processes"
|
@@ -219,45 +184,6 @@ class HerokuBench::CLI < Thor
|
|
219
184
|
end
|
220
185
|
end
|
221
186
|
|
222
|
-
def format(k,v, pad)
|
223
|
-
"#{fill(k,pad)}#{v.map{|val| fill(serialize val)}.join('')}\r\n"
|
224
|
-
end
|
225
|
-
|
226
|
-
def fill(str, length=12)
|
227
|
-
"#{str}#{" " * (length - str.length)}"
|
228
|
-
end
|
229
|
-
|
230
|
-
def get_result_hash(f)
|
231
|
-
result_hash = {}
|
232
|
-
f.each_line do |line|
|
233
|
-
@@result_type.each do |k,v|
|
234
|
-
group = line.scan(v)
|
235
|
-
if not group.nil? and group.length.equal? 1
|
236
|
-
capture = group[0].map {|v| parse v} #convert to float/int/etc
|
237
|
-
result_hash[k] = {} unless result_hash.has_key?(k)
|
238
|
-
res_key = capture[0]
|
239
|
-
res_values = capture.slice(1, capture.length)
|
240
|
-
result_hash[k][res_key] = res_values
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
result_hash
|
245
|
-
end
|
246
|
-
|
247
|
-
def update
|
248
|
-
error "no app yet, create first" unless config[:app]
|
249
|
-
|
250
|
-
Dir.mktmpdir do |dir|
|
251
|
-
Dir.chdir(dir) do
|
252
|
-
system "git init -q"
|
253
|
-
system "git remote add origin git@github.com:wcdolphin/heroku-benchserver.git"
|
254
|
-
system "git remote add heroku git@#{heroku_git_domain}:#{config[:app]}.git"
|
255
|
-
pullres = capture { system "git pull --quiet origin master"}
|
256
|
-
pushres = capture { system "git push heroku master --quiet"}
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
187
|
def capture
|
262
188
|
results = $stdout = StringIO.new
|
263
189
|
yield
|
data/lib/herokubench/result.rb
CHANGED
@@ -19,110 +19,147 @@ require 'tempfile'
|
|
19
19
|
require 'ruby-progressbar'
|
20
20
|
|
21
21
|
|
22
|
-
class BaseResult
|
22
|
+
class BaseResult < Thor
|
23
23
|
@@summable_fields = []
|
24
24
|
@@maxable_fields = []
|
25
25
|
end
|
26
26
|
|
27
27
|
class ApacheBenchResult < BaseResult
|
28
|
-
attr_accessor :result_hash
|
29
|
-
@@result_regexes = {
|
30
|
-
:connection_times=>/(.+):\s+\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)/,
|
31
|
-
:generic_result=> /^([\w\s]+):\s*([\d|\.]+)/,
|
32
|
-
:response_time_cdf=>/(\d+%)\s+(\d+)/
|
33
|
-
}
|
34
|
-
@@summable_fields = ["Complete requests","Failed requests", "Write errors", "Requests per second", "Total transferred", "HTML transferred", "Concurrency Level"]
|
35
|
-
@@averageable_fields = ["Connect", "Processing", "Waiting", "Total", "Time per request", "Time taken for tests"]
|
36
|
-
@@maxable_fields = ["50%", "66%", "75%", "80%", "90%", "95%", "98%", "99%","100%"]
|
37
|
-
|
38
|
-
def initialize(temp_file)
|
39
|
-
@result_hash = {}
|
40
|
-
|
41
|
-
temp_file.each_line do |line|
|
42
|
-
@@result_regexes.each do |type,v|
|
43
|
-
group = line.scan(v)
|
44
|
-
if not group.nil? and group.length.equal? 1
|
45
|
-
capture = group[0].map {|v| parse v} #convert to float/int/etc
|
46
|
-
res_key = capture[0]
|
47
|
-
res_values = capture.slice(1, capture.length)
|
48
|
-
|
49
|
-
@result_hash[type] = {} unless @result_hash.has_key? type
|
50
|
-
@result_hash[type][res_key] = res_values.length == 1 ? res_values[0] : res_values
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
puts @result_hash
|
55
|
-
end
|
56
28
|
|
29
|
+
attr_accessor :result_tfile
|
30
|
+
@@result_regexes = {
|
31
|
+
:connection_times=>/(.+):\s+\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)/,
|
32
|
+
:generic_result=> /^([\w\s]+):\s*([\d|\.]+)/,
|
33
|
+
:response_time_cdf=>/(\d+%)\s+(\d+)/
|
34
|
+
}
|
35
|
+
@@summable_fields = ["Complete requests","Failed requests", "Write errors", "Requests per second", "Total transferred", "HTML transferred", "Concurrency Level"]
|
36
|
+
@@averageable_fields = ["Connect", "Processing", "Waiting", "Total", "Time per request", "Time taken for tests"]
|
37
|
+
@@maxable_fields = ["50%", "66%", "75%", "80%", "90%", "95%", "98%", "99%","100%"]
|
38
|
+
|
39
|
+
no_commands do
|
40
|
+
def initialize(temp_file)
|
41
|
+
@result_tfile = temp_file
|
42
|
+
end
|
43
|
+
|
44
|
+
def result_hash()
|
45
|
+
@result_tfile.rewind
|
46
|
+
resulting_hash = {}
|
47
|
+
@result_tfile.each_line do |line|
|
48
|
+
@@result_regexes.each do |type,v|
|
49
|
+
group = line.scan(v)
|
50
|
+
if not group.nil? and group.length.equal? 1
|
51
|
+
capture = group[0].map {|v| parse v} #convert to float/int/etc
|
52
|
+
res_key = capture[0]
|
53
|
+
res_values = capture.slice(1, capture.length)
|
54
|
+
|
55
|
+
resulting_hash[type] = {} unless resulting_hash.has_key? type
|
56
|
+
resulting_hash[type][res_key] = res_values.length == 1 ? res_values.first : res_values
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
resulting_hash
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Returns the progress of this particular Dyno/Bench Result
|
66
|
+
def get_progress()
|
67
|
+
@result_tfile.rewind
|
68
|
+
progress = @result_tfile.each_line.collect do |line|
|
69
|
+
group = line.scan(/Completed (\d+) requests/)
|
70
|
+
group = group.empty? ? 0 : group[0][0]
|
71
|
+
end
|
72
|
+
progress.reject{|x| x == 0}.length * 10
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def unlink()
|
77
|
+
@result_tfile.unlink
|
78
|
+
end
|
79
|
+
end
|
57
80
|
end
|
58
81
|
|
59
82
|
class ApacheBenchSummaryResult < ApacheBenchResult
|
83
|
+
no_commands do
|
84
|
+
def initialize()
|
85
|
+
@results = []
|
86
|
+
end
|
60
87
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def add_result(ab_result)
|
66
|
-
@results.push ab_result
|
67
|
-
end
|
88
|
+
def add_result(ab_result)
|
89
|
+
@results.push ab_result
|
90
|
+
end
|
68
91
|
|
69
|
-
|
70
|
-
|
92
|
+
def get_progress()
|
93
|
+
@results.collect{|r| r.get_progress}.inject(:+)
|
94
|
+
end
|
95
|
+
|
96
|
+
def unlink()
|
97
|
+
@results.each{|r| r.unlink}
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_summary_result()
|
101
|
+
summary_result_hash = {}
|
102
|
+
@results.each do |result|
|
103
|
+
result.result_hash.each do |result_type, res_type_hashes|
|
104
|
+
summary_result_hash[result_type] = {} unless summary_result_hash.has_key? result_type
|
105
|
+
res_type_hashes.each do |result_key, value|
|
106
|
+
summary_result_hash[result_type][result_key] = [] unless summary_result_hash[result_type].has_key? result_key
|
107
|
+
summary_result_hash[result_type][result_key].push value
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
71
111
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
112
|
+
summary_result_hash.each do |result_type, result_hash|
|
113
|
+
result_hash.each do |result_name, result_values|
|
114
|
+
if @@summable_fields.include? result_name
|
115
|
+
summary_result_hash[result_type][result_name] = result_values.inject(:+)
|
116
|
+
elsif @@averageable_fields.include? result_name
|
117
|
+
summary_result_hash[result_type][result_name] = deep_average(result_values)
|
118
|
+
elsif @@maxable_fields.include? result_name
|
119
|
+
summary_result_hash[result_type][result_name] = result_values.max
|
120
|
+
else
|
121
|
+
summary_result_hash[result_type][result_name] = result_values.first
|
122
|
+
end
|
78
123
|
end
|
79
|
-
end
|
124
|
+
end
|
125
|
+
|
126
|
+
summary_result_hash
|
80
127
|
end
|
81
128
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
summary_result_hash[result_type][result_name] = result_values.max
|
90
|
-
else
|
91
|
-
summary_result_hash[result_type][result_name] = result_values.first
|
129
|
+
def print
|
130
|
+
summary = self.get_summary_result()
|
131
|
+
if summary.empty?
|
132
|
+
say("Herokubench ran into an error while executing ApacheBench. It is likely there was a syntax error in your command. Please see output below.", :red)
|
133
|
+
@results.first.result_tfile.rewind
|
134
|
+
@results.first.result_tfile.each_line do |line|
|
135
|
+
puts line
|
92
136
|
end
|
137
|
+
return
|
138
|
+
end
|
139
|
+
say("Cumulative results, summed across dynos",:bold)
|
140
|
+
summary[:generic_result].each{|k,v| printf "%-20s %s\n", k + ":",v}
|
141
|
+
|
142
|
+
say ""
|
143
|
+
say("Connection Times (ms), median across dynos",:bold)
|
144
|
+
printf "%-20s %-8s %-8s %-8s %s\n", "","min", "mean", "[+/-sd]" ,"median","max"
|
145
|
+
summary[:connection_times].each do |k,v|
|
146
|
+
printf "%-20s %-8s %-8s %-8s %s\n",k +":", v[0], v[1], v[2], v[3], v[4], v[5]
|
93
147
|
end
|
94
|
-
end
|
95
148
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# puts summary
|
102
|
-
puts "-----"
|
103
|
-
puts "\t Cumulative results, summed across dynos"
|
104
|
-
puts ""
|
105
|
-
summary[:generic_result].each{|k,v| printf "%-20s %s\n", k + ":",v}
|
106
|
-
|
107
|
-
puts ""
|
108
|
-
puts "\t Connection Times (ms), median across dynos"
|
109
|
-
printf "%-20s %-6s %-6s %-6s %s\n", "","min", "mean", "[+/-sd]" ,"median","max"
|
110
|
-
summary[:connection_times].each do |k,v|
|
111
|
-
printf "%-20s %-6s %-6s %-6s %s\n",k +":", v[0], v[1], v[2], v[3], v[4], v[5]
|
149
|
+
if summary.has_key? :response_time_cdf #valid ab results can have no result CDF if there is only one response
|
150
|
+
say ""
|
151
|
+
say("Percentage of the requests served within a certain time (ms) across dynos", :bold)
|
152
|
+
summary[:response_time_cdf].each{|k,v| printf "\t%-20s %s\n", k,v}
|
153
|
+
end
|
112
154
|
end
|
113
|
-
puts ""
|
114
|
-
puts "\t Percentage of the requests served within a certain time (ms)"
|
115
|
-
puts "\t across dynos"
|
116
|
-
summary[:response_time_cdf].each{|k,v| printf " %-20s %s\n", k,v}
|
117
|
-
|
118
155
|
end
|
119
|
-
|
120
156
|
end
|
121
157
|
|
122
158
|
|
123
159
|
|
124
160
|
private
|
125
|
-
|
161
|
+
# Parses a value as a Float or integer, defaulting to the original
|
162
|
+
# string if unsuccesful.
|
126
163
|
def parse(v)
|
127
164
|
((float = Float(v)) && (float % 1.0 == 0) ? float.to_i : float) rescue v
|
128
165
|
end
|
@@ -131,13 +168,10 @@ def deep_average(arr)
|
|
131
168
|
result = []
|
132
169
|
if not arr.empty? and arr[0].is_a? Array #we need to do a 'deep' average.
|
133
170
|
arr[0].each_index do |i|
|
134
|
-
result[i] = arr.collect {|a| a[i]/arr.length.to_f}.inject(:+)
|
171
|
+
result[i] = arr.collect {|a| a[i]/arr.length.to_f}.inject(:+).round(1)
|
135
172
|
end
|
136
173
|
result
|
137
174
|
else
|
138
|
-
arr.collect {|a| a/arr.length}.inject(:+)
|
175
|
+
arr.collect {|a| a/arr.length}.inject(:+).round(1)
|
139
176
|
end
|
140
177
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
data/lib/herokubench/version.rb
CHANGED
data/spec/cli_spec.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: herokubench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cory Dolphin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10
|
11
|
+
date: 2013-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: heroku
|
@@ -82,6 +82,7 @@ files:
|
|
82
82
|
- lib/herokubench/version.rb
|
83
83
|
- lib/herokubench.rb
|
84
84
|
- README.md
|
85
|
+
- spec/cli_spec.rb
|
85
86
|
homepage: https://github.com/wcdolphin/heroku-bench
|
86
87
|
licenses:
|
87
88
|
- MIT
|
@@ -102,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
103
|
version: '0'
|
103
104
|
requirements: []
|
104
105
|
rubyforge_project:
|
105
|
-
rubygems_version: 2.0.
|
106
|
+
rubygems_version: 2.0.6
|
106
107
|
signing_key:
|
107
108
|
specification_version: 4
|
108
109
|
summary: A gem to help load testing web applications deployed on AWS or Heroku, using
|