benchmark-http 0.14.1 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7b898f9431f2e00f2635eb1c4defb390f458faa1b5cce000834a1b5b338501e
4
- data.tar.gz: 7f145d3680f1454aa57d328d9a9af5c8f5d342ec24c41d2494f2486fb6fb2119
3
+ metadata.gz: ddd680383fc595b55d77b78490c6acf5acaddf2760e3fcf61fcd852f3fb90c64
4
+ data.tar.gz: 302bf66c3fe10416e6cdffcb56dda7d57e053b864af31521877524f4a32faab3
5
5
  SHA512:
6
- metadata.gz: 3dbe27cd285207090193134aec7e7fcd94fef8263742dee41ec53c61ab8dd65998b6339ee02ae6c4e51bf03533350397076b44c41802f2986aea6874f767cd35
7
- data.tar.gz: c85924364c69f467af407752313f22a6fd2eeb56b18df2ac3450e9c2b10758dc7cc1bb3a8f8fb30579769799451d9bfa75c09ba82c204b4250306f25c30c2b0d
6
+ metadata.gz: 2f1c0173286d02236604f0e599aded82384936e0dfa0629e8eccfe348b8be6846cafdbc81d062655b91ee605071d471fe7c3b294f0701c8c3935107d464eec92
7
+ data.tar.gz: 65abd131693f16c9ed9c40a5b2c5e461ef33b99cf5f8fcb91d3fb7bb72d5af4723e77835b2a194839b846da35eff9d86bc0e026c3d1a6f7da4a32352449e0440
checksums.yaml.gz.sig ADDED
Binary file
@@ -1,22 +1,7 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- puts
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
- 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."
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
- puts "\t Variance: #{Seconds[statistics.variance]}"
70
- puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
71
- puts "\t Standard Error: #{statistics.standard_error}"
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
- puts "I am going to benchmark #{url}..."
66
+ Console.logger.info(self) {"I am going to benchmark #{url}..."}
81
67
 
82
- Async::Reactor.run do |task|
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
- puts "Your server can handle #{statistics.last.concurrency} concurrent requests."
114
-
115
- puts "At this level of concurrency, requests have ~#{(statistics.last.latency / statistics.first.latency).round(2)}x higher latency."
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).wait
108
+ run(host)
122
109
  end
123
110
  end
124
111
  end
@@ -1,22 +1,7 @@
1
- # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- puts "I am running #{concurrency} asynchronous tasks that will each make #{count} sequential requests..."
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.print
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
- 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."
76
- puts "\t Variance: #{Seconds[statistics.variance]}"
77
- puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
78
- puts "\t Standard Error: #{Seconds[statistics.standard_error]}"
79
-
80
- statistics.print
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
- puts "I am going to benchmark #{url}..."
80
+ Console.logger.info(self) {"I am going to benchmark #{url}..."}
90
81
 
91
- Async do |task|
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).wait
92
+ run(url)
102
93
  end
103
94
 
104
95
  if @interval
@@ -1,22 +1,7 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- puts "I am running #{concurrency} asynchronous tasks that will each make sequential requests..."
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
- 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."
66
- puts "\t Variance: #{Seconds[statistics.variance]}"
67
- puts "\tStandard Deviation: #{Seconds[statistics.standard_deviation]}"
68
- puts "\t Standard Error: #{Seconds[statistics.standard_error]}"
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
- puts "I am going to benchmark #{url}..."
64
+ Console.logger.info(self) {"I am going to benchmark #{url}..."}
78
65
 
79
- Async::Reactor.run do |task|
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).wait
75
+ run(host)
89
76
  end
90
77
  end
91
78
  end
@@ -1,22 +1,7 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- Async.logger.call(self, severity: (response.failure? ? :warn : :info)) do |buffer|
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.print
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- Async.logger.debug!
50
+ Console.logger.debug!
63
51
  elsif quiet?
64
- Async.logger.warn!
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
- Async.logger.error(self) {$!}
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
- Async.logger.warn(self) {"Could not fetch #{href}, relative to #{base}!"}
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
- Async.logger.warn(self) {"Exceeded depth while trying to visit #{url}!"}
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
- Async.logger.debug(self) {"Following redirect to #{location}..."}
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
- Async.logger.debug(self) {"Ignoring redirect to #{location}."}
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
- Async.logger.error(self) {"Timeout while fetching #{url}"}
121
- rescue StandardError
122
- Async.logger.error(self) {$!}
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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 print(out = STDOUT)
121
+ def to_s
137
122
  if self.valid?
138
- out.puts "#{@samples.size} samples. #{per_second} requests per second. S/D: #{Seconds[standard_deviation]}."
123
+ "#{@samples.size} samples. #{per_second} requests per second. S/D: #{Seconds[standard_deviation]}."
139
124
  else
140
- out.puts "Not enough samples."
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
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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.14.1"
8
+ VERSION = "0.16.0"
24
9
  end
25
10
  end
@@ -1,22 +1,7 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
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
+ [![Development Status](https://github.com/socketry/benchmark-http/workflows/Test/badge.svg)](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.14.1
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
- date: 2021-06-27 00:00:00.000000000 Z
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: bundler
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: covered
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: rake
170
+ name: covered
127
171
  requirement: !ruby/object:Gem::Requirement
128
172
  requirements:
129
173
  - - "~>"
130
174
  - !ruby/object:Gem::Version
131
- version: '10.0'
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: '10.0'
182
+ version: '0.16'
139
183
  - !ruby/object:Gem::Dependency
140
- name: rspec
184
+ name: sus
141
185
  requirement: !ruby/object:Gem::Requirement
142
186
  requirements:
143
187
  - - "~>"
144
188
  - !ruby/object:Gem::Version
145
- version: '3.0'
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: '3.0'
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.1.6
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