drnbench 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/doc/text/news.md
ADDED
data/drnbench.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
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
|
+
clean_white_space = lambda do |entry|
|
19
|
+
entry.gsub(/(\A\n+|\n+\z)/, '') + "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
|
23
|
+
require "drnbench/version"
|
24
|
+
|
25
|
+
Gem::Specification.new do |spec|
|
26
|
+
spec.name = "drnbench"
|
27
|
+
spec.version = Drnbench::VERSION
|
28
|
+
spec.homepage = "https://github.com/groonga/grntest"
|
29
|
+
spec.authors = ["YUKI Hiroshi", "Kouhei Sutou"]
|
30
|
+
spec.email = ["yuki@clear-code.com", "kou@clear-code.com"]
|
31
|
+
readme = File.read("README.md")
|
32
|
+
readme.force_encoding("UTF-8") if readme.respond_to?(:force_encoding)
|
33
|
+
entries = readme.split(/^\#\#\s(.*)$/)
|
34
|
+
description = clean_white_space.call(entries[entries.index("Description") + 1])
|
35
|
+
spec.summary, spec.description, = description.split(/\n\n+/, 3)
|
36
|
+
spec.license = "GPLv3 or later"
|
37
|
+
spec.files = [
|
38
|
+
"README.md",
|
39
|
+
"Rakefile",
|
40
|
+
"Gemfile",
|
41
|
+
"#{spec.name}.gemspec",
|
42
|
+
"LICENSE.txt",
|
43
|
+
]
|
44
|
+
spec.files += Dir.glob("doc/text/**/*")
|
45
|
+
spec.files += Dir.glob("lib/**/*.rb")
|
46
|
+
spec.test_files += Dir.glob("test/**/*")
|
47
|
+
Dir.chdir("bin") do
|
48
|
+
spec.executables = Dir.glob("*")
|
49
|
+
end
|
50
|
+
|
51
|
+
spec.add_runtime_dependency("json")
|
52
|
+
spec.add_runtime_dependency("droonga-client")
|
53
|
+
spec.add_runtime_dependency("drntest")
|
54
|
+
|
55
|
+
spec.add_development_dependency("bundler")
|
56
|
+
spec.add_development_dependency("rake")
|
57
|
+
spec.add_development_dependency("packnga")
|
58
|
+
spec.add_development_dependency("kramdown")
|
59
|
+
end
|
data/lib/drnbench.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "drnbench/version"
|
17
|
+
require "drnbench/request-response/configuration"
|
18
|
+
require "drnbench/request-response/runner"
|
19
|
+
require "drnbench/request-response/gradual-runner"
|
20
|
+
require "drnbench/publish-subscribe/configuration"
|
21
|
+
require "drnbench/publish-subscribe/runner"
|
22
|
+
require "drnbench/publish-subscribe/gradual-runner"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module Drnbench
|
17
|
+
class HttpDroongaClient < HttpClient
|
18
|
+
DEFAULT_PATH_BASE = "/droonga"
|
19
|
+
DEFAULT_COMMAND = "search"
|
20
|
+
DEFAULT_METHOD = "POST"
|
21
|
+
|
22
|
+
def initialize(params, config)
|
23
|
+
super
|
24
|
+
@command = params["command"] || DEFAULT_COMMAND
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def fixup_request(request)
|
29
|
+
request = {
|
30
|
+
"body" => request,
|
31
|
+
}
|
32
|
+
request["path"] ||= "#{DEFAULT_PATH_BASE}/#{@command}"
|
33
|
+
request["method"] ||= DEFAULT_METHOD
|
34
|
+
super(request)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "thread"
|
17
|
+
require "droonga/client"
|
18
|
+
require "json"
|
19
|
+
|
20
|
+
module Drnbench
|
21
|
+
class HttpClient
|
22
|
+
attr_reader :requests, :results, :wait
|
23
|
+
|
24
|
+
def initialize(params, config)
|
25
|
+
@requests = params[:requests]
|
26
|
+
@result = params[:result]
|
27
|
+
@config = config
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
@thread = Thread.new do
|
32
|
+
loop do
|
33
|
+
request = @requests.pop
|
34
|
+
request = fixup_request(request)
|
35
|
+
|
36
|
+
client = Droonga::Client.new(:protocol => :http,
|
37
|
+
:host => request["host"],
|
38
|
+
:port => request["port"])
|
39
|
+
request["headers"] ||= {}
|
40
|
+
request["headers"]["user-agent"] = "Ruby/#{RUBY_VERSION} Droonga::Benchmark::Runner::HttpClient"
|
41
|
+
start_time = Time.now
|
42
|
+
response = client.request(request)
|
43
|
+
@result << {
|
44
|
+
:request => request,
|
45
|
+
:status => response.code,
|
46
|
+
:elapsed_time => Time.now - start_time,
|
47
|
+
}
|
48
|
+
sleep @config.wait
|
49
|
+
end
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop
|
55
|
+
@thread.exit
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def fixup_request(request)
|
60
|
+
request["host"] ||= @config.default_host
|
61
|
+
request["port"] ||= @config.default_port
|
62
|
+
request["path"] ||= @config.default_path
|
63
|
+
request["method"] ||= @config.default_method
|
64
|
+
request["method"] = request["method"].upcase
|
65
|
+
request
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "drnbench/server/configuration"
|
17
|
+
|
18
|
+
module Drnbench
|
19
|
+
module PublishSubscribe
|
20
|
+
class Configuration
|
21
|
+
attr_accessor :start_n_subscribers, :n_publishings, :n_steps, :timeout
|
22
|
+
attr_accessor :subscribe_request_file, :feed_file, :engine, :protocol_adapter
|
23
|
+
attr_accessor :report_progressively, :output_path
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@start_n_subscribers = 1000
|
27
|
+
@n_publishings = 1000
|
28
|
+
@n_steps = 10
|
29
|
+
@timeout = 10
|
30
|
+
|
31
|
+
@report_progressively = true
|
32
|
+
@output_path = "/tmp/drnbench-pubsub-result.csv"
|
33
|
+
|
34
|
+
@engine = Server::EngineConfiguration.new
|
35
|
+
@protocol_adapter = Server::ProtocolAdapterConfiguration.new
|
36
|
+
@protocol_adapter.engine = @engine
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate
|
40
|
+
if @subscribe_request_file.nil?
|
41
|
+
raise ArgumentError.new("You must specify a JSON file for a message pattern to subscribe.")
|
42
|
+
end
|
43
|
+
if @feed_file.nil?
|
44
|
+
raise ArgumentError.new("You must specify a JSON file for a message pattern to feed.")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def subscribe_request
|
49
|
+
@subscribe_request ||= prepare_subscribe_request
|
50
|
+
end
|
51
|
+
|
52
|
+
def new_subscribe_request
|
53
|
+
Marshal.load(Marshal.dump(subscribe_request))
|
54
|
+
end
|
55
|
+
|
56
|
+
def feed
|
57
|
+
@feed ||= prepare_feed
|
58
|
+
end
|
59
|
+
|
60
|
+
def new_feed
|
61
|
+
Marshal.load(Marshal.dump(feed))
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def prepare_subscribe_request
|
66
|
+
subscribe_request_file = Pathname(@subscribe_request_file).expand_path(Dir.pwd)
|
67
|
+
JSON.parse(subscribe_request_file.read)
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_feed
|
71
|
+
feed_file = Pathname(@feed_file).expand_path(Dir.pwd)
|
72
|
+
JSON.parse(feed_file.read)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "benchmark"
|
17
|
+
require "csv"
|
18
|
+
|
19
|
+
module Drnbench
|
20
|
+
module PublishSubscribe
|
21
|
+
class GradualRunner
|
22
|
+
attr_reader :total_results
|
23
|
+
|
24
|
+
def initialize(config)
|
25
|
+
@config = config
|
26
|
+
@runner = Runner.new(@config)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
results = []
|
31
|
+
@runner.setup
|
32
|
+
begin
|
33
|
+
@config.n_steps.times do
|
34
|
+
run_once(results)
|
35
|
+
end
|
36
|
+
ensure
|
37
|
+
@runner.teardown
|
38
|
+
end
|
39
|
+
@total_results = [
|
40
|
+
["case", "qps"],
|
41
|
+
]
|
42
|
+
@total_results += results
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def run_once(results)
|
47
|
+
@runner.increase_subscribers
|
48
|
+
label = "#{@runner.n_subscribers} subscribers"
|
49
|
+
GC.disable
|
50
|
+
result = Benchmark.bm do |benchmark|
|
51
|
+
benchmark.report(label) do
|
52
|
+
@runner.run
|
53
|
+
end
|
54
|
+
end
|
55
|
+
GC.enable
|
56
|
+
GC.start
|
57
|
+
result = result.join("").strip.gsub(/[()]/, "").split(/\s+/)
|
58
|
+
qps = @config.n_publishings.to_f / result.last.to_f
|
59
|
+
if @config.report_progressively
|
60
|
+
puts " (#{qps} queries per second)"
|
61
|
+
end
|
62
|
+
results << [label, qps]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "pathname"
|
17
|
+
require "droonga/client"
|
18
|
+
require "drnbench/server/engine"
|
19
|
+
require "drnbench/server/protocol-adapter"
|
20
|
+
|
21
|
+
module Drnbench
|
22
|
+
module PublishSubscribe
|
23
|
+
class Runner
|
24
|
+
def initialize(config)
|
25
|
+
@config = config
|
26
|
+
@published_messages = Queue.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def n_subscribers
|
30
|
+
@subscribers.size
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup
|
34
|
+
setup_server
|
35
|
+
setup_subscribers
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
teardown_subscribers
|
40
|
+
teardown_server
|
41
|
+
end
|
42
|
+
|
43
|
+
def run
|
44
|
+
publishing_times = @config.n_publishings
|
45
|
+
n_will_be_published_messages = @subscribers.size * publishing_times
|
46
|
+
|
47
|
+
do_feed(publishing_times)
|
48
|
+
receive_messages(n_will_be_published_messages)
|
49
|
+
end
|
50
|
+
|
51
|
+
def increase_subscribers
|
52
|
+
if @subscribers.empty?
|
53
|
+
new_n_subscribers = @config.start_n_subscribers
|
54
|
+
else
|
55
|
+
new_n_subscribers = @subscribers.size
|
56
|
+
end
|
57
|
+
add_subscribers(new_n_subscribers)
|
58
|
+
ensure_subscribers_ready
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def setup_server
|
63
|
+
@engine = Engine.new(@config.engine)
|
64
|
+
@engine.start
|
65
|
+
|
66
|
+
@protocol_adapter = ProtocolAdapter.new(@config.protocol_adapter)
|
67
|
+
@protocol_adapter.start
|
68
|
+
end
|
69
|
+
|
70
|
+
def teardown_server
|
71
|
+
@protocol_adapter.stop
|
72
|
+
@engine.stop
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_subscribers
|
76
|
+
@subscribers = []
|
77
|
+
end
|
78
|
+
|
79
|
+
def teardown_subscribers
|
80
|
+
@subscribers.each do |subscriber|
|
81
|
+
subscriber.close
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_subscribers(n_subscribers)
|
86
|
+
n_subscribers.times do
|
87
|
+
message = @config.new_subscribe_request
|
88
|
+
client = Droonga::Client.new(:protocol => :http,
|
89
|
+
:host => @config.protocol_adapter.host,
|
90
|
+
:port => @config.protocol_adapter.port)
|
91
|
+
client.subscribe(message) do |published_message|
|
92
|
+
@published_messages.push(published_message)
|
93
|
+
end
|
94
|
+
@subscribers << client
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_subscribers_ready
|
99
|
+
sleep(1)
|
100
|
+
2.times do
|
101
|
+
do_feed(1)
|
102
|
+
n_subscribers.times do
|
103
|
+
@published_messages.pop
|
104
|
+
break if @published_messages.empty?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
@published_messages.clear
|
108
|
+
end
|
109
|
+
|
110
|
+
def do_feed(count)
|
111
|
+
Droonga::Client.open(:tag => @config.engine.tag,
|
112
|
+
:host => @config.engine.host,
|
113
|
+
:port => @config.engine.port) do |feeder|
|
114
|
+
count.times do
|
115
|
+
do_one_feed(feeder)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def do_one_feed(feeder)
|
121
|
+
message = @config.new_feed
|
122
|
+
feeder.send(message)
|
123
|
+
end
|
124
|
+
|
125
|
+
def receive_messages(count)
|
126
|
+
n_published_messages = 0
|
127
|
+
count.times do
|
128
|
+
# we should implement "timeout" for too slow cases
|
129
|
+
@published_messages.pop
|
130
|
+
n_published_messages += 1
|
131
|
+
end
|
132
|
+
n_published_messages
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|