drnbench 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ # News
2
+
3
+ ## 1.0.0: 2014-01-29
4
+
5
+ The first release!!!
@@ -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
@@ -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