rbsim 0.0.3

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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.hgignore +6 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +66 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +960 -0
  8. data/TODO +28 -0
  9. data/basic_sim.rb +62 -0
  10. data/fast-tcpn.rb +3 -0
  11. data/lib/rbsim.rb +14 -0
  12. data/lib/rbsim/dsl.rb +30 -0
  13. data/lib/rbsim/dsl/infrastructure.rb +48 -0
  14. data/lib/rbsim/dsl/mapping.rb +32 -0
  15. data/lib/rbsim/dsl/process.rb +129 -0
  16. data/lib/rbsim/dsl/program.rb +10 -0
  17. data/lib/rbsim/experiment.rb +110 -0
  18. data/lib/rbsim/hlmodel.rb +25 -0
  19. data/lib/rbsim/hlmodel/infrastructure.rb +116 -0
  20. data/lib/rbsim/hlmodel/mapping.rb +5 -0
  21. data/lib/rbsim/hlmodel/process.rb +152 -0
  22. data/lib/rbsim/numeric_units.rb +107 -0
  23. data/lib/rbsim/simulator.rb +184 -0
  24. data/lib/rbsim/statistics.rb +77 -0
  25. data/lib/rbsim/tokens.rb +146 -0
  26. data/lib/rbsim/version.rb +3 -0
  27. data/new_process.rb +49 -0
  28. data/rbsim.gemspec +42 -0
  29. data/show_readme.rb +15 -0
  30. data/sim.rb +142 -0
  31. data/sim_bamboo.rb +251 -0
  32. data/sim_process.rb +83 -0
  33. data/sim_process_dsl.rb +58 -0
  34. data/spec/dsl/infrastructure_nets_spec.rb +39 -0
  35. data/spec/dsl/infrastructure_nodes_spec.rb +72 -0
  36. data/spec/dsl/infrastructure_routes_spec.rb +44 -0
  37. data/spec/dsl/mapping_spec.rb +70 -0
  38. data/spec/dsl/process_spec.rb +56 -0
  39. data/spec/dsl/program_spec.rb +36 -0
  40. data/spec/dsl_and_hlmodel/new_process_spec.rb +235 -0
  41. data/spec/hlmodel/net_spec.rb +112 -0
  42. data/spec/hlmodel/process_spec.rb +242 -0
  43. data/spec/hlmodel/route_spec.rb +47 -0
  44. data/spec/hlmodel/routes_spec.rb +44 -0
  45. data/spec/integration/basic_simulation_spec.rb +104 -0
  46. data/spec/integration/net_spec.rb +44 -0
  47. data/spec/integration/process_spec.rb +117 -0
  48. data/spec/integration/rbsim_spec.rb +40 -0
  49. data/spec/simulator/logger_spec.rb +35 -0
  50. data/spec/simulator/stats_spec.rb +93 -0
  51. data/spec/spec_helper.rb +26 -0
  52. data/spec/statistics_spec.rb +300 -0
  53. data/spec/tcpn/add_route_spec.rb +55 -0
  54. data/spec/tcpn/cpu_spec.rb +53 -0
  55. data/spec/tcpn/map_data_spec.rb +37 -0
  56. data/spec/tcpn/network_spec.rb +163 -0
  57. data/spec/tcpn/register_event_spec.rb +48 -0
  58. data/spec/tcpn/route_to_self_spec.rb +53 -0
  59. data/spec/tcpn/stats_spec.rb +77 -0
  60. data/spec/tokens/data_queue_obsolete.rb +121 -0
  61. data/spec/tokens/data_queue_spec.rb +111 -0
  62. data/spec/units_spec.rb +48 -0
  63. data/tcpn/model.rb +6 -0
  64. data/tcpn/model/add_route.rb +78 -0
  65. data/tcpn/model/application.rb +250 -0
  66. data/tcpn/model/cpu.rb +75 -0
  67. data/tcpn/model/map_data.rb +42 -0
  68. data/tcpn/model/network.rb +108 -0
  69. data/tcpn/model/register_event.rb +89 -0
  70. data/tcpn/model/stats.rb +46 -0
  71. metadata +221 -0
