herokubench 0.0.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|