rbsim 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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