data/sim_bamboo.rb ADDED
@@ -0,0 +1,251 @@
1
+ require 'rbsim'
2
+
3
+ client_no = 1
4
+ router_no = 100
5
+ server_no = 10
6
+ request_per_client = 1000
7
+ request_gap = 30.miliseconds
8
+ long_prob = 0.01
9
+ REQUEST_TIMES = {
10
+ long: 5000.miliseconds,
11
+ short: 50.miliseconds
12
+ }
13
+
14
+ model = RBSim.model do
15
+
16
+ # gets array of server names and assigns
17
+ # requests to servers using round-robin, but
18
+ # next request is assigned to a server only
19
+ # when previous is served.
20
+ program :router do |servers|
21
+ request_queue = []
22
+ on_event :data_received do |data|
23
+ if data.type == :request
24
+ stats :requests, process.name
25
+ request_queue << data
26
+ stats_start :request_in_queue, process.name
27
+ register_event :process_request
28
+ stats_save request_queue.size, :rqueue_len, process.name
29
+ elsif data.type == :response
30
+ servers << data.src
31
+ send_data to: data.content[:from], size: data.size, type: :response, content: data.content[:content]
32
+ register_event :process_request
33
+ else
34
+ raise "Unknown data type #{data.type} received by #{process.name}"
35
+ end
36
+ end
37
+
38
+ on_event :process_request do
39
+ unless servers.empty? or request_queue.empty?
40
+ data = request_queue.shift
41
+ stats_stop :request_in_queue, process.name
42
+ server = servers.shift
43
+ stats_save request_queue.size, :rqueue_len, process.name
44
+ send_data to: server, size: data.size, type: :request, content: { from: data.src, content: data.content }
45
+ register_event :process_request unless request_queue.empty?
46
+ end
47
+ end
48
+ end
49
+
50
+ program :webserver do
51
+ on_event :data_received do |data|
52
+ if data.type == :request
53
+ tag = "request_#{data.content[:content][:length]}".to_sym
54
+ stats tag, process.name
55
+ stats :request, process.name
56
+ #log "#{process.name} got request #{data.content[:content][:number]} from #{data.content[:from]} #{data.content[:content][:length]}"
57
+ cpu do |cpu|
58
+ # request holds information about its processing time
59
+ REQUEST_TIMES[data.content[:content][:length]] / cpu.performance
60
+ end
61
+ data.content[:content].merge!({ server: process.name })
62
+ send_data to: data.src, size: data.size * 10, type: :response, content: data.content
63
+ else
64
+ raise "Unknown data type #{data.type} received by #{process.name}"
65
+ end
66
+ end
67
+ end
68
+
69
+ # opts are: count, delay, target
70
+ program :wget do |opts|
71
+ sent = 0
72
+ on_event :send do
73
+ length = if rand < opts[:long_prob]
74
+ stats :requests_long#, process.name
75
+ stats_start :requests_long#, process.name
76
+ :long
77
+ else
78
+ stats :requests_short#, process.name
79
+ stats_start :requests_short#, process.name
80
+ :short
81
+ end
82
+ content = { number: sent, length: length }
83
+ target = opts[:targets][rand opts[:targets].length]
84
+ send_data to: target, size: 1024.bytes, type: :request, content: content
85
+ #log "#{process.name} sent request #{sent} #{length}"
86
+ stats_start :request, process.name
87
+ stats_start "request_#{sent}".to_sym, process.name
88
+ sent += 1
89
+ register_event :send, delay: opts[:delay] if sent < opts[:count]
90
+ end
91
+
92
+ on_event :data_received do |data|
93
+ stats_stop :request, process.name
94
+ stats_stop "requests_#{data.content[:length]}".to_sym#, process.name
95
+ #log "#{process.name} got response #{data.content[:number]} #{data.content[:server]} #{data.content[:length]}"
96
+ stats :request_served, process.name
97
+ stats_stop "request_#{data.content[:number]}".to_sym, process.name
98
+ end
99
+
100
+ register_event :send
101
+ end
102
+
103
+
104
+
105
+
106
+
107
+ clients = (0..client_no - 1).map { |i| "client#{i}".to_sym }
108
+ routers = (0..router_no - 1).map { |i| "router#{i}".to_sym }
109
+ servers = (0..server_no - 1).map { |i| "thin#{i}".to_sym }
110
+
111
+ servers.each do |s|
112
+ node s do
113
+ cpu 1
114
+ end
115
+ new_process s, program: :webserver
116
+ put s, on: s
117
+ end
118
+
119
+
120
+ routers.each_with_index do |r, i|
121
+ new_process r, program: :router, args: servers.clone
122
+ node r do
123
+ cpu 1
124
+ end
125
+ put r, on: r
126
+ end
127
+
128
+ clients.each do |c|
129
+ new_process c, program: :wget, args: { count: request_per_client, delay: request_gap, targets: routers, long_prob: long_prob }
130
+ node c do
131
+ cpu 1
132
+ end
133
+ put c, on: c
134
+
135
+ routers.each do |r|
136
+ route from: c, to: r, via: [ :wan ], twoway: true
137
+ end
138
+ end
139
+
140
+ net :wan, bw: 102400.bps
141
+ net :lan, bw: 1024000.bps
142
+
143
+
144
+ servers.each do |s|
145
+ routers.each do |r|
146
+ route from: r, to: s, via: [ :lan ], twoway: true
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ prev_seconds = 0
153
+ model.tcpn.cb_for :clock, :after do |tag, event|
154
+ print "\b"*40
155
+ seconds = event.clock.in_seconds.truncate
156
+ print "Time: #{seconds} sec." if seconds > prev_seconds
157
+ prev_seconds = seconds
158
+ end
159
+
160
+ puts "Clients\t\t: #{client_no}"
161
+ puts "Routers\t\t: #{router_no}"
162
+ puts "Servers\t\t: #{server_no}"
163
+ puts "Requests\t: #{request_per_client}"
164
+ puts "Request gap\t: #{request_gap.in_miliseconds}ms"
165
+ puts "Long req. prob.\t: #{long_prob}"
166
+ puts "Request times\t: #{REQUEST_TIMES.map{ |n,t| "#{n}: #{t.in_miliseconds}ms"}.join ', '}"
167
+ puts
168
+
169
+ model.run
170
+
171
+ #model.stats_print
172
+ #p model.stats_summary
173
+
174
+ =begin
175
+ puts "======================="
176
+ puts "Routers' queue length"
177
+ model.stats_data[:application].values.each do |process, tag, time, values|
178
+ next unless tag == :rqueue_len
179
+ puts "#{process}\t#{time}: #{values.last}"
180
+ end
181
+ =end
182
+ puts
183
+
184
+ max_rqueue_len = model.stats_summary[:application][:values].map do |process, records|
185
+ records[:rqueue_len].map{ |time, values| values.last }.max
186
+ end.max
187
+
188
+ max_thinqueue_len = model.stats_summary[:resources][:values]['DATAQ LEN'].map do |process, records|
189
+ if process.to_s =~ /thin*/
190
+ records.map{ |time, values| values.last }.max
191
+ else
192
+ 0
193
+ end
194
+ end.max
195
+
196
+ #max_thinqueue_wait = model.stats_summary[:resources][:durations]['DATAQ WAIT'].select do |process, time|
197
+ # process.to_s =~ /thin*/
198
+ #end.values.max
199
+
200
+ max_thinq_wait = nil
201
+ model.stats_data[:resources].durations do |group, tag, start, stop|
202
+ next unless group == 'DATAQ WAIT'
203
+ next unless tag.to_s =~ /thin.*/
204
+ if max_thinq_wait.nil? || (stop - start) > max_thinq_wait[:time]
205
+ max_thinq_wait = { time: stop - start, tag: tag }
206
+ end
207
+ end
208
+
209
+ sum_rqueue_wait = 0
210
+ max_rqueue_wait = 0
211
+ model.stats_data[:application].durations do |group, tag, start, stop|
212
+ next unless group.to_s =~ /router.*/
213
+ next unless tag == :request_in_queue
214
+ wait = stop - start
215
+ sum_rqueue_wait += wait
216
+ max_rqueue_wait = wait if wait > max_rqueue_wait
217
+ end
218
+
219
+ summary_thinqueue_wait = model.stats_summary[:resources][:durations]['DATAQ WAIT'].select do |process, time|
220
+ process.to_s =~ /thin*/
221
+ end.values.reduce(:+)
222
+
223
+ puts
224
+ puts "Max rtr queue len\t: #{max_rqueue_len}"
225
+ puts "Max rtr queue wait\t: #{max_rqueue_wait.in_miliseconds}ms"
226
+ puts "Sum rtr queue wait\t: #{sum_rqueue_wait.in_miliseconds}ms"
227
+ puts "Avg rtr queue wait\t: #{(sum_rqueue_wait/(client_no*request_per_client)).in_miliseconds}ms"
228
+ puts "Max thin queue len\t: #{max_thinqueue_len}"
229
+ puts "Max thin queue wait\t: #{max_thinq_wait[:time].in_miliseconds}ms #{max_thinq_wait[:tag]}"
230
+ puts "Sum thin queue wait\t: #{summary_thinqueue_wait.in_miliseconds}ms"
231
+ puts "Avg. thin queue wait\t: #{(summary_thinqueue_wait/(client_no*request_per_client)).in_miliseconds}ms"
232
+
233
+ long_time = (model.stats_summary[:application][:durations][""][:requests_long] || 0).to_f
234
+ short_time = (model.stats_summary[:application][:durations][""][:requests_short] || 0).to_f
235
+ long_count = (model.stats_summary[:application][:counters][""][:requests_long] || 0).to_f
236
+ short_count = (model.stats_summary[:application][:counters][""][:requests_short] || 0).to_f
237
+
238
+ if short_count > 0
239
+ short_req_avg = short_time / short_count
240
+ puts "Short req. avg\t\t: #{short_req_avg.in_miliseconds}ms"
241
+ end
242
+
243
+ if long_count > 0
244
+ long_req_avg = long_time / long_count
245
+ puts "Long req. avg\t\t: #{long_req_avg.in_miliseconds}ms"
246
+ end
247
+
248
+ file = "rtr_#{router_no}_req_#{request_per_client}.dump"
249
+ model.stats_save file
250
+ puts "\nStats saved in #{file}"
251
+
data/sim_process.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'hlmodel'
2
+ require 'tcpn'
3
+
4
+ class ProcessToken < RBSim::HLModel::Process
5
+ include TCPN::TokenMethods
6
+ end
7
+
8
+ class CPU
9
+ attr_accessor :node, :performance
10
+ def initialize(node, performance)
11
+ @node, @performance = node, performance
12
+ end
13
+ end
14
+
15
+ class CPUToken < CPU
16
+ include TCPN::TokenMethods
17
+ end
18
+
19
+ class Handler
20
+ def call(*)
21
+ 2345
22
+ end
23
+ end
24
+
25
+ def doproc(&block)
26
+ return block
27
+ end
28
+
29
+ model = TCPN.read 'lib/tcpn/model/application.rb'
30
+
31
+ process = ProcessToken.new(:node01)
32
+ process.on_event :data do |process, args|
33
+ handler = proc do |cpu|
34
+ 4000 * args[:volume]/cpu.performance
35
+ end
36
+ process.register_event :cpu, block: handler
37
+ process.register_event :delay_for, time: 300
38
+ if args[:volume] > 10
39
+ process.register_event :data, volume: args[:volume]/10
40
+ else
41
+ constructor = proc do |process, args|
42
+ puts "===> FORKED <=="
43
+ process.register_event :delay_for, time: args
44
+ process.register_event :send_data, volume: args, type: :HTTP_REQUEST
45
+ end
46
+ process.register_event :new_process, program: :curl, constructor: constructor, constructor_args: 5000
47
+ end
48
+ process.register_event :send_data, volume: args[:volume], type: :response
49
+ end
50
+
51
+
52
+ #handler = Handler.new
53
+ handler = Proc.new { |cpu| 1000/cpu.performance } # java error if handler is set to Proc or lambda...
54
+ #handler = Proc.new { |cpu| 1000 } # java error if handler is set to Proc or lambda...
55
+ #handler = doproc do |cpu|
56
+ # 1000/cpu.performance
57
+ #end
58
+ process.register_event(:cpu, block: handler )
59
+ process.register_event(:cpu, block: handler )
60
+ process.register_event(:data, volume: 1000)
61
+ #process.register_event(:delay_for, time: 100)
62
+ model.add_marking_for 'process', process
63
+
64
+ cpu = CPUToken.new(:node01, 10)
65
+ model.add_marking_for 'CPU', cpu
66
+
67
+ sim = TCPN.sim model
68
+
69
+ sim.cb_for :transition, :after do |t, e|
70
+ puts "==> FIRING: #{e.transition} #{e.binding.map { |k, v| "#{k}: #{v}"}.join ',' }"
71
+ #puts model.marking
72
+ end
73
+
74
+ sim.cb_for :clock, :after do |t, e|
75
+ puts e.clock #if (tick += 1) % 100 == 0
76
+ end
77
+
78
+ sim.run
79
+
80
+ puts model.marking
81
+
82
+ process = sim.model.marking_for 'process'
83
+ p process
@@ -0,0 +1,58 @@
1
+ require 'rbsim'
2
+ require 'tcpn'
3
+
4
+ class CPU
5
+ attr_accessor :node, :performance
6
+ def initialize(node, performance)
7
+ @node, @performance = node, performance
8
+ end
9
+ end
10
+
11
+ class CPUToken < CPU
12
+ include TCPN::TokenMethods
13
+ end
14
+
15
+ hlmodel = RBSim.dsl do
16
+ new_process :worker do
17
+ on_event :data do |volume|
18
+ delay_for 100
19
+ cpu do |c|
20
+ 12/c.performance
21
+ end
22
+ end
23
+ delay_for 100
24
+ cpu do |cpu|
25
+ 100/cpu.performance
26
+ end
27
+ register_event :data, 1000
28
+ end
29
+ end
30
+
31
+
32
+ process_token = hlmodel.processes[:worker]
33
+ process_token.node = :node01
34
+ cpu_token = CPUToken.new(:node01, 10)
35
+
36
+
37
+ tcpn = TCPN.read 'lib/tcpn/model/application.rb'
38
+
39
+ tcpn.add_marking_for 'CPU', cpu_token
40
+ tcpn.add_marking_for 'process', process_token
41
+
42
+ sim = TCPN.sim tcpn
43
+
44
+ transitions = []
45
+ sim.cb_for :transition, :after do |t, e|
46
+ transitions << e.transition
47
+ puts "==> FIRING: #{e.transition} #{e.binding.map { |k, v| "#{k}: #{v}"}.join ',' }"
48
+ #puts model.marking
49
+ end
50
+
51
+ sim.run
52
+
53
+ p transitions
54
+
55
+ puts " MARKING ".center(70, '=')
56
+ tcpn.marking.each do |p, m|
57
+ puts "#{p}: #{m}"
58
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'RBSim#dsl' do
4
+ context "model with two nets" do
5
+
6
+ let(:model) do
7
+ RBSim.dsl do
8
+
9
+ net :net01, bw: 100, delay: 10
10
+ net :net02, bw: 1000, delay: 20, drop: 0.3
11
+
12
+ end
13
+ end
14
+
15
+ it "has two nets" do
16
+ expect(model.nets.size).to eq 2
17
+ end
18
+
19
+ it "has net called :net01" do
20
+ expect(model.nets.first.name).to eq :net01
21
+ end
22
+ context "net called :net01" do
23
+ subject { model.nets.first }
24
+ its(:bw) { should eq(100) }
25
+ its(:delay) { should eq(10) }
26
+ end
27
+
28
+ it "has net called :net02" do
29
+ expect(model.nets[1].name).to eq :net02
30
+ end
31
+ context "net called :net02" do
32
+ subject { model.nets[1] }
33
+ its(:bw) { should eq(1000) }
34
+ its(:delay) { should eq(20) }
35
+ its(:drop) { should eq(0.3) }
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe "RBSim#dsl" do
4
+ context "model with one empty node" do
5
+ let(:model) do
6
+ RBSim.dsl do
7
+ node :worker do
8
+ end
9
+ end
10
+ end
11
+
12
+ it "has one node" do
13
+ expect(model.nodes.size).to eq(1)
14
+ end
15
+
16
+ it "has node called :worker" do
17
+ expect(model.nodes.first.name).to eq(:worker)
18
+ end
19
+
20
+ it "has node with no CPUs" do
21
+ expect(model.nodes.first.cpus.size).to eq(0)
22
+ end
23
+
24
+ end
25
+
26
+ context "model with nodes and CPUs" do
27
+ let(:model) do
28
+ RBSim.dsl do
29
+
30
+ node :worker1 do
31
+ cpu 1000
32
+ cpu 2000
33
+ end
34
+ node :worker2 do
35
+ cpu 200
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ it "has two nodes" do
42
+ expect(model.nodes.size).to eq 2
43
+ end
44
+
45
+ it "has first node called :worker1" do
46
+ expect(model.nodes.first.name).to eq :worker1
47
+ end
48
+
49
+ it "has first node with two cpus" do
50
+ expect(model.nodes.first.cpus.size).to eq 2
51
+ end
52
+
53
+ it "has first node with first cpu with performance 1000" do
54
+ expect(model.nodes.first.cpus.first.performance).to eq 1000
55
+ end
56
+
57
+
58
+ it "has first node with second cpu with performance 2000" do
59
+ expect(model.nodes.first.cpus[1].performance).to eq 2000
60
+ end
61
+
62
+ it "has second node called :worker2" do
63
+ expect(model.nodes[1].name).to eq :worker2
64
+ end
65
+
66
+ it "has second node with cpu with performance 200" do
67
+ expect(model.nodes[1].cpus.first.performance).to eq 200
68
+ end
69
+
70
+ end
71
+
72
+ end