stresser 0.3.2 → 0.4.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.
- data/HISTORY.markdown +3 -0
- data/README.markdown +4 -0
- data/Rakefile +9 -1
- data/VERSION +1 -1
- data/bin/stresser +2 -0
- data/bin/stresser-grapher +1 -1
- data/build/stresser-0.4.0.gem +0 -0
- data/lib/httperf.rb +3 -2
- data/lib/mp_perf.rb +41 -21
- data/sample.conf +2 -2
- data/spec/{httperf_output.txt → httperf_session_based_output.txt} +0 -0
- data/spec/lib/httperf_spec.rb +70 -59
- data/stresser.gemspec +5 -4
- metadata +8 -7
- data/build/stresser-0.3.2.gem +0 -0
data/HISTORY.markdown
ADDED
data/README.markdown
CHANGED
@@ -100,6 +100,10 @@ as often as you like:
|
|
100
100
|
|
101
101
|
The `{{n}}` will be replaced with the numbers 0-99.
|
102
102
|
|
103
|
+
## Tests
|
104
|
+
Run `rake spec` to run them tests. Currently, only httperf's output of a session based
|
105
|
+
replay log is parsed, but I will add more.
|
106
|
+
|
103
107
|
## Thanks
|
104
108
|
|
105
109
|
Stresser is based on igvita's autoperf driver for httperf.
|
data/Rakefile
CHANGED
@@ -47,9 +47,17 @@ task :default => :test
|
|
47
47
|
require 'rake/rdoctask'
|
48
48
|
Rake::RDocTask.new do |rdoc|
|
49
49
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
-
|
51
50
|
rdoc.rdoc_dir = 'rdoc'
|
52
51
|
rdoc.title = "stresser #{version}"
|
53
52
|
rdoc.rdoc_files.include('README*')
|
54
53
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
54
|
end
|
55
|
+
|
56
|
+
|
57
|
+
require 'spec/rake/spectask'
|
58
|
+
|
59
|
+
desc "Run all examples"
|
60
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
61
|
+
t.spec_files = FileList['spec/**/*.rb']
|
62
|
+
end
|
63
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/bin/stresser
CHANGED
data/bin/stresser-grapher
CHANGED
@@ -23,7 +23,7 @@ EOS
|
|
23
23
|
:type => String
|
24
24
|
end.merge(:csv_file => ARGV.last)
|
25
25
|
|
26
|
-
Trollop::die :output_dir,
|
26
|
+
Trollop::die :output_dir, "must be writeable" unless opts[:output_dir] and File.stat(opts[:output_dir]).writable?
|
27
27
|
Trollop::die :output_dir, "must be a directory" unless opts[:output_dir] and File.stat(opts[:output_dir]).directory?
|
28
28
|
|
29
29
|
Grapher.generate_reports(opts)
|
Binary file
|
data/lib/httperf.rb
CHANGED
@@ -2,11 +2,12 @@ module Httperf
|
|
2
2
|
extend self
|
3
3
|
|
4
4
|
def run(conf)
|
5
|
-
res = Hash
|
5
|
+
res = Hash["started at", Time.now]
|
6
|
+
|
6
7
|
httperf_opt = conf.keys.grep(/httperf/).collect {|k| "--#{k.gsub(/httperf_/, '')}=#{conf[k]}"}.join(" ")
|
7
8
|
httperf_cmd = "httperf --hog --server=#{conf['host']} --port=#{conf['port']} #{httperf_opt}"
|
8
9
|
IO.popen("#{httperf_cmd} 2>&1") do |pipe|
|
9
|
-
res
|
10
|
+
res.merge! parse_output(pipe)
|
10
11
|
|
11
12
|
# Now calculate the amount of stati per second
|
12
13
|
(1..5).each do |i|
|
data/lib/mp_perf.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'ruport'
|
3
3
|
require 'httperf'
|
4
|
+
require 'trollop'
|
5
|
+
|
4
6
|
|
5
7
|
#
|
6
8
|
# Takes command line options and attempts to make a benchmark.
|
@@ -8,29 +10,33 @@ require 'httperf'
|
|
8
10
|
class MPPerf
|
9
11
|
|
10
12
|
def initialize(opts = {})
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
opts.on( "-c", "--config FILE", String, "Your stresser configuration file with stresstest options and parameters directly passed to httperf") do |v|
|
18
|
-
@conf = parse_config(v)
|
19
|
-
end
|
20
|
-
end.parse!
|
13
|
+
parse_options
|
14
|
+
parse_config
|
15
|
+
run_suite
|
16
|
+
display_hints
|
17
|
+
end
|
21
18
|
|
22
|
-
|
19
|
+
#
|
20
|
+
# Parse command line options
|
21
|
+
#
|
22
|
+
def parse_options
|
23
|
+
@conf = Trollop::options do
|
24
|
+
banner = MPPerf.options_banner
|
25
|
+
opt :output_file, "The name of the csv file to write the results to. Warning: overwrites that file!",
|
26
|
+
:type => String
|
27
|
+
opt :config_file, "The name of the .conf file defining your testsuite. See http://github.com/moviepilot/stresser",
|
28
|
+
:type => String
|
29
|
+
end
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
puts " stresser-grapher -o #{File.expand_path(File.dirname(@output_file))} #{@output_file}"
|
27
|
-
puts ""
|
31
|
+
Trollop::die :output_file, "must be a writeable file" unless @conf[:config_file]
|
32
|
+
Trollop::die :config_file, "must be a readable file" unless @conf[:config_file]
|
28
33
|
end
|
29
34
|
|
30
35
|
#
|
31
36
|
# Taken from http://github.com/igrigorik/autoperf
|
32
37
|
#
|
33
|
-
def parse_config
|
38
|
+
def parse_config
|
39
|
+
config_file = @conf[:config_file]
|
34
40
|
raise Errno::EACCES, "#{config_file} is not readable" unless File.readable?(config_file)
|
35
41
|
|
36
42
|
conf = {}
|
@@ -56,7 +62,7 @@ class MPPerf
|
|
56
62
|
end
|
57
63
|
}
|
58
64
|
|
59
|
-
|
65
|
+
@conf.merge! conf
|
60
66
|
end
|
61
67
|
|
62
68
|
#
|
@@ -71,7 +77,7 @@ class MPPerf
|
|
71
77
|
return res
|
72
78
|
end
|
73
79
|
|
74
|
-
def
|
80
|
+
def run_suite
|
75
81
|
results = {}
|
76
82
|
report = nil
|
77
83
|
(@conf['low_rate']..@conf['high_rate']).step(@conf['rate_step']) do |rate|
|
@@ -94,9 +100,23 @@ class MPPerf
|
|
94
100
|
end
|
95
101
|
|
96
102
|
# Write csv
|
97
|
-
File.new(@output_file, "w").puts report.to_csv unless report.nil?
|
103
|
+
File.new(@conf[:output_file], "w").puts report.to_csv unless report.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
def display_hints
|
107
|
+
puts "~"*80
|
108
|
+
puts "Great, now create a graph with"
|
109
|
+
puts " stresser-grapher -o #{File.expand_path(File.dirname(@conf[:output_file]))} #{@conf[:output_file]}"
|
110
|
+
puts ""
|
98
111
|
end
|
99
|
-
end
|
100
|
-
|
101
112
|
|
113
|
+
def self.options_banner
|
114
|
+
<<BANNER
|
115
|
+
Runs a stresstest defined in a config file and write the results to a csv file.
|
102
116
|
|
117
|
+
Usage:
|
118
|
+
stresser -c my_config_file -o results.csv
|
119
|
+
where options are:
|
120
|
+
BANNER
|
121
|
+
end
|
122
|
+
end
|
data/sample.conf
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# MPPerf Configuration File
|
2
2
|
|
3
3
|
# The host, URI (relative to the document root) and port to test.
|
4
|
-
host =
|
4
|
+
host = localhost
|
5
5
|
uri = /
|
6
|
-
port =
|
6
|
+
port = 80
|
7
7
|
|
8
8
|
# The 'rate' is the number of number of connections to open per second.
|
9
9
|
# A series of tests will be conducted, starting at low rate,
|
File without changes
|
data/spec/lib/httperf_spec.rb
CHANGED
@@ -4,126 +4,137 @@ describe Httperf do
|
|
4
4
|
|
5
5
|
describe "parsing httperf output" do
|
6
6
|
|
7
|
-
before(:
|
8
|
-
@pipe = File.open("spec/
|
9
|
-
|
7
|
+
before(:each) do
|
8
|
+
@pipe = File.open("spec/httperf_session_based_output.txt")
|
9
|
+
Time.stub!(:now).and_return "Tue Nov 30 15:49:08 0100 2010"
|
10
|
+
|
11
|
+
#
|
12
|
+
# The friendly snail is greeting you!
|
13
|
+
#
|
14
|
+
IO.should_receive(:popen).and_yield @pipe
|
15
|
+
@⚋♉ = Httperf.run({})
|
10
16
|
end
|
11
17
|
|
12
18
|
it "should parse the 'Total' line correctly" do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
19
|
+
@⚋♉['conns'].should == 500
|
20
|
+
@⚋♉['requests'].should == 600
|
21
|
+
@⚋♉['replies'].should == 300
|
22
|
+
@⚋♉['duration'].should == 50.354
|
17
23
|
end
|
18
24
|
|
19
25
|
it "should parse the 'Connection rate' line correctly" do
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
@⚋♉['conn/s'].should == 9.9
|
27
|
+
@⚋♉['ms/connection'].should == 100.7
|
28
|
+
@⚋♉['concurrent connections max'].should == 8
|
23
29
|
end
|
24
30
|
|
25
31
|
it "should parse the 'Connection time' line correctly" do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
@⚋♉['conn time min'].should == 449.7
|
33
|
+
@⚋♉['conn time avg'].should == 465.1
|
34
|
+
@⚋♉['conn time max'].should == 2856.6
|
35
|
+
@⚋♉['conn time median'].should == 451.5
|
36
|
+
@⚋♉['conn time stddev'].should == 132.1
|
31
37
|
end
|
32
38
|
|
33
39
|
it "should parse the second 'Connection time' line correctly" do
|
34
|
-
|
40
|
+
@⚋♉['conn time connect'].should == 74.1
|
35
41
|
end
|
36
42
|
|
37
43
|
it "should parse the 'Connection length' line correctly" do
|
38
|
-
|
44
|
+
@⚋♉['conn length replies/conn'].should == 1.0
|
39
45
|
end
|
40
46
|
|
41
47
|
it "should parse the 'Request rate' line correctly" do
|
42
|
-
|
43
|
-
|
48
|
+
@⚋♉['req/s'].should == 9.9
|
49
|
+
@⚋♉['ms/req'].should == 100.7
|
44
50
|
end
|
45
51
|
|
46
52
|
it "should parse the 'Request size' line correctly" do
|
47
|
-
|
53
|
+
@⚋♉['request size'].should == 65.0
|
48
54
|
end
|
49
55
|
|
50
56
|
it "should parse the 'Reply rate' line correctly" do
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
57
|
+
@⚋♉['replies/s min'].should == 9.2
|
58
|
+
@⚋♉['replies/s avg'].should == 9.9
|
59
|
+
@⚋♉['replies/s max'].should == 10.0
|
60
|
+
@⚋♉['replies/s stddev'].should == 0.3
|
55
61
|
end
|
56
62
|
|
57
63
|
it "should parse the 'Reply time' line correctly" do
|
58
|
-
|
59
|
-
|
64
|
+
@⚋♉['reply time response'].should == 88.1
|
65
|
+
@⚋♉['reply time transfer'].should == 302.9
|
60
66
|
end
|
61
67
|
|
62
68
|
it "should parse the 'Reply size' line correctly" do
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
@⚋♉['reply size header'].should == 274.0
|
70
|
+
@⚋♉['reply size content'].should == 54744.0
|
71
|
+
@⚋♉['reply size footer'].should == 2.0
|
72
|
+
@⚋♉['reply size total'].should == 55020.0
|
67
73
|
end
|
68
74
|
|
69
75
|
it "should parse the 'Reply status' line correctly" do
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
@⚋♉['status 1xx'].should == 1
|
77
|
+
@⚋♉['status 2xx'].should == 500
|
78
|
+
@⚋♉['status 3xx'].should == 3
|
79
|
+
@⚋♉['status 4xx'].should == 4
|
80
|
+
@⚋♉['status 5xx'].should == 5
|
75
81
|
end
|
76
82
|
|
77
83
|
it "should parse the 'CPU time' line correctly" do
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
84
|
+
@⚋♉['cpu time user'].should == 15.65
|
85
|
+
@⚋♉['cpu time system'].should == 34.65
|
86
|
+
@⚋♉['cpu time user %'].should == 31.1
|
87
|
+
@⚋♉['cpu time system %'].should == 68.8
|
88
|
+
@⚋♉['cpu time total %'].should == 99.9
|
83
89
|
end
|
84
90
|
|
85
91
|
it "should parse the 'Net I/O' line correctly" do
|
86
|
-
|
92
|
+
@⚋♉['net i/o (KB/s)'].should == 534.1
|
87
93
|
end
|
88
94
|
|
89
95
|
it "should parse the first 'Errors' line correctly" do
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
@⚋♉['errors total'].should == 1234
|
97
|
+
@⚋♉['errors client-timo'].should == 2345
|
98
|
+
@⚋♉['errors socket-timo'].should == 3456
|
99
|
+
@⚋♉['errors connrefused'].should == 4567
|
100
|
+
@⚋♉['errors connreset'].should == 5678
|
95
101
|
end
|
96
102
|
|
97
103
|
it "should parse the second 'Errors' line correctly" do
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
104
|
+
@⚋♉['errors fd-unavail'].should == 1
|
105
|
+
@⚋♉['errors addrunavail'].should == 2
|
106
|
+
@⚋♉['errors ftab-full'].should == 3
|
107
|
+
@⚋♉['errors other'].should == 4
|
102
108
|
end
|
103
109
|
|
104
110
|
it "should parse the 'Session rate' line correctly" do
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
111
|
+
@⚋♉['session rate min'].should == 35.80
|
112
|
+
@⚋♉['session rate avg'].should == 37.04
|
113
|
+
@⚋♉['session rate max'].should == 38.20
|
114
|
+
@⚋♉['session rate stddev'].should == 0.98
|
115
|
+
@⚋♉['session rate quota'].should == "1000/1000"
|
110
116
|
end
|
111
117
|
|
112
118
|
it "should parse the 'Session' line correctly" do
|
113
|
-
|
119
|
+
@⚋♉['session avg conns/sess'].should == 2.00
|
114
120
|
end
|
115
121
|
|
116
122
|
it "should parse the 'Session lifetime' line correctly" do
|
117
|
-
|
123
|
+
@⚋♉['session lifetime [s]'].should == 0.3
|
118
124
|
end
|
119
125
|
|
120
126
|
it "should parse the 'Session failtime' line correctly" do
|
121
|
-
|
127
|
+
@⚋♉['session failtime [s]'].should == 0.0
|
122
128
|
end
|
123
129
|
|
124
130
|
it "should parse the 'Session length histogram' correctly" do
|
125
|
-
|
131
|
+
@⚋♉['session length histogram'].should == "0 0 1000"
|
126
132
|
end
|
133
|
+
|
134
|
+
it "should add a started at timestamp for each rate" do
|
135
|
+
@⚋♉['started at'].should == "Tue Nov 30 15:49:08 0100 2010"
|
136
|
+
end
|
137
|
+
|
127
138
|
end
|
128
139
|
end
|
129
140
|
|
data/stresser.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{stresser}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jannis Hermanns"]
|
12
|
-
s.date = %q{2010-11-
|
12
|
+
s.date = %q{2010-11-30}
|
13
13
|
s.description = %q{Wrapper around httperf for stresstesting your app. Runs httperf multiple times with different concurrency levels and generates an executive summary™ in .csv"}
|
14
14
|
s.email = %q{jannis@moviepilot.com}
|
15
15
|
s.executables = ["stresser", "stresser-grapher", "stresser-loggen"]
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
22
|
".gitignore",
|
23
|
+
"HISTORY.markdown",
|
23
24
|
"LICENSE",
|
24
25
|
"README.markdown",
|
25
26
|
"Rakefile",
|
@@ -27,13 +28,13 @@ Gem::Specification.new do |s|
|
|
27
28
|
"bin/stresser",
|
28
29
|
"bin/stresser-grapher",
|
29
30
|
"bin/stresser-loggen",
|
30
|
-
"build/stresser-0.
|
31
|
+
"build/stresser-0.4.0.gem",
|
31
32
|
"lib/grapher.rb",
|
32
33
|
"lib/httperf.rb",
|
33
34
|
"lib/mp_perf.rb",
|
34
35
|
"lib/reports.yml",
|
35
36
|
"sample.conf",
|
36
|
-
"spec/
|
37
|
+
"spec/httperf_session_based_output.txt",
|
37
38
|
"spec/lib/httperf_spec.rb",
|
38
39
|
"spec/lib/mp_perf_spec.rb",
|
39
40
|
"spec/spec.opts",
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stresser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jannis Hermanns
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-30 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -88,6 +88,7 @@ extra_rdoc_files:
|
|
88
88
|
files:
|
89
89
|
- .document
|
90
90
|
- .gitignore
|
91
|
+
- HISTORY.markdown
|
91
92
|
- LICENSE
|
92
93
|
- README.markdown
|
93
94
|
- Rakefile
|
@@ -95,13 +96,13 @@ files:
|
|
95
96
|
- bin/stresser
|
96
97
|
- bin/stresser-grapher
|
97
98
|
- bin/stresser-loggen
|
98
|
-
- build/stresser-0.
|
99
|
+
- build/stresser-0.4.0.gem
|
99
100
|
- lib/grapher.rb
|
100
101
|
- lib/httperf.rb
|
101
102
|
- lib/mp_perf.rb
|
102
103
|
- lib/reports.yml
|
103
104
|
- sample.conf
|
104
|
-
- spec/
|
105
|
+
- spec/httperf_session_based_output.txt
|
105
106
|
- spec/lib/httperf_spec.rb
|
106
107
|
- spec/lib/mp_perf_spec.rb
|
107
108
|
- spec/spec.opts
|
data/build/stresser-0.3.2.gem
DELETED
Binary file
|