drnbench 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +674 -0
- data/README.md +296 -0
- data/Rakefile +33 -0
- data/bin/drnbench-publish-subscribe +104 -0
- data/bin/drnbench-request-response +89 -0
- data/doc/text/news.md +5 -0
- data/drnbench.gemspec +59 -0
- data/lib/drnbench.rb +22 -0
- data/lib/drnbench/client/http-droonga.rb +37 -0
- data/lib/drnbench/client/http.rb +68 -0
- data/lib/drnbench/publish-subscribe/configuration.rb +76 -0
- data/lib/drnbench/publish-subscribe/gradual-runner.rb +66 -0
- data/lib/drnbench/publish-subscribe/runner.rb +136 -0
- data/lib/drnbench/publish-subscribe/watch.rb +43 -0
- data/lib/drnbench/request-response/configuration.rb +79 -0
- data/lib/drnbench/request-response/gradual-runner.rb +95 -0
- data/lib/drnbench/request-response/result.rb +127 -0
- data/lib/drnbench/request-response/runner.rb +111 -0
- data/lib/drnbench/server/configuration.rb +59 -0
- data/lib/drnbench/server/engine.rb +21 -0
- data/lib/drnbench/server/protocol-adapter.rb +89 -0
- data/lib/drnbench/version.rb +18 -0
- metadata +170 -0
data/README.md
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# Drnbench
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Drnbench is a benchmark tool for Droonga.
|
6
|
+
|
7
|
+
It may be used for other HTTP servers.
|
8
|
+
|
9
|
+
Drnbench provides features to send multiple random requests with different settings periodically.
|
10
|
+
Number of clients (requests) in each period will be automatically increased gradually.
|
11
|
+
So you'll be able to guess the limit performance of the throughput of a server, via the report like following:
|
12
|
+
|
13
|
+
n_clients,total_n_requests,queries_per_second,min_elapsed_time,max_elapsed_time,average_elapsed_time,200
|
14
|
+
1,33,3.3,0.164632187,0.164632187,0.19133309036363635,0
|
15
|
+
2,70,7.0,0.161510877,0.161510877,0.1846983412285715,0
|
16
|
+
3,87,8.7,0.1658357,0.1658357,0.24303329366666668,0
|
17
|
+
...
|
18
|
+
|
19
|
+
Drnbench provides two commands, for different styles of benchmarked servers.
|
20
|
+
|
21
|
+
* `drnbench-request-response`: benchmarks simple request-response style APIs.
|
22
|
+
* `drnbench-publish-subscribe`: benchmarks publish-subscribe style (including HTTP streaming) APIs.
|
23
|
+
This command is not implemented yet.
|
24
|
+
|
25
|
+
## How to run benchmark?
|
26
|
+
|
27
|
+
### Benchmarking with an HTTP server
|
28
|
+
|
29
|
+
Drnbench can benchmark throughput performance of an HTTP server with random requests.
|
30
|
+
|
31
|
+
In this scenario, you have to do:
|
32
|
+
|
33
|
+
* setup an HTTP server.
|
34
|
+
* prepare patterns of requests.
|
35
|
+
|
36
|
+
Drnbench will start multiple clients and send many requests based on the patterns file.
|
37
|
+
|
38
|
+
1. Create a patterns file in the format:
|
39
|
+
|
40
|
+
{
|
41
|
+
"(pattern type 1 name)": {
|
42
|
+
"frequency": (appearance ratio in all requests),
|
43
|
+
"path": "(path to the endpoint)",
|
44
|
+
"method": "(HTTP method)",
|
45
|
+
"patterns": [
|
46
|
+
{ "body": (request body 1 sent by POST method) },
|
47
|
+
{ "body": (request body 2 sent by POST method) },
|
48
|
+
...
|
49
|
+
]
|
50
|
+
}
|
51
|
+
"(patterns type 2 name)": {
|
52
|
+
"frequency": (appearance ratio in all requests),
|
53
|
+
"patterns": [
|
54
|
+
{
|
55
|
+
"path": "(path to the endpoint 1)",
|
56
|
+
"method": "(HTTP method)",
|
57
|
+
"body": (request body 1 sent by POST method)
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"path": "(path to the endpoint 2)",
|
61
|
+
"method": "(HTTP method)",
|
62
|
+
"body": (request body 2 sent by POST method)
|
63
|
+
},
|
64
|
+
...
|
65
|
+
]
|
66
|
+
},
|
67
|
+
...
|
68
|
+
}
|
69
|
+
|
70
|
+
For example, a file "patterns.json" like:
|
71
|
+
|
72
|
+
{
|
73
|
+
"user search": {
|
74
|
+
"frequency": 0.61,
|
75
|
+
"method": "GET",
|
76
|
+
"patterns": [
|
77
|
+
{ "path": "/users?q=foo" },
|
78
|
+
{ "path": "/users?q=bar" },
|
79
|
+
...
|
80
|
+
]
|
81
|
+
},
|
82
|
+
"item search": {
|
83
|
+
"frequency": 0.32,
|
84
|
+
"method": "GET",
|
85
|
+
"patterns": [
|
86
|
+
{ "path": "/items?q=foo" },
|
87
|
+
{ "path": "/items?q=bar" },
|
88
|
+
...
|
89
|
+
]
|
90
|
+
},
|
91
|
+
...
|
92
|
+
}
|
93
|
+
|
94
|
+
2. Setup an HTTP server. For example, localhost:80.
|
95
|
+
3. Run drnbench with the pattern file.
|
96
|
+
|
97
|
+
# cd ~/drnbench
|
98
|
+
# bundle exec bin/drnbench-request-response \
|
99
|
+
--start-n-clients=1 \
|
100
|
+
--end-n-clients=32 \
|
101
|
+
--step=1 \
|
102
|
+
--duration=10 \
|
103
|
+
--wait=0.01 \
|
104
|
+
--mode=http \
|
105
|
+
--request-patterns-file=/tmp/patterns.json \
|
106
|
+
--host=localhost \
|
107
|
+
--port=80
|
108
|
+
|
109
|
+
4. You'll get a report.
|
110
|
+
|
111
|
+
|
112
|
+
### Benchmarking of request-responsne style commands, with a Droonga-based search system
|
113
|
+
|
114
|
+
Drnbench can benchmark throughput performance of a Droonga-based search system with random requests.
|
115
|
+
|
116
|
+
In this scenario, you have to do:
|
117
|
+
|
118
|
+
* setup a Droonga-based search system.
|
119
|
+
* prepare patterns of requests for commands.
|
120
|
+
|
121
|
+
Drnbench will start multiple clients and send many requests based on the patterns file.
|
122
|
+
|
123
|
+
1. Create a patterns file in the format:
|
124
|
+
|
125
|
+
{
|
126
|
+
"(pattern type 1 name)": {
|
127
|
+
"frequency": (appearance ratio in all requests),
|
128
|
+
"command": "(command name)",
|
129
|
+
"patterns": [
|
130
|
+
{ command parameters 1 },
|
131
|
+
{ command parameters 2 },
|
132
|
+
{ command parameters 3 },
|
133
|
+
...
|
134
|
+
]
|
135
|
+
}
|
136
|
+
"(patterns type 2 name)": {
|
137
|
+
...
|
138
|
+
},
|
139
|
+
...
|
140
|
+
}
|
141
|
+
|
142
|
+
For example, a file "patterns.json" like:
|
143
|
+
|
144
|
+
{
|
145
|
+
"user search": {
|
146
|
+
"frequency": 0.61,
|
147
|
+
"command": "search",
|
148
|
+
"patterns": [
|
149
|
+
{
|
150
|
+
"queries": {
|
151
|
+
"users": {
|
152
|
+
"source": "User",
|
153
|
+
"condition": "age >= 10",
|
154
|
+
"sortBy": { "keys": ["-birthday"], "offset": 0, "limit": 100" },
|
155
|
+
"output": {
|
156
|
+
"elements": [
|
157
|
+
"count",
|
158
|
+
"records"
|
159
|
+
],
|
160
|
+
"attributes": ["_key", "name", "age", "birhtday"],
|
161
|
+
"offset": 0,
|
162
|
+
"limit": 100
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
},
|
167
|
+
...
|
168
|
+
]
|
169
|
+
},
|
170
|
+
"item search": {
|
171
|
+
"frequency": 0.32,
|
172
|
+
"command": "search",
|
173
|
+
"patterns": [
|
174
|
+
{
|
175
|
+
"queries": {
|
176
|
+
"users": {
|
177
|
+
"source": "Item",
|
178
|
+
"condition": "visible == true",
|
179
|
+
"sortBy": { "keys": ["title"], "offset": 0, "limit": 100" },
|
180
|
+
"output": {
|
181
|
+
"elements": [
|
182
|
+
"count",
|
183
|
+
"records"
|
184
|
+
],
|
185
|
+
"attributes": ["title", "price"],
|
186
|
+
"offset": 0,
|
187
|
+
"limit": 100
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
},
|
192
|
+
...
|
193
|
+
]
|
194
|
+
},
|
195
|
+
...
|
196
|
+
}
|
197
|
+
|
198
|
+
2. Setup a Droonga Engine server. For example, localhost:23003.
|
199
|
+
3. Setup a Protocol Adapter server. For example, localhost:3003.
|
200
|
+
4. Run drnbench with the pattern file.
|
201
|
+
|
202
|
+
# cd ~/drnbench
|
203
|
+
# bundle exec bin/drnbench-request-response \
|
204
|
+
--start-n-clients=1 \
|
205
|
+
--end-n-clients=32 \
|
206
|
+
--step=1 \
|
207
|
+
--duration=10 \
|
208
|
+
--wait=0.01 \
|
209
|
+
--mode=http-droonga \
|
210
|
+
--request-patterns-file=/tmp/patterns.json \
|
211
|
+
--host=localhost \
|
212
|
+
--port=3003
|
213
|
+
|
214
|
+
5. You'll get a report.
|
215
|
+
|
216
|
+
|
217
|
+
### Benchmarking of HTTP streaming APIs, with a Droonga-based search system
|
218
|
+
|
219
|
+
Drnbench can benchmark an HTTP streaming API based on a publish-subscribe command.
|
220
|
+
|
221
|
+
In this scenario, you have to do:
|
222
|
+
|
223
|
+
* prepare configuration files "fluentd.conf" and "catalog.json" for a Droonga Engine.
|
224
|
+
* prepare an express application works as a Droonga Protocol Adapter.
|
225
|
+
* prepare pattern files for subscribe request and feeded data.
|
226
|
+
|
227
|
+
Drnbench will run benchmark like:
|
228
|
+
|
229
|
+
1. Prepare subscribers.
|
230
|
+
2. Send "feed" messages to the Droonga Engine.
|
231
|
+
All subscribers will receive all published messages.
|
232
|
+
3. Increase the number of subscribers.
|
233
|
+
4. Repeat 2, 3, and 4.
|
234
|
+
|
235
|
+
Steps to run:
|
236
|
+
|
237
|
+
1. Create a patterns file for a subscribe request:
|
238
|
+
|
239
|
+
{
|
240
|
+
"path": "/path/to/endpoint",
|
241
|
+
"method": "HTTP method",
|
242
|
+
"headers": {
|
243
|
+
"X-xxxx": "xxxxx",
|
244
|
+
},
|
245
|
+
"body": (sent as the request body)
|
246
|
+
}
|
247
|
+
|
248
|
+
For example, a file "watch-subscribe.json" like:
|
249
|
+
|
250
|
+
{
|
251
|
+
"path": "/droonga-streaming/watch?condition=keyword"
|
252
|
+
}
|
253
|
+
|
254
|
+
2. Create a patterns file for messages to be feeded:
|
255
|
+
|
256
|
+
{
|
257
|
+
"type": "(message type)",
|
258
|
+
"dataset": "(dataset name)",
|
259
|
+
"body": (message body)
|
260
|
+
}
|
261
|
+
|
262
|
+
For example, a file "watch-feed.json" like:
|
263
|
+
|
264
|
+
{
|
265
|
+
"type": "watch.feed",
|
266
|
+
"dataset": "Watch",
|
267
|
+
"body": {
|
268
|
+
"targets": {
|
269
|
+
"body": "a content including the keyword"
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
3. Run drnbench with the pattern file.
|
275
|
+
|
276
|
+
# cd ~/drnbench
|
277
|
+
# bundle exec bin/drnbench-publish-subscribe \
|
278
|
+
--start-n-subscribers=1000 \
|
279
|
+
--n-publishings=1000 \
|
280
|
+
--n-steps=10 \
|
281
|
+
--timeout=5 \
|
282
|
+
--subscribe-request-file=/tmp/watch-subscribe.json \
|
283
|
+
--feed-file=/tmp/watch-feed.json \
|
284
|
+
--protocol-adapter-port=80 \
|
285
|
+
--engine-config-path=/tmp/engine/
|
286
|
+
|
287
|
+
4. You'll get a report.
|
288
|
+
|
289
|
+
|
290
|
+
## License
|
291
|
+
|
292
|
+
GPLv3 or later.
|
293
|
+
|
294
|
+
Copyright (c) 2013-2014 Droonga Project
|
295
|
+
|
296
|
+
See LICENSE.txt for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2013-2014 Droonga Project
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require "bundler/gem_helper"
|
19
|
+
require "packnga"
|
20
|
+
|
21
|
+
base_dir = File.join(File.dirname(__FILE__))
|
22
|
+
helper = Bundler::GemHelper.new(base_dir)
|
23
|
+
def helper.version_tag
|
24
|
+
version
|
25
|
+
end
|
26
|
+
|
27
|
+
helper.install
|
28
|
+
spec = helper.gemspec
|
29
|
+
|
30
|
+
Packnga::DocumentTask.new(spec) do |task|
|
31
|
+
task.original_language = "en"
|
32
|
+
task.translate_languages = ["ja"]
|
33
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright (C) 2013-2014 Droonga Project
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require "drnbench"
|
20
|
+
require "optparse"
|
21
|
+
require "shellwords"
|
22
|
+
|
23
|
+
config = Drnbench::PublishSubscribe::Configuration.new
|
24
|
+
option_parser = OptionParser.new do |parser|
|
25
|
+
parser.on("--start-n-subscribers=N", Integer,
|
26
|
+
"initial number of subscribers") do |n_subscribers|
|
27
|
+
config.start_n_subscribers = n_subscribers
|
28
|
+
end
|
29
|
+
parser.on("--n-publishings=N", Integer,
|
30
|
+
"number of publish times") do |n_publishings|
|
31
|
+
config.n_publishings = n_publishings
|
32
|
+
end
|
33
|
+
parser.on("--n-steps=N", Integer,
|
34
|
+
"number of benchmark steps") do |n_steps|
|
35
|
+
config.n_steps = n_steps
|
36
|
+
end
|
37
|
+
parser.on("--timeout=SECONDS", Float,
|
38
|
+
"timeout for receiving") do |timeout|
|
39
|
+
config.timeout = timeout
|
40
|
+
end
|
41
|
+
parser.on("--output-path=PATH", String,
|
42
|
+
"path to the output CSV file") do |output_path|
|
43
|
+
config.output_path = output_path
|
44
|
+
end
|
45
|
+
|
46
|
+
parser.on("--subscribe-request-file=PATH", String,
|
47
|
+
"path to the file which defines a request to subscribe") do |path|
|
48
|
+
config.subscribe_request_file = path
|
49
|
+
end
|
50
|
+
parser.on("--feed-file=PATH", String,
|
51
|
+
"path to the file which defines a message feeded to the engine") do |path|
|
52
|
+
config.feed_file = path
|
53
|
+
end
|
54
|
+
|
55
|
+
parser.on("--protocol-adapter-port=PORT", Integer,
|
56
|
+
"port number for the Droonga Protocol Adapter which is used for clients") do |port|
|
57
|
+
config.protocol_adapter.port = port
|
58
|
+
end
|
59
|
+
parser.on("--protocol-adapter-receive-port=PORT", Integer,
|
60
|
+
"port number for the Droonga Protocol Adapter which is used for the engine") do |port|
|
61
|
+
config.protocol_adapter.receive_port = port
|
62
|
+
end
|
63
|
+
parser.on("--protocol-adapter-application-dir=PATH", String,
|
64
|
+
"path to the directory of the Droonga Protocol Adapter") do |path|
|
65
|
+
config.protocol_adapter.application_dir = path
|
66
|
+
end
|
67
|
+
parser.on("--node=PATH", String,
|
68
|
+
"path to the node.js executable") do |node|
|
69
|
+
config.protocol_adapter.node = node
|
70
|
+
end
|
71
|
+
parser.on("--node-options=OPTIONS",
|
72
|
+
"options for node.js",
|
73
|
+
"you can specify this option multiple times") do |options|
|
74
|
+
config.protocol_adapter.node_options = Shellwords.split(options)
|
75
|
+
end
|
76
|
+
|
77
|
+
parser.on("--engine-config-path=PATH", String,
|
78
|
+
"path to the configuration directory for Droonga Engine") do |path|
|
79
|
+
config.engine.engine_config_path = path
|
80
|
+
end
|
81
|
+
parser.on("--fluentd=PATH", String,
|
82
|
+
"path to the fluentd executable") do |fluentd|
|
83
|
+
config.engine.fluentd = fluentd
|
84
|
+
end
|
85
|
+
parser.on("--fluentd-options=OPTIONS",
|
86
|
+
"options for fluentd",
|
87
|
+
"you can specify this option multiple times") do |options|
|
88
|
+
config.engine.fluentd_options = Shellwords.split(options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
args = option_parser.parse!(ARGV)
|
92
|
+
|
93
|
+
config.validate
|
94
|
+
|
95
|
+
runner = Drnbench::PublishSubscribe::GradualRunner.new(config)
|
96
|
+
runner.run
|
97
|
+
|
98
|
+
File.open(config.output_path, "w") do |file|
|
99
|
+
runner.total_results.each do |row|
|
100
|
+
file.puts(CSV.generate_line(row))
|
101
|
+
puts row.join(",")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
puts "Statistics has been saved to #{config.output_path}"
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright (C) 2013-2014 Droonga Project
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require "drnbench"
|
20
|
+
require "optparse"
|
21
|
+
|
22
|
+
config = Drnbench::RequestResponse::Configuration.new
|
23
|
+
option_parser = OptionParser.new do |parser|
|
24
|
+
parser.on("--duration=SECONDS", Float,
|
25
|
+
"duration of the benmark") do |duration|
|
26
|
+
config.duration = duration
|
27
|
+
end
|
28
|
+
parser.on("--wait=SECONDS", Float,
|
29
|
+
"wait for each request") do |wait|
|
30
|
+
config.wait = wait
|
31
|
+
end
|
32
|
+
parser.on("--start-n-clients=N", Integer,
|
33
|
+
"initial number of clients (optional)") do |n_clients|
|
34
|
+
config.start_n_clients = n_clients
|
35
|
+
end
|
36
|
+
parser.on("--end-n-clients=N", Integer,
|
37
|
+
"final number of clients (optional)") do |n_clients|
|
38
|
+
config.end_n_clients = n_clients
|
39
|
+
end
|
40
|
+
parser.on("--step=COUNT", Integer,
|
41
|
+
"step to increase number of clients (optional)") do |step|
|
42
|
+
config.step = step
|
43
|
+
end
|
44
|
+
|
45
|
+
parser.on("--mode=MODE", String,
|
46
|
+
"mode of benchmark (optional)",
|
47
|
+
"available modes:",
|
48
|
+
" http",
|
49
|
+
" http-droonga-search") do |mode|
|
50
|
+
config.mode = mode.gsub(/-/, "_")
|
51
|
+
end
|
52
|
+
parser.on("--request-patterns-file=PATH",
|
53
|
+
"path to request patterns JSON file") do |path|
|
54
|
+
config.request_patterns_file = File.expand_path(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
parser.on("--default-host=HOST", String,
|
58
|
+
"default host name (optional)") do |host|
|
59
|
+
config.default_host = host
|
60
|
+
end
|
61
|
+
parser.on("--default-port=PORT", Integer,
|
62
|
+
"default port number (optional)") do |port|
|
63
|
+
config.default_port = port
|
64
|
+
end
|
65
|
+
parser.on("--default-path=PATH", String,
|
66
|
+
"default path (optional)") do |path|
|
67
|
+
config.default_path = path
|
68
|
+
end
|
69
|
+
parser.on("--default-method=METHOD", String,
|
70
|
+
"default HTTP method (optional)") do |method|
|
71
|
+
config.default_method = method
|
72
|
+
end
|
73
|
+
|
74
|
+
parser.on("--output-path=PATH",
|
75
|
+
"path to output statistics as a CSV file (optional)") do |path|
|
76
|
+
config.output_path = File.expand_path(path)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
args = option_parser.parse!(ARGV)
|
80
|
+
|
81
|
+
config.validate
|
82
|
+
|
83
|
+
runner = Drnbench::RequestResponse::GradualRunner.new(config)
|
84
|
+
runner.run
|
85
|
+
|
86
|
+
File.open(config.output_path, "w") do |file|
|
87
|
+
file.puts runner.result.to_csv
|
88
|
+
end
|
89
|
+
puts "Statistics has been saved to #{config.output_path}"
|