ruby-mqtt-bench 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bb071932d4f5408baa1be95dbbde168c6be78105
4
+ data.tar.gz: b18612d37a36719675e4d20a33c1a194e1cd3369
5
+ SHA512:
6
+ metadata.gz: 7f6fd8ec1324da568a825a5d58d89ba840dd52187888ce8df5416e59ff188dc5495957756d29392632fe67628ac093b8f90d1aba97156242b9019e587b322413
7
+ data.tar.gz: f62296b9266d19598009ade1f529f3fad784ea348656d52544eafb20b2397ecde6fd8495e3405a71314099e35fd95268194dc1bc5997e8915b55de6bcf034c92
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-mqtt-io.gemspec
4
+ gemspec
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-mqtt-bench (0.0.1)
5
+ concurrent-ruby (~> 1.0)
6
+ mqtt (~> 0.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.0.0)
12
+ concurrent-ruby (1.0.0-java)
13
+ mqtt (0.3.1)
14
+ rake (10.5.0)
15
+
16
+ PLATFORMS
17
+ java
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ bundler (~> 1.10)
22
+ rake (~> 10.0)
23
+ ruby-mqtt-bench!
24
+
25
+ BUNDLED WITH
26
+ 1.11.2
@@ -0,0 +1,53 @@
1
+ # ruby-mqtt-bench
2
+ mqtt-bench for ruby
3
+
4
+ This project is deeply inspired by [mqtt-bench](https://github.com/takanorig/mqtt-bench "mqtt-bench"). Ruby cannot provide the same performance as golang. This code is provided just for debugging purposes.
5
+
6
+
7
+ ## Installation
8
+
9
+ gem install ruby-mqtt-bench
10
+
11
+
12
+ ## How to use
13
+
14
+ ruby-mqtt-bench conf/mqtt_bench.conf
15
+
16
+ ## Configuration
17
+
18
+ The configuration can be modified by editing mqtt_bench.conf as follows. mqtt_opts are passed to ruby-mqtt and bench_opts are used locally in ruby-mqtt-bench.
19
+
20
+ vi conf/mqtt_bench.conf
21
+ {
22
+ "mqtt_opts": {
23
+ "host": "127.0.0.1",
24
+ "port": 1883,
25
+ "keep_alive": 15
26
+ },
27
+ "bench_opts": {
28
+ "topic": "mqtt_bench",
29
+ "num_clients": 128,
30
+ "data_size": 64,
31
+ "num_msgs": 1000,
32
+ "interval": 0,
33
+ "time_key": "time",
34
+ "timestamp": "timestamp"
35
+ }
36
+ }
37
+
38
+ - topic: topic to be published
39
+ - num_clients: number of clients connecting to a target broker simultaneously
40
+ - data_size: message size
41
+ - num_msgs: total number of messages sent to a target broker
42
+ - interval: message sending interval
43
+ - time_key: attribute name of time when the message was published
44
+ - timestamp: attribute name for passing timestamp information to fluentd (default nil)
45
+
46
+ Message is created in JSON format. Because each message has minimum fields,
47
+ minimum message size can be calculated as follows:
48
+
49
+ Example message:
50
+
51
+ {:cid=>"001", :data=>"", :mid=>"00001", :time=>1455754303515}
52
+
53
+ Field name and symbols have 50 bytes. "data" field size can be specified in configuration. "cid" (client id) and "mid" (message id) have number of digits with maximum number specified in configuration (num_clients and num_msgs. Time to send a message is recorded in the message as time field in ms.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mqtt'
4
+ require 'json'
5
+ require 'thwait'
6
+ require 'time'
7
+
8
+ # MQTT benchmark software written in Ruby
9
+ # Message is created in JSON format.
10
+ # Because each message has minimum fields,
11
+ # minimum message size can be calculated as follows:
12
+ #
13
+ # Example configuration:
14
+ # {
15
+ # "mqtt_opts": {
16
+ # "host": "127.0.0.1",
17
+ # "port": 1883,
18
+ # "keep_alive": 15
19
+ # },
20
+ # "bench_opts": {
21
+ # "num_clients": 512,
22
+ # "data_size": 64,
23
+ # "num_msgs": 1000,
24
+ # "interval": 0
25
+ # }
26
+ # }
27
+ #
28
+ # Example message:
29
+ # {:cid=>"001", :data=>"", :mid=>"00001", :time=>1455754303515}
30
+ #
31
+ # Field name and symbols have 50 bytes.
32
+ # "data" field size can be specified in configuration.
33
+ # "cid" (client id) and "mid" (message id) have number of digits with
34
+ # maximum number specified in configuration (num_clients and num_msgs.
35
+ # Time to send a message is recorded in the message as time field in ms.
36
+ #
37
+ class MqttBench
38
+ attr_accessor :results, :total_results
39
+
40
+ def initialize(conf_file)
41
+ conf = JSON.parse(open(conf_file || File.dirname(__FILE__) + '/../conf/mqtt_bench.conf').read, symbolize_names: true)
42
+ @mqtt_opts = {
43
+ host: "127.0.0.1",
44
+ port: 1883,
45
+ keep_alive: 15
46
+ }.merge(conf[:mqtt_opts])
47
+
48
+ @bench_opts = {
49
+ topic: "mqtt_bench",
50
+ num_clients: 5,
51
+ data_size: 128,
52
+ num_msgs: 100,
53
+ interval: 1,
54
+ time_key: "time",
55
+ timestamp: nil
56
+ }.merge(conf[:bench_opts])
57
+ end
58
+
59
+ def curr_time
60
+ Time.now.instance_eval { self.to_i * 1000 + (usec/1000) }
61
+ end
62
+
63
+ def align_digits(basis, target)
64
+ sprintf("%0#{@bench_opts[basis].to_s.length}d", target)
65
+ end
66
+
67
+ def start
68
+ $stderr.puts "start mqtt #{@mqtt_opts[:host]}"
69
+ @clients = []
70
+ @threads = []
71
+ @results = Queue.new
72
+ @total_results = {}
73
+ @data = (0..(@bench_opts[:data_size]-1)).map {|i| i % 10}.join
74
+ @total_results[:start_time] = curr_time
75
+ @bench_opts[:num_clients].times do |i|
76
+ @threads[i] = Thread.new do
77
+ result = {}
78
+ msg_count = 0
79
+ topic = "#{@bench_opts[:topic]}/#{align_digits(:num_clients, i)}"
80
+ message = {
81
+ cid: align_digits(:num_clients, i),
82
+ data: @data
83
+ }
84
+ begin
85
+ client = MQTT::Client.new(@mqtt_opts)
86
+ result[:start_time] = curr_time
87
+ client.connect
88
+ while (true)
89
+ message[:mid] = align_digits(:num_msgs, msg_count + 1)
90
+ message[@bench_opts[:time_key].to_sym] = curr_time
91
+ message[@bench_opts[:timestamp].to_sym] = Time.now.utc.iso8601 if !@bench_opts[:timestamp].nil?
92
+ client.publish(topic, message.to_json)
93
+ msg_count += 1
94
+ break if @bench_opts[:num_msgs] - msg_count <= 0
95
+ sleep @bench_opts[:interval]
96
+ end
97
+ client.disconnect
98
+ result[:end_time] = curr_time
99
+ @results.push(result)
100
+ rescue MQTT::ProtocolException => e
101
+ $stderr.puts "Protocol error occurs: #{e.class},#{e.message}"
102
+ next
103
+ rescue Timeout::Error => e
104
+ $stderr.puts "Timeout error occurs: #{e.class},#{e.message}"
105
+ next
106
+ rescue SystemCallError => e
107
+ $stderr.puts "System call error occurs: #{e.class},#{e.message}"
108
+ next
109
+ rescue StandardError=> e
110
+ $stderr.puts "The other error occurs: #{e.class},#{e.message}"
111
+ next
112
+ end
113
+ end
114
+ #p @threads[i]
115
+ end
116
+ end
117
+
118
+ def wait_clients
119
+ ThreadsWait.all_waits(*@threads) # {|th| puts "end #{th.inspect}"}
120
+ @total_results[:end_time] = curr_time
121
+ end
122
+
123
+ def print_results
124
+ total_duration = @total_results[:end_time] - @total_results[:start_time]
125
+ results = []
126
+ @results.size.times do
127
+ results << @results.pop
128
+ end
129
+ duration = results.map {|r| r[:end_time] - r[:start_time]}
130
+ avg_duration = duration.inject(:+).to_f / duration.size
131
+ dev_duration = duration.map {|d| (d - avg_duration)**2}
132
+ stddev_duration = Math.sqrt(dev_duration.inject(:+).to_f) / dev_duration.size
133
+ puts "total duration:\t\t\t\t#{total_duration} ms"
134
+ puts "total throughput:\t\t\t#{@bench_opts[:num_msgs].to_f * @bench_opts[:num_clients] / total_duration} msgs/ms"
135
+ puts "average duration/client:\t\t#{avg_duration} ms"
136
+ puts "standard deviation of duration/client:\t#{stddev_duration} ms"
137
+ end
138
+ end
139
+
140
+ bench = MqttBench.new(ARGV[0])
141
+ bench.start
142
+ bench.wait_clients
143
+ bench.print_results
@@ -0,0 +1,15 @@
1
+ {
2
+ "mqtt_opts": {
3
+ "host": "127.0.0.1",
4
+ "port": 1883,
5
+ "keep_alive": 15
6
+ },
7
+ "bench_opts": {
8
+ "topic": "mqtt_bench",
9
+ "num_clients": 5,
10
+ "data_size": 128,
11
+ "num_msgs": 100,
12
+ "interval": 1,
13
+ "time_key": "time"
14
+ }
15
+ }
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ruby-mqtt-bench"
7
+ spec.version = "0.0.3"
8
+ spec.authors = ["Toyokazu Akiyama"]
9
+ spec.email = ["toyokazu@gmail.com"]
10
+
11
+ spec.summary = %q{mqtt benchmark for ruby}
12
+ spec.description = %q{mqtt benchmark for ruby}
13
+ spec.homepage = "https://github.com/toyokazu/ruby-mqtt-bench"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.gsub(/images\/[\w\.]+\n/, "").split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "mqtt", "~> 0.3"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.10"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-mqtt-bench
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Toyokazu Akiyama
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mqtt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: mqtt benchmark for ruby
56
+ email:
57
+ - toyokazu@gmail.com
58
+ executables:
59
+ - mqtt_bench
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - README.md
66
+ - Rakefile
67
+ - bin/mqtt_bench
68
+ - conf/mqtt_bench.conf
69
+ - ruby-mqtt-bench.gemspec
70
+ homepage: https://github.com/toyokazu/ruby-mqtt-bench
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.5.1
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: mqtt benchmark for ruby
94
+ test_files: []