benchmark-http 0.14.1 → 0.16.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
- checksums.yaml.gz.sig +0 -0
- data/lib/benchmark/http/command/concurrency.rb +18 -31
- data/lib/benchmark/http/command/hammer.rb +22 -31
- data/lib/benchmark/http/command/latency.rb +14 -27
- data/lib/benchmark/http/command/spider.rb +7 -21
- data/lib/benchmark/http/command/wait.rb +69 -0
- data/lib/benchmark/http/command.rb +9 -23
- data/lib/benchmark/http/links_filter.rb +4 -19
- data/lib/benchmark/http/seconds.rb +4 -19
- data/lib/benchmark/http/spider.rb +14 -28
- data/lib/benchmark/http/statistics.rb +20 -22
- data/lib/benchmark/http/version.rb +5 -20
- data/lib/benchmark/http.rb +4 -19
- data/license.md +21 -0
- data/readme.md +195 -0
- data.tar.gz.sig +0 -0
- metadata +59 -12
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddd680383fc595b55d77b78490c6acf5acaddf2760e3fcf61fcd852f3fb90c64
|
4
|
+
data.tar.gz: 302bf66c3fe10416e6cdffcb56dda7d57e053b864af31521877524f4a32faab3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f1c0173286d02236604f0e599aded82384936e0dfa0629e8eccfe348b8be6846cafdbc81d062655b91ee605071d471fe7c3b294f0701c8c3935107d464eec92
|
7
|
+
data.tar.gz: 65abd131693f16c9ed9c40a5b2c5e461ef33b99cf5f8fcb91d3fb7bb72d5af4723e77835b2a194839b846da35eff9d86bc0e026c3d1a6f7da4a32352449e0440
|
checksums.yaml.gz.sig
ADDED
Binary file
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative '../seconds'
|
22
7
|
require_relative '../statistics'
|
@@ -46,8 +31,7 @@ module Benchmark
|
|
46
31
|
end
|
47
32
|
|
48
33
|
def measure_performance(concurrency, endpoint, request_path)
|
49
|
-
|
50
|
-
puts "I am running #{concurrency} asynchronous tasks that will each make sequential requests..."
|
34
|
+
Console.logger.info(self, url: endpoint.url) {"I am running #{concurrency} asynchronous tasks that will each make sequential requests..."}
|
51
35
|
|
52
36
|
statistics = Statistics.new(concurrency)
|
53
37
|
task = Async::Task.current
|
@@ -64,11 +48,13 @@ module Benchmark
|
|
64
48
|
end
|
65
49
|
end.each(&:wait)
|
66
50
|
|
67
|
-
|
51
|
+
Console.logger.info(self, url: endpoint.url, concurrency: concurrency, statistics: statistics) do |buffer|
|
52
|
+
buffer.puts "I made #{statistics.count} requests in #{Seconds[statistics.sequential_duration]}. The per-request latency was #{Seconds[statistics.latency]}. That's #{statistics.per_second.round(2)} asynchronous requests/second."
|
68
53
|
|
69
|
-
|
70
|
-
|
71
|
-
|
54
|
+
buffer.puts "\t Variance: #{Seconds[statistics.variance]}"
|
55
|
+
buffer.puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
|
56
|
+
buffer.puts "\t Standard Error: #{statistics.standard_error}"
|
57
|
+
end
|
72
58
|
|
73
59
|
return statistics
|
74
60
|
end
|
@@ -77,9 +63,9 @@ module Benchmark
|
|
77
63
|
endpoint = Async::HTTP::Endpoint.parse(url)
|
78
64
|
request_path = endpoint.url.request_uri
|
79
65
|
|
80
|
-
|
66
|
+
Console.logger.info(self) {"I am going to benchmark #{url}..."}
|
81
67
|
|
82
|
-
|
68
|
+
Sync do |task|
|
83
69
|
statistics = []
|
84
70
|
minimum = @options[:minimum]
|
85
71
|
|
@@ -110,15 +96,16 @@ module Benchmark
|
|
110
96
|
end
|
111
97
|
end
|
112
98
|
|
113
|
-
|
114
|
-
|
115
|
-
|
99
|
+
Console.logger.info(self) do |buffer|
|
100
|
+
buffer.puts "Your server can handle #{statistics.last.concurrency} concurrent requests."
|
101
|
+
buffer.puts "At this level of concurrency, requests have ~#{(statistics.last.latency / statistics.first.latency).round(2)}x higher latency."
|
102
|
+
end
|
116
103
|
end
|
117
104
|
end
|
118
105
|
|
119
106
|
def call
|
120
107
|
@hosts.each do |host|
|
121
|
-
run(host)
|
108
|
+
run(host)
|
122
109
|
end
|
123
110
|
end
|
124
111
|
end
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative '../seconds'
|
22
7
|
require_relative '../statistics'
|
@@ -38,12 +23,13 @@ module Benchmark
|
|
38
23
|
option '-c/--count <integer>', "The number of requests to make per connection.", default: 10_000, type: Integer
|
39
24
|
|
40
25
|
option '-i/--interval <integer>', "The time to wait between measurements.", default: nil, type: Integer
|
26
|
+
option '--alpn-protocols <name,name>', "Force specific ALPN protocols during connection negotiation.", default: nil, type: String
|
41
27
|
end
|
42
28
|
|
43
29
|
many :urls, "The urls to hammer."
|
44
30
|
|
45
31
|
def measure_performance(concurrency, count, endpoint, request_path)
|
46
|
-
|
32
|
+
Console.logger.info(self) {"I am running #{concurrency} asynchronous tasks that will each make #{count} sequential requests..."}
|
47
33
|
|
48
34
|
statistics = Statistics.new(concurrency)
|
49
35
|
task = Async::Task.current
|
@@ -52,7 +38,7 @@ module Benchmark
|
|
52
38
|
progress_task = task.async do |child|
|
53
39
|
while true
|
54
40
|
child.sleep(1)
|
55
|
-
statistics
|
41
|
+
Console.logger.info(self, statistics)
|
56
42
|
end
|
57
43
|
end
|
58
44
|
|
@@ -72,23 +58,28 @@ module Benchmark
|
|
72
58
|
|
73
59
|
progress_task&.stop
|
74
60
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
61
|
+
Console.logger.info(self) do |buffer|
|
62
|
+
buffer.puts "I made #{statistics.count} requests in #{Seconds[statistics.sequential_duration]}. The per-request latency was #{Seconds[statistics.latency]}. That's #{statistics.per_second} asynchronous requests/second."
|
63
|
+
buffer.puts "\t Variance: #{Seconds[statistics.variance]}"
|
64
|
+
buffer.puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
|
65
|
+
buffer.puts "\t Standard Error: #{Seconds[statistics.standard_error]}"
|
66
|
+
buffer.puts statistics
|
67
|
+
end
|
81
68
|
|
82
69
|
return statistics
|
83
70
|
end
|
84
71
|
|
72
|
+
def alpn_protocols
|
73
|
+
@options[:alpn_protocols]&.split(',')
|
74
|
+
end
|
75
|
+
|
85
76
|
def run(url)
|
86
|
-
endpoint = Async::HTTP::Endpoint.parse(url)
|
77
|
+
endpoint = Async::HTTP::Endpoint.parse(url, alpn_protocols: self.alpn_protocols)
|
87
78
|
request_path = endpoint.url.request_uri
|
88
79
|
|
89
|
-
|
80
|
+
Console.logger.info(self) {"I am going to benchmark #{url}..."}
|
90
81
|
|
91
|
-
|
82
|
+
Sync do |task|
|
92
83
|
statistics = []
|
93
84
|
|
94
85
|
base = measure_performance(@options[:concurrency], @options[:count], endpoint, request_path)
|
@@ -98,7 +89,7 @@ module Benchmark
|
|
98
89
|
def call
|
99
90
|
while true
|
100
91
|
@urls.each do |url|
|
101
|
-
run(url)
|
92
|
+
run(url)
|
102
93
|
end
|
103
94
|
|
104
95
|
if @interval
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2019-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative '../seconds'
|
22
7
|
require_relative '../statistics'
|
@@ -45,7 +30,7 @@ module Benchmark
|
|
45
30
|
end
|
46
31
|
|
47
32
|
def measure_performance(concurrency, endpoint, request_path)
|
48
|
-
|
33
|
+
Console.logger.info(self) {"I am running #{concurrency} asynchronous tasks that will each make sequential requests..."}
|
49
34
|
|
50
35
|
statistics = Statistics.new(concurrency)
|
51
36
|
task = Async::Task.current
|
@@ -62,10 +47,12 @@ module Benchmark
|
|
62
47
|
end
|
63
48
|
end.each(&:wait)
|
64
49
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
Console.logger.info(self, statistics: statistics) do |buffer|
|
51
|
+
buffer.puts "I made #{statistics.count} requests in #{Seconds[statistics.sequential_duration]}. The per-request latency was #{Seconds[statistics.latency]}. That's #{statistics.per_second} asynchronous requests/second."
|
52
|
+
buffer.puts "\t Variance: #{Seconds[statistics.variance]}"
|
53
|
+
buffer.puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
|
54
|
+
buffer.puts "\t Standard Error: #{Seconds[statistics.standard_error]}"
|
55
|
+
end
|
69
56
|
|
70
57
|
return statistics
|
71
58
|
end
|
@@ -74,9 +61,9 @@ module Benchmark
|
|
74
61
|
endpoint = Async::HTTP::Endpoint.parse(url)
|
75
62
|
request_path = endpoint.url.request_uri
|
76
63
|
|
77
|
-
|
64
|
+
Console.logger.info(self) {"I am going to benchmark #{url}..."}
|
78
65
|
|
79
|
-
|
66
|
+
Sync do |task|
|
80
67
|
statistics = []
|
81
68
|
|
82
69
|
base = measure_performance(@options[:concurrency], endpoint, request_path)
|
@@ -85,7 +72,7 @@ module Benchmark
|
|
85
72
|
|
86
73
|
def call
|
87
74
|
@hosts.each do |host|
|
88
|
-
run(host)
|
75
|
+
run(host)
|
89
76
|
end
|
90
77
|
end
|
91
78
|
end
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative '../spider'
|
22
7
|
|
@@ -24,6 +9,7 @@ require 'async/await'
|
|
24
9
|
|
25
10
|
require 'samovar'
|
26
11
|
require 'uri'
|
12
|
+
require 'console'
|
27
13
|
|
28
14
|
module Benchmark
|
29
15
|
module HTTP
|
@@ -41,7 +27,7 @@ module Benchmark
|
|
41
27
|
many :urls, "One or more hosts to benchmark"
|
42
28
|
|
43
29
|
def log(method, url, response)
|
44
|
-
|
30
|
+
Console.logger.public_send(response.failure? ? :warn : :info, self) do |buffer|
|
45
31
|
buffer.puts "#{method} #{url} -> #{response.version} #{response.status} (#{response.body&.length || 'unspecified'} bytes)"
|
46
32
|
|
47
33
|
response.headers.each do |key, value|
|
@@ -55,7 +41,7 @@ module Benchmark
|
|
55
41
|
|
56
42
|
statistics = spider.call(@urls, &self.method(:log))
|
57
43
|
|
58
|
-
statistics
|
44
|
+
Console.logger.info(self, statistics: statistics)
|
59
45
|
|
60
46
|
return statistics
|
61
47
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative '../seconds'
|
7
|
+
require_relative '../statistics'
|
8
|
+
|
9
|
+
require 'async'
|
10
|
+
require 'async/barrier'
|
11
|
+
require 'async/http/client'
|
12
|
+
require 'async/http/endpoint'
|
13
|
+
|
14
|
+
require 'samovar'
|
15
|
+
|
16
|
+
module Benchmark
|
17
|
+
module HTTP
|
18
|
+
module Command
|
19
|
+
class Wait < Samovar::Command
|
20
|
+
self.description = "Measure how long it takes for an endpoint to become accessible."
|
21
|
+
|
22
|
+
options do
|
23
|
+
option '-w/--wait <time>', "The maximum wait time.", default: 10, type: Float
|
24
|
+
end
|
25
|
+
|
26
|
+
many :hosts, "The hosts to wait for."
|
27
|
+
|
28
|
+
def run(url, parent: Async::Task.current)
|
29
|
+
endpoint = Async::HTTP::Endpoint.parse(url)
|
30
|
+
request_path = endpoint.url.request_uri
|
31
|
+
maximum_wait = @options[:wait]
|
32
|
+
|
33
|
+
parent.async do
|
34
|
+
clock = Async::Clock.start
|
35
|
+
|
36
|
+
client = Async::HTTP::Client.new(endpoint)
|
37
|
+
|
38
|
+
begin
|
39
|
+
client.get(request_path).tap(&:finish)
|
40
|
+
rescue => error
|
41
|
+
if clock.total > maximum_wait
|
42
|
+
raise
|
43
|
+
else
|
44
|
+
sleep 0.01
|
45
|
+
retry
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Console.logger.info(self) {"#{url} is ready after #{clock.total} seconds."}
|
50
|
+
ensure
|
51
|
+
client.close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def call
|
56
|
+
Sync do |task|
|
57
|
+
barrier = Async::Barrier.new
|
58
|
+
|
59
|
+
@hosts.each do |host|
|
60
|
+
run(host, parent: barrier)
|
61
|
+
end
|
62
|
+
|
63
|
+
barrier.wait
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,30 +1,17 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative 'command/latency'
|
22
7
|
require_relative 'command/concurrency'
|
23
8
|
require_relative 'command/spider'
|
24
9
|
require_relative 'command/hammer'
|
10
|
+
require_relative 'command/wait'
|
25
11
|
|
26
12
|
require_relative 'version'
|
27
13
|
require 'samovar'
|
14
|
+
require 'console'
|
28
15
|
|
29
16
|
module Benchmark
|
30
17
|
module HTTP
|
@@ -47,6 +34,7 @@ module Benchmark
|
|
47
34
|
'concurrency' => Concurrency,
|
48
35
|
'spider' => Spider,
|
49
36
|
'hammer' => Hammer,
|
37
|
+
'wait' => Wait,
|
50
38
|
}
|
51
39
|
|
52
40
|
def verbose?
|
@@ -59,11 +47,9 @@ module Benchmark
|
|
59
47
|
|
60
48
|
def call
|
61
49
|
if verbose?
|
62
|
-
|
50
|
+
Console.logger.debug!
|
63
51
|
elsif quiet?
|
64
|
-
|
65
|
-
else
|
66
|
-
Async.logger.info!
|
52
|
+
Console.logger.warn!
|
67
53
|
end
|
68
54
|
|
69
55
|
if @options[:version]
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require 'trenni/sanitize'
|
22
7
|
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
module Benchmark
|
22
7
|
module HTTP
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2020-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative 'seconds'
|
22
7
|
require_relative 'statistics'
|
@@ -28,6 +13,7 @@ require 'async/http/endpoint'
|
|
28
13
|
require 'async/await'
|
29
14
|
|
30
15
|
require 'uri'
|
16
|
+
require 'console'
|
31
17
|
|
32
18
|
module Benchmark
|
33
19
|
module HTTP
|
@@ -47,7 +33,7 @@ module Benchmark
|
|
47
33
|
begin
|
48
34
|
filter = LinksFilter.parse(body)
|
49
35
|
rescue
|
50
|
-
|
36
|
+
Console.logger.error(self) {$!}
|
51
37
|
return []
|
52
38
|
end
|
53
39
|
|
@@ -65,7 +51,7 @@ module Benchmark
|
|
65
51
|
yield full_url
|
66
52
|
end
|
67
53
|
rescue ArgumentError, URI::InvalidURIError
|
68
|
-
|
54
|
+
Console.logger.warn(self) {"Could not fetch #{href}, relative to #{base}!"}
|
69
55
|
next # Don't accumulate an item into the resulting array.
|
70
56
|
end
|
71
57
|
end.compact
|
@@ -73,7 +59,7 @@ module Benchmark
|
|
73
59
|
|
74
60
|
async def fetch(statistics, client, url, depth = @depth, fetched = Set.new, &block)
|
75
61
|
if depth&.zero?
|
76
|
-
|
62
|
+
Console.logger.warn(self) {"Exceeded depth while trying to visit #{url}!"}
|
77
63
|
return
|
78
64
|
elsif fetched.include?(url)
|
79
65
|
return
|
@@ -92,11 +78,11 @@ module Benchmark
|
|
92
78
|
if response.redirection?
|
93
79
|
location = url + response.headers['location']
|
94
80
|
if location.host == url.host
|
95
|
-
|
81
|
+
Console.logger.debug(self) {"Following redirect to #{location}..."}
|
96
82
|
fetch(statistics, client, location, depth&.-(1), fetched, &block).wait
|
97
83
|
return
|
98
84
|
else
|
99
|
-
|
85
|
+
Console.logger.debug(self) {"Ignoring redirect to #{location}."}
|
100
86
|
return
|
101
87
|
end
|
102
88
|
end
|
@@ -116,10 +102,10 @@ module Benchmark
|
|
116
102
|
extract_links(url, response) do |href|
|
117
103
|
fetch(statistics, client, href, depth&.-(1), fetched, &block)
|
118
104
|
end.each(&:wait)
|
119
|
-
rescue Async::TimeoutError
|
120
|
-
|
121
|
-
rescue StandardError
|
122
|
-
|
105
|
+
rescue Async::TimeoutError => error
|
106
|
+
Console.logger.error(self, error, url: url)
|
107
|
+
rescue StandardError => error
|
108
|
+
Console.logger.error(self, error)
|
123
109
|
end
|
124
110
|
|
125
111
|
sync def call(urls, &block)
|
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require 'async/clock'
|
22
7
|
|
@@ -133,14 +118,27 @@ module Benchmark
|
|
133
118
|
end until confident?(confidence_factor)
|
134
119
|
end
|
135
120
|
|
136
|
-
def
|
121
|
+
def to_s
|
137
122
|
if self.valid?
|
138
|
-
|
123
|
+
"#{@samples.size} samples. #{per_second} requests per second. S/D: #{Seconds[standard_deviation]}."
|
139
124
|
else
|
140
|
-
|
125
|
+
"Not enough samples."
|
141
126
|
end
|
142
127
|
end
|
143
128
|
|
129
|
+
def to_json(options)
|
130
|
+
{
|
131
|
+
count: self.count,
|
132
|
+
concurrency: self.concurrency,
|
133
|
+
latency: self.latency,
|
134
|
+
standard_deviation: self.standard_deviation,
|
135
|
+
standard_error: self.standard_error,
|
136
|
+
per_second: self.per_second,
|
137
|
+
duration: self.duration,
|
138
|
+
variance: self.variance,
|
139
|
+
}.to_json(options)
|
140
|
+
end
|
141
|
+
|
144
142
|
private
|
145
143
|
|
146
144
|
def confident?(factor)
|
@@ -1,25 +1,10 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
module Benchmark
|
22
7
|
module HTTP
|
23
|
-
VERSION = "0.
|
8
|
+
VERSION = "0.16.0"
|
24
9
|
end
|
25
10
|
end
|
data/lib/benchmark/http.rb
CHANGED
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2018-2022, by Samuel Williams.
|
20
5
|
|
21
6
|
require_relative "http/version"
|
22
7
|
require_relative "http/command"
|
data/license.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# MIT License
|
2
|
+
|
3
|
+
Copyright, 2018-2022, by Samuel Williams.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/readme.md
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
# Benchmark::HTTP
|
2
|
+
|
3
|
+
An asynchronous HTTP benchmark tool built on top of [async](https://github.com/socketry/async), [async-io](https://github.com/socketry/async-io) and [async-http](https://github.com/socketry/async-http). Useful for analysing server performance. Supports HTTP1 and HTTP2.
|
4
|
+
|
5
|
+
[](https://github.com/socketry/benchmark-http/actions?workflow=Test)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install it yourself:
|
10
|
+
|
11
|
+
$ gem install benchmark-http
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
You can run `benchmark-http` is a top level tool for invoking specific benchmarks.
|
16
|
+
|
17
|
+
### Spider
|
18
|
+
|
19
|
+
This benchmark spiders a website and generates some statistics on general access time.
|
20
|
+
|
21
|
+
``` shell
|
22
|
+
$ benchmark-http spider https://www.oriontransfer.co.nz/welcome/index
|
23
|
+
HEAD https://www.oriontransfer.co.nz/welcome/index -> HTTP/2.0 404 (unspecified bytes)
|
24
|
+
GET https://www.oriontransfer.co.nz/welcome/index (depth = 10)
|
25
|
+
GET https://www.oriontransfer.co.nz/welcome/index -> HTTP/2.0 404 (2263 bytes)
|
26
|
+
HEAD https://www.oriontransfer.co.nz/products/index -> HTTP/2.0 200 (unspecified bytes)
|
27
|
+
GET https://www.oriontransfer.co.nz/products/index (depth = 9)
|
28
|
+
HEAD https://www.oriontransfer.co.nz/services/index -> HTTP/2.0 200 (unspecified bytes)
|
29
|
+
GET https://www.oriontransfer.co.nz/services/index (depth = 9)
|
30
|
+
HEAD https://www.oriontransfer.co.nz/support/index -> HTTP/2.0 200 (unspecified bytes)
|
31
|
+
GET https://www.oriontransfer.co.nz/support/index (depth = 9)
|
32
|
+
HEAD https://www.oriontransfer.co.nz/support/contact-us -> HTTP/2.0 307 (unspecified bytes)
|
33
|
+
Following redirect to https://www.oriontransfer.co.nz/support/contact-us/index...
|
34
|
+
HEAD https://www.oriontransfer.co.nz/support/terms-of-service -> HTTP/2.0 200 (unspecified bytes)
|
35
|
+
GET https://www.oriontransfer.co.nz/support/terms-of-service (depth = 9)
|
36
|
+
GET https://www.oriontransfer.co.nz/products/index -> HTTP/2.0 200 (3469 bytes)
|
37
|
+
GET https://www.oriontransfer.co.nz/services/index -> HTTP/2.0 200 (2488 bytes)
|
38
|
+
GET https://www.oriontransfer.co.nz/support/index -> HTTP/2.0 200 (2246 bytes)
|
39
|
+
HEAD https://www.oriontransfer.co.nz/support/contact-us/index -> HTTP/2.0 200 (unspecified bytes)
|
40
|
+
GET https://www.oriontransfer.co.nz/support/contact-us/index (depth = 8)
|
41
|
+
GET https://www.oriontransfer.co.nz/support/terms-of-service -> HTTP/2.0 200 (8466 bytes)
|
42
|
+
HEAD https://www.oriontransfer.co.nz/products/library-inspector/index -> HTTP/2.0 200 (unspecified bytes)
|
43
|
+
GET https://www.oriontransfer.co.nz/products/library-inspector/index (depth = 8)
|
44
|
+
HEAD https://www.oriontransfer.co.nz/products/truth-tables/index -> HTTP/2.0 200 (unspecified bytes)
|
45
|
+
GET https://www.oriontransfer.co.nz/products/truth-tables/index (depth = 8)
|
46
|
+
HEAD https://www.oriontransfer.co.nz/products/fingerprint/index -> HTTP/2.0 200 (unspecified bytes)
|
47
|
+
GET https://www.oriontransfer.co.nz/products/fingerprint/index (depth = 8)
|
48
|
+
HEAD https://www.oriontransfer.co.nz/services/internet-services -> HTTP/2.0 200 (unspecified bytes)
|
49
|
+
GET https://www.oriontransfer.co.nz/services/internet-services (depth = 8)
|
50
|
+
HEAD https://www.oriontransfer.co.nz/services/software-development -> HTTP/2.0 200 (unspecified bytes)
|
51
|
+
GET https://www.oriontransfer.co.nz/services/software-development (depth = 8)
|
52
|
+
HEAD https://www.oriontransfer.co.nz/services/systems-administration -> HTTP/2.0 200 (unspecified bytes)
|
53
|
+
GET https://www.oriontransfer.co.nz/services/systems-administration (depth = 8)
|
54
|
+
HEAD https://www.oriontransfer.co.nz/services/website-development -> HTTP/2.0 200 (unspecified bytes)
|
55
|
+
GET https://www.oriontransfer.co.nz/services/website-development (depth = 8)
|
56
|
+
HEAD https://www.oriontransfer.co.nz/support/contact-us/ -> HTTP/2.0 307 (unspecified bytes)
|
57
|
+
Following redirect to https://www.oriontransfer.co.nz/support/contact-us/index...
|
58
|
+
GET https://www.oriontransfer.co.nz/support/contact-us/index -> HTTP/2.0 200 (3094 bytes)
|
59
|
+
GET https://www.oriontransfer.co.nz/products/library-inspector/index -> HTTP/2.0 200 (5592 bytes)
|
60
|
+
GET https://www.oriontransfer.co.nz/products/truth-tables/index -> HTTP/2.0 200 (4160 bytes)
|
61
|
+
GET https://www.oriontransfer.co.nz/products/fingerprint/index -> HTTP/2.0 200 (4414 bytes)
|
62
|
+
GET https://www.oriontransfer.co.nz/services/internet-services -> HTTP/2.0 200 (3362 bytes)
|
63
|
+
GET https://www.oriontransfer.co.nz/services/software-development -> HTTP/2.0 200 (3521 bytes)
|
64
|
+
GET https://www.oriontransfer.co.nz/services/systems-administration -> HTTP/2.0 200 (2979 bytes)
|
65
|
+
GET https://www.oriontransfer.co.nz/services/website-development -> HTTP/2.0 200 (3943 bytes)
|
66
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/library-inspector/_screenshots/large/Library%20Inspector%20(Libraries).png -> HTTP/2.0 200 (unspecified bytes)
|
67
|
+
Unsupported content type: image/png
|
68
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/library-inspector/_screenshots/large/Library%20Inspector%20(Libraries%20Disassembly).png -> HTTP/2.0 200 (unspecified bytes)
|
69
|
+
Unsupported content type: image/png
|
70
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/library-inspector/_screenshots/large/Library%20Inspector%20(Libraries%20QuickLook).png -> HTTP/2.0 200 (unspecified bytes)
|
71
|
+
Unsupported content type: image/png
|
72
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/library-inspector/_screenshots/large/Library%20Inspector%20(App).png -> HTTP/2.0 200 (unspecified bytes)
|
73
|
+
Unsupported content type: image/png
|
74
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/library-inspector/_screenshots/large/Library%20Inspector%20(App%20Headers).png -> HTTP/2.0 200 (unspecified bytes)
|
75
|
+
Unsupported content type: image/png
|
76
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/truth-tables/_screenshots/large/Reformat%20Expression.png -> HTTP/2.0 200 (unspecified bytes)
|
77
|
+
Unsupported content type: image/png
|
78
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/truth-tables/_screenshots/large/Large%20Tables.png -> HTTP/2.0 200 (unspecified bytes)
|
79
|
+
Unsupported content type: image/png
|
80
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/truth-tables/_screenshots/large/Tutor.png -> HTTP/2.0 200 (unspecified bytes)
|
81
|
+
Unsupported content type: image/png
|
82
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/truth-tables/_screenshots/large/Informative%20Text.png -> HTTP/2.0 200 (unspecified bytes)
|
83
|
+
Unsupported content type: image/png
|
84
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/fingerprint/_screenshots/large/Fingerprint%20(3).png -> HTTP/2.0 200 (unspecified bytes)
|
85
|
+
Unsupported content type: image/png
|
86
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/fingerprint/_screenshots/large/Fingerprint%20(2).png -> HTTP/2.0 200 (unspecified bytes)
|
87
|
+
Unsupported content type: image/png
|
88
|
+
HEAD https://www.oriontransfer.co.nz/_gallery/products/fingerprint/_screenshots/large/Fingerprint%20(1).png -> HTTP/2.0 200 (unspecified bytes)
|
89
|
+
Unsupported content type: image/png
|
90
|
+
HEAD https://www.oriontransfer.co.nz/services/training -> HTTP/2.0 200 (unspecified bytes)
|
91
|
+
GET https://www.oriontransfer.co.nz/services/training (depth = 7)
|
92
|
+
GET https://www.oriontransfer.co.nz/services/training -> HTTP/2.0 200 (2994 bytes)
|
93
|
+
14 samples: 13x 200; 1x 404. 15.12 requests per second. S/D: 35.69ms.
|
94
|
+
```
|
95
|
+
|
96
|
+
### Concurrency
|
97
|
+
|
98
|
+
This benchmark determines the optimal level of concurrency (maximise throughput while keeping latency to a minimum).
|
99
|
+
|
100
|
+
``` shell
|
101
|
+
$ benchmark-http concurrency https://www.oriontransfer.co.nz/welcome/index
|
102
|
+
I am going to benchmark https://www.oriontransfer.co.nz/welcome/index...
|
103
|
+
I am running 1 asynchronous tasks that will each make sequential requests...
|
104
|
+
I made 273 requests in 52.4s. The per-request latency was 191.79ms. That's 5.214149911737622 asynchronous requests/second.
|
105
|
+
Variance: 997.437µs
|
106
|
+
Standard Deviation: 31.58ms
|
107
|
+
Standard Error: 0.0019114428646174592
|
108
|
+
I am running 2 asynchronous tasks that will each make sequential requests...
|
109
|
+
I made 177 requests in 16.8s. The per-request latency was 190.19ms. That's 10.51600772540387 asynchronous requests/second.
|
110
|
+
Variance: 632.076µs
|
111
|
+
Standard Deviation: 25.14ms
|
112
|
+
Standard Error: 0.001889722381767832
|
113
|
+
I am running 4 asynchronous tasks that will each make sequential requests...
|
114
|
+
I made 8 requests in 372.49ms. The per-request latency was 186.25ms. That's 21.476841588829895 asynchronous requests/second.
|
115
|
+
Variance: 0.048µs
|
116
|
+
Standard Deviation: 219.819µs
|
117
|
+
Standard Error: 7.771792696588776e-05
|
118
|
+
I am running 8 asynchronous tasks that will each make sequential requests...
|
119
|
+
I made 128 requests in 3.0s. The per-request latency was 188.10ms. That's 42.53004421587869 asynchronous requests/second.
|
120
|
+
Variance: 399.781µs
|
121
|
+
Standard Deviation: 19.99ms
|
122
|
+
Standard Error: 0.0017672840585127617
|
123
|
+
I am running 16 asynchronous tasks that will each make sequential requests...
|
124
|
+
I made 184 requests in 2.2s. The per-request latency was 188.46ms. That's 84.89938672881854 asynchronous requests/second.
|
125
|
+
Variance: 548.641µs
|
126
|
+
Standard Deviation: 23.42ms
|
127
|
+
Standard Error: 0.0017267724185582615
|
128
|
+
I am running 32 asynchronous tasks that will each make sequential requests...
|
129
|
+
I made 152 requests in 891.06ms. The per-request latency was 187.59ms. That's 170.58399627520865 asynchronous requests/second.
|
130
|
+
Variance: 335.694µs
|
131
|
+
Standard Deviation: 18.32ms
|
132
|
+
Standard Error: 0.00148610620533633
|
133
|
+
I am running 64 asynchronous tasks that will each make sequential requests...
|
134
|
+
I made 438 requests in 1.3s. The per-request latency was 191.68ms. That's 333.89790173541496 asynchronous requests/second.
|
135
|
+
Variance: 1.19ms
|
136
|
+
Standard Deviation: 34.51ms
|
137
|
+
Standard Error: 0.001648801656177374
|
138
|
+
I am running 128 asynchronous tasks that will each make sequential requests...
|
139
|
+
I made 360 requests in 533.83ms. The per-request latency was 189.81ms. That's 674.373540567776 asynchronous requests/second.
|
140
|
+
Variance: 555.212µs
|
141
|
+
Standard Deviation: 23.56ms
|
142
|
+
Standard Error: 0.0012418759009531876
|
143
|
+
I am running 256 asynchronous tasks that will each make sequential requests...
|
144
|
+
I made 512 requests in 463.03ms. The per-request latency was 231.51ms. That's 1105.762787139087 asynchronous requests/second.
|
145
|
+
Variance: 888.185µs
|
146
|
+
Standard Deviation: 29.80ms
|
147
|
+
Standard Error: 0.0013170938569343825
|
148
|
+
I am running 192 asynchronous tasks that will each make sequential requests...
|
149
|
+
I made 384 requests in 380.97ms. The per-request latency was 190.48ms. That's 1007.9615261872923 asynchronous requests/second.
|
150
|
+
Variance: 142.770µs
|
151
|
+
Standard Deviation: 11.95ms
|
152
|
+
Standard Error: 0.0006097518459132856
|
153
|
+
I am running 224 asynchronous tasks that will each make sequential requests...
|
154
|
+
I made 448 requests in 411.79ms. The per-request latency was 205.89ms. That's 1087.9398101463066 asynchronous requests/second.
|
155
|
+
Variance: 215.480µs
|
156
|
+
Standard Deviation: 14.68ms
|
157
|
+
Standard Error: 0.0006935294886115942
|
158
|
+
I am running 240 asynchronous tasks that will each make sequential requests...
|
159
|
+
I made 480 requests in 401.62ms. The per-request latency was 200.81ms. That's 1195.1473779597363 asynchronous requests/second.
|
160
|
+
Variance: 292.021µs
|
161
|
+
Standard Deviation: 17.09ms
|
162
|
+
Standard Error: 0.0007799848849992035
|
163
|
+
I am running 248 asynchronous tasks that will each make sequential requests...
|
164
|
+
I made 496 requests in 432.58ms. The per-request latency was 216.29ms. That's 1146.621534849607 asynchronous requests/second.
|
165
|
+
Variance: 446.681µs
|
166
|
+
Standard Deviation: 21.13ms
|
167
|
+
Standard Error: 0.0009489813840514241
|
168
|
+
I am running 252 asynchronous tasks that will each make sequential requests...
|
169
|
+
I made 504 requests in 417.86ms. The per-request latency was 208.93ms. That's 1206.1477638702509 asynchronous requests/second.
|
170
|
+
Variance: 222.939µs
|
171
|
+
Standard Deviation: 14.93ms
|
172
|
+
Standard Error: 0.0006650854376052381
|
173
|
+
I am running 254 asynchronous tasks that will each make sequential requests...
|
174
|
+
I made 508 requests in 419.67ms. The per-request latency was 209.83ms. That's 1210.4835614086478 asynchronous requests/second.
|
175
|
+
Variance: 177.005µs
|
176
|
+
Standard Deviation: 13.30ms
|
177
|
+
Standard Error: 0.0005902836562252991
|
178
|
+
I am running 255 asynchronous tasks that will each make sequential requests...
|
179
|
+
I made 510 requests in 434.38ms. The per-request latency was 217.19ms. That's 1174.0936493567908 asynchronous requests/second.
|
180
|
+
Variance: 457.592µs
|
181
|
+
Standard Deviation: 21.39ms
|
182
|
+
Standard Error: 0.000947227304291054
|
183
|
+
Your server can handle 255 concurrent requests.
|
184
|
+
At this level of concurrency, requests have ~1.13x higher latency.
|
185
|
+
```
|
186
|
+
|
187
|
+
## Contributing
|
188
|
+
|
189
|
+
We welcome contributions to this project.
|
190
|
+
|
191
|
+
1. Fork it.
|
192
|
+
2. Create your feature branch (`git checkout -b my-new-feature`).
|
193
|
+
3. Commit your changes (`git commit -am 'Add some feature'`).
|
194
|
+
4. Push to the branch (`git push origin my-new-feature`).
|
195
|
+
5. Create new Pull Request.
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,44 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: benchmark-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
+
- Olle Jonsson
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
|
11
|
+
cert_chain:
|
12
|
+
- |
|
13
|
+
-----BEGIN CERTIFICATE-----
|
14
|
+
MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
|
15
|
+
ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
|
16
|
+
CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
|
17
|
+
MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
|
18
|
+
MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
|
19
|
+
bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
|
20
|
+
igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
|
21
|
+
9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
|
22
|
+
sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
|
23
|
+
e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
|
24
|
+
XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
|
25
|
+
RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
|
26
|
+
tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
|
27
|
+
zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
|
28
|
+
xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
29
|
+
BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
|
30
|
+
aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
|
31
|
+
aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
|
32
|
+
cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
|
33
|
+
xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
|
34
|
+
c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
|
35
|
+
8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
|
36
|
+
JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
|
37
|
+
eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
|
38
|
+
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
39
|
+
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
40
|
+
-----END CERTIFICATE-----
|
41
|
+
date: 2022-08-28 00:00:00.000000000 Z
|
12
42
|
dependencies:
|
13
43
|
- !ruby/object:Gem::Dependency
|
14
44
|
name: async-await
|
@@ -52,6 +82,20 @@ dependencies:
|
|
52
82
|
- - "~>"
|
53
83
|
- !ruby/object:Gem::Version
|
54
84
|
version: '1.5'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: console
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :runtime
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
55
99
|
- !ruby/object:Gem::Dependency
|
56
100
|
name: samovar
|
57
101
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,7 +139,7 @@ dependencies:
|
|
95
139
|
- !ruby/object:Gem::Version
|
96
140
|
version: '0'
|
97
141
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
142
|
+
name: bake-test
|
99
143
|
requirement: !ruby/object:Gem::Requirement
|
100
144
|
requirements:
|
101
145
|
- - ">="
|
@@ -109,7 +153,7 @@ dependencies:
|
|
109
153
|
- !ruby/object:Gem::Version
|
110
154
|
version: '0'
|
111
155
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
156
|
+
name: bundler
|
113
157
|
requirement: !ruby/object:Gem::Requirement
|
114
158
|
requirements:
|
115
159
|
- - ">="
|
@@ -123,33 +167,33 @@ dependencies:
|
|
123
167
|
- !ruby/object:Gem::Version
|
124
168
|
version: '0'
|
125
169
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
170
|
+
name: covered
|
127
171
|
requirement: !ruby/object:Gem::Requirement
|
128
172
|
requirements:
|
129
173
|
- - "~>"
|
130
174
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
175
|
+
version: '0.16'
|
132
176
|
type: :development
|
133
177
|
prerelease: false
|
134
178
|
version_requirements: !ruby/object:Gem::Requirement
|
135
179
|
requirements:
|
136
180
|
- - "~>"
|
137
181
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
182
|
+
version: '0.16'
|
139
183
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
184
|
+
name: sus
|
141
185
|
requirement: !ruby/object:Gem::Requirement
|
142
186
|
requirements:
|
143
187
|
- - "~>"
|
144
188
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
189
|
+
version: '0.12'
|
146
190
|
type: :development
|
147
191
|
prerelease: false
|
148
192
|
version_requirements: !ruby/object:Gem::Requirement
|
149
193
|
requirements:
|
150
194
|
- - "~>"
|
151
195
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
196
|
+
version: '0.12'
|
153
197
|
description:
|
154
198
|
email:
|
155
199
|
executables:
|
@@ -164,11 +208,14 @@ files:
|
|
164
208
|
- lib/benchmark/http/command/hammer.rb
|
165
209
|
- lib/benchmark/http/command/latency.rb
|
166
210
|
- lib/benchmark/http/command/spider.rb
|
211
|
+
- lib/benchmark/http/command/wait.rb
|
167
212
|
- lib/benchmark/http/links_filter.rb
|
168
213
|
- lib/benchmark/http/seconds.rb
|
169
214
|
- lib/benchmark/http/spider.rb
|
170
215
|
- lib/benchmark/http/statistics.rb
|
171
216
|
- lib/benchmark/http/version.rb
|
217
|
+
- license.md
|
218
|
+
- readme.md
|
172
219
|
homepage: https://github.com/socketry/benchmark-http
|
173
220
|
licenses:
|
174
221
|
- MIT
|
@@ -188,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
235
|
- !ruby/object:Gem::Version
|
189
236
|
version: '0'
|
190
237
|
requirements: []
|
191
|
-
rubygems_version: 3.
|
238
|
+
rubygems_version: 3.3.7
|
192
239
|
signing_key:
|
193
240
|
specification_version: 4
|
194
241
|
summary: An asynchronous benchmark toolbox for modern HTTP servers.
|
metadata.gz.sig
ADDED
Binary file
|