sisfc 0.1.0 → 0.2.0

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # taken from Jim Freeze's excellent article "Creating DSLs with Ruby"
2
4
  # http://www.artima.com/rubycs/articles/ruby_as_dsl.html
3
5
 
data/lib/sisfc/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SISFC
2
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
3
5
  end
data/lib/sisfc/vm.rb CHANGED
@@ -1,46 +1,61 @@
1
- require 'sisfc/event'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './event'
4
+ require_relative './logger'
2
5
  require 'erv'
3
6
 
7
+ class RequestInfo < Struct.new(:request, :service_time, :arrival_time)
8
+ include Comparable
9
+ def <=> (o)
10
+ arrival_time <=> o.arrival_time
11
+ end
12
+ end
4
13
 
5
14
  module SISFC
6
15
 
7
16
  class VM
17
+ include Logging
8
18
 
9
19
  # setup readable/accessible attributes
10
- ATTRIBUTES = [ :vmid, :dc_id, :size ]
11
-
12
- attr_reader *ATTRIBUTES
13
-
14
- def initialize(vmid, opts)
15
- # make sure all the required opts were provided
16
- [ :dc_id, :vm_size, :service_time_distribution ].each do |k|
17
- raise ArgumentError, "opts[:#{k}] missing" unless opts.has_key? k
18
- end
20
+ attr_reader :vmid, :dc_id, :size
19
21
 
22
+ def initialize(vmid, dc_id, size, service_time_distribution, opts={})
20
23
  @vmid = vmid
21
- @dcid = opts[:dc_id]
22
- @size = opts[:vm_size]
23
- @service_times_rv = ERV::RandomVariable.new(opts[:service_time_distribution][@size])
24
+ @dcid = dc_id
25
+ @size = size
26
+ @service_times_rv = ERV::RandomVariable.new(service_time_distribution[@size])
24
27
 
25
28
  # initialize request queue and related tracking information
26
29
  @busy = false
27
30
  @request_queue = []
28
31
 
32
+ @trace = opts[:trace] ? true : false
33
+ @notes = opts[:notes]
34
+
29
35
  # @request_queue_info = []
30
36
  # @request_currently_servicing = nil
31
37
  end
32
38
 
33
39
  def new_request(sim, r, time)
34
- # put the (request, service time, arrival time) tuple at the end of the queue
35
- @request_queue << [ r, @service_times_rv.next, time ]
40
+ # put request w/ metadata at the end of the queue
41
+ @request_queue << RequestInfo.new(r, @service_times_rv.next, time)
42
+
43
+ if @trace
44
+ @request_queue.each_cons(2) do |x,y|
45
+ if y[2] < x[2]
46
+ raise "Inconsistent ordering in request_queue!!!!"
47
+ end
48
+ end
49
+ end
36
50
 
37
51
  # update queue size tracking information
38
- # @request_queue_info << { :size => @request_queue.size, :time => time }
39
-
40
- unless @busy
41
- # try to allocate operator
42
- try_servicing_new_request(sim, time)
52
+ # @request_queue_info << { size: @request_queue.size, time: time }
53
+ if @trace and @request_queue.size % 100 == 0
54
+ logger.info "VM #{@vmid} with #{@notes} has #{@request_queue.size} requests in queue at time #{time} and is " +
55
+ (@busy ? "busy" : "not busy")
43
56
  end
57
+
58
+ try_servicing_new_request(sim, time) unless @busy
44
59
  end
45
60
 
46
61
  def request_finished(sim, time)
@@ -64,20 +79,24 @@ module SISFC
64
79
  raise "Busy VM (vmid: #{@vmid})!" if @busy
65
80
 
66
81
  unless @request_queue.empty?
82
+
67
83
  # pick request and metadata from the incoming request queue
68
- req, service_time, arrival_time = @request_queue.shift
84
+ ri = @request_queue.shift
69
85
 
70
- # update the request's queuing information
71
- req.queuing_completed(arrival_time, time - arrival_time)
86
+ if @trace
87
+ logger.info "VM #{@vmid} with #{@notes} fulfilling a new request at time #{time} for #{ri.service_time} seconds"
88
+ end
89
+
90
+ req = ri.request
72
91
 
73
- # the VM is busy now
74
- @busy = true
92
+ # update the request's queuing information
93
+ req.update_queuing_time(time - ri.arrival_time)
75
94
 
76
95
  # update the request's working information
77
- req.step_completed(time, time + service_time)
96
+ req.step_completed(ri.service_time)
78
97
 
79
98
  # schedule completion of workflow step
80
- sim.new_event(Event::ET_WORKFLOW_STEP_COMPLETED, req, time + service_time, self)
99
+ sim.new_event(Event::ET_WORKFLOW_STEP_COMPLETED, req, time + ri.service_time, self)
81
100
  end
82
101
  end
83
102
 
data/sisfc.gemspec CHANGED
@@ -18,10 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'activesupport', '~> 4.0.0'
22
- spec.add_dependency 'awesome_print', '~> 1.2.0'
23
- spec.add_dependency 'erv', '~> 0.0.2'
21
+ spec.add_dependency 'as-duration', '~> 0.1.1'
22
+ spec.add_dependency 'erv', '~> 0.3.5'
23
+ spec.add_dependency 'ice_nine', '~> 0.11.2'
24
24
 
25
- spec.add_development_dependency 'bundler', '~> 1.5.3'
26
- spec.add_development_dependency 'rake', '~> 10.1.1'
25
+ spec.add_development_dependency 'bundler', '~> 1.16'
26
+ spec.add_development_dependency 'dotenv', '~> 2.5'
27
+ spec.add_development_dependency 'rake', '~> 12.3'
28
+ spec.add_development_dependency 'minitest', '~> 5.11'
29
+ spec.add_development_dependency 'minitest-reporters', '~> 1.3'
30
+ spec.add_development_dependency 'minitest-spec-context', '~> 0.0.3'
27
31
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'sisfc'
5
+
6
+ require 'minitest/spec'
7
+ require 'minitest-spec-context'
8
+
9
+ require 'minitest/autorun'
@@ -1,6 +1,8 @@
1
- require 'test_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'sisfc/reference_configuration'
3
+ require 'minitest_helper'
4
+
5
+ require_relative './reference_configuration'
4
6
 
5
7
 
6
8
  describe SISFC::Configuration do
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_helper'
4
+
5
+ require_relative './reference_configuration'
6
+
7
+
8
+ describe SISFC::DataCenter do
9
+ it 'should create a valid public Cloud data center' do
10
+ args = { maximum_vm_capacity: lambda {|vms| true } }
11
+ dc = SISFC::DataCenter.new(id: :dc_name, name: "Some DC", type: :public, location_id: 1, **args)
12
+ end
13
+
14
+ it 'should create a valid private Cloud data center' do
15
+ args = { maximum_vm_capacity: lambda {|vms| true } }
16
+ dc = SISFC::DataCenter.new(id: :dc_name, name: "Some DC", type: :private, location_id: 1, **args)
17
+ end
18
+ end
19
+
@@ -1,10 +1,12 @@
1
- require 'test_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'sisfc/reference_configuration'
3
+ require 'minitest_helper'
4
+
5
+ require_relative './reference_configuration'
4
6
 
5
7
 
6
8
  describe SISFC::Evaluator do
7
- describe '.penalties' do
9
+ context '.penalties' do
8
10
  EXAMPLE_ALLOCATION = [
9
11
  { dc_id: 1, vm_size: :medium, vm_num: 20 },
10
12
  { dc_id: 1, vm_size: :large, vm_num: 30 },
@@ -1,20 +1,23 @@
1
- require 'tempfile'
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_helper'
2
4
 
3
- require 'test_helper'
5
+ require 'tempfile'
4
6
  require 'sisfc/generator'
5
7
 
8
+ require_relative './reference_configuration'
9
+
6
10
 
7
11
  describe SISFC::RequestGenerator do
8
12
 
9
- GENERATION_TIMES = [ Time.now, Time.now + 1.second, Time.now + 2.seconds ].map(&:to_f)
10
- DATA_CENTER_IDS = (1..GENERATION_TIMES.size).to_a
11
- ARRIVAL_TIMES = GENERATION_TIMES.map {|x| x + 1.0 }
12
- WORKFLOW_IDS = GENERATION_TIMES.map { rand(10) }
13
+ GENERATION_TIMES = [ Time.now, Time.now + 1.second, Time.now + 2.seconds ].map(&:to_f)
14
+ WORKFLOW_TYPE_IDS = GENERATION_TIMES.map { rand(10) }
15
+ CUSTOMER_IDS = GENERATION_TIMES.map { rand(5) }
13
16
  REQUEST_GENERATION_DATA=<<-END
14
- Generation Time,Data Center ID,Arrival Time,Workflow ID
15
- #{GENERATION_TIMES[0]},#{DATA_CENTER_IDS[0]},#{ARRIVAL_TIMES[0]},#{WORKFLOW_IDS[0]}
16
- #{GENERATION_TIMES[1]},#{DATA_CENTER_IDS[1]},#{ARRIVAL_TIMES[1]},#{WORKFLOW_IDS[1]}
17
- #{GENERATION_TIMES[2]},#{DATA_CENTER_IDS[2]},#{ARRIVAL_TIMES[2]},#{WORKFLOW_IDS[2]}
17
+ Generation Time,Workflow Type ID,Customer ID
18
+ #{GENERATION_TIMES[0]},#{WORKFLOW_TYPE_IDS[0]},#{CUSTOMER_IDS[0]}
19
+ #{GENERATION_TIMES[1]},#{WORKFLOW_TYPE_IDS[1]},#{CUSTOMER_IDS[1]}
20
+ #{GENERATION_TIMES[2]},#{WORKFLOW_TYPE_IDS[2]},#{CUSTOMER_IDS[2]}
18
21
  END
19
22
 
20
23
  it 'should read from CSV file' do
@@ -27,10 +30,10 @@ describe SISFC::RequestGenerator do
27
30
  with_reference_config(request_generation: { filename: tf.path }) do |conf|
28
31
  rg = SISFC::RequestGenerator.new(conf.request_generation)
29
32
  r = rg.generate
30
- r.rid.must_equal 1
31
- r.generation_time.must_equal GENERATION_TIMES[0]
32
- r.data_center_id.must_equal DATA_CENTER_IDS[0]
33
- r.arrival_time.must_equal ARRIVAL_TIMES[0]
33
+ r[:rid].must_equal 1
34
+ r[:generation_time].must_equal GENERATION_TIMES[0]
35
+ r[:workflow_type_id].must_equal WORKFLOW_TYPE_IDS[0]
36
+ r[:customer_id].must_equal CUSTOMER_IDS[0]
34
37
  end
35
38
 
36
39
  ensure
@@ -49,10 +52,10 @@ describe SISFC::RequestGenerator do
49
52
  with_reference_config(request_generation: { command: "cat #{tf.path}" }) do |conf|
50
53
  rg = SISFC::RequestGenerator.new(conf.request_generation)
51
54
  r = rg.generate
52
- r.rid.must_equal 1
53
- r.generation_time.must_equal GENERATION_TIMES[0]
54
- r.data_center_id.must_equal DATA_CENTER_IDS[0]
55
- r.arrival_time.must_equal ARRIVAL_TIMES[0]
55
+ r[:rid].must_equal 1
56
+ r[:generation_time].must_equal GENERATION_TIMES[0]
57
+ r[:workflow_type_id].must_equal WORKFLOW_TYPE_IDS[0]
58
+ r[:customer_id].must_equal CUSTOMER_IDS[0]
56
59
  end
57
60
  ensure
58
61
  # delete temporary file
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_helper'
4
+ require 'sisfc/latency_manager'
5
+
6
+ require_relative './reference_configuration'
7
+
8
+
9
+ describe SISFC::LatencyManager do
10
+ it 'should correctly work with reference configuration' do
11
+ SISFC::LatencyManager.new(LATENCY_MODELS)
12
+ end
13
+ end
@@ -0,0 +1,534 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sisfc/configuration'
4
+
5
+ START_TIME = Time.utc(1978, 'Aug', 12, 14, 30, 0).to_f
6
+ DURATION = 1.minute.to_f
7
+ WARMUP_DURATION = 10.seconds.to_f
8
+ SIMULATION_CHARACTERIZATION = <<END
9
+ # start time, duration, and warmup time for simulations
10
+ start_time Time.utc(1978, 'Aug', 12, 14, 30, 0)
11
+ duration 1.minute
12
+ warmup_duration 10.seconds
13
+ END
14
+
15
+
16
+ # characterization of data centers
17
+ DATA_CENTERS_CHARACTERIZATION = <<END
18
+ data_centers \
19
+ 1 => {
20
+ maximum_vm_capacity: {
21
+ tiny: 300,
22
+ small: 300,
23
+ medium: 300,
24
+ large: 300,
25
+ huge: 300,
26
+ },
27
+ location_id: 0,
28
+ },
29
+ 2 => {
30
+ maximum_vm_capacity: {
31
+ tiny: 300,
32
+ small: 300,
33
+ medium: 300,
34
+ large: 300,
35
+ huge: 300,
36
+ },
37
+ location_id: 1,
38
+ },
39
+ 3 => {
40
+ maximum_vm_capacity: {
41
+ tiny: 300,
42
+ small: 300,
43
+ medium: 300,
44
+ large: 300,
45
+ huge: 300,
46
+ },
47
+ location_id: 2,
48
+ },
49
+ 4 => {
50
+ maximum_vm_capacity: {
51
+ tiny: 300,
52
+ small: 300,
53
+ medium: 300,
54
+ large: 300,
55
+ huge: 300,
56
+ },
57
+ location_id: 3,
58
+ },
59
+ 5 => {
60
+ maximum_vm_capacity: {
61
+ tiny: 300,
62
+ small: 300,
63
+ medium: 300,
64
+ large: 300,
65
+ huge: 300,
66
+ },
67
+ location_id: 4,
68
+ }
69
+ END
70
+
71
+
72
+ LATENCY_MODELS_CHARACTERIZATION = <<END
73
+ latency_models \
74
+ [
75
+ # location 0
76
+ [
77
+ {
78
+ distribution: :gaussian,
79
+ args: {
80
+ mean: 0.009,
81
+ sd: 0.001,
82
+ },
83
+ },
84
+ {
85
+ distribution: :gaussian,
86
+ args: {
87
+ mean: 0.009,
88
+ sd: 0.001,
89
+ },
90
+ },
91
+ {
92
+ distribution: :gaussian,
93
+ args: {
94
+ mean: 0.009,
95
+ sd: 0.001,
96
+ },
97
+ },
98
+ {
99
+ distribution: :gaussian,
100
+ args: {
101
+ mean: 0.009,
102
+ sd: 0.001,
103
+ },
104
+ },
105
+ {
106
+ distribution: :gaussian,
107
+ args: {
108
+ mean: 0.009,
109
+ sd: 0.001,
110
+ },
111
+ },
112
+ {
113
+ distribution: :gaussian,
114
+ args: {
115
+ mean: 0.009,
116
+ sd: 0.001,
117
+ },
118
+ },
119
+ {
120
+ distribution: :gaussian,
121
+ args: {
122
+ mean: 0.009,
123
+ sd: 0.001,
124
+ },
125
+ },
126
+ {
127
+ distribution: :gaussian,
128
+ args: {
129
+ mean: 0.009,
130
+ sd: 0.001,
131
+ },
132
+ },
133
+ ],
134
+ # location 1
135
+ [
136
+ {
137
+ distribution: :gaussian,
138
+ args: {
139
+ mean: 0.009,
140
+ sd: 0.001,
141
+ },
142
+ },
143
+ {
144
+ distribution: :gaussian,
145
+ args: {
146
+ mean: 0.009,
147
+ sd: 0.001,
148
+ },
149
+ },
150
+ {
151
+ distribution: :gaussian,
152
+ args: {
153
+ mean: 0.009,
154
+ sd: 0.001,
155
+ },
156
+ },
157
+ {
158
+ distribution: :gaussian,
159
+ args: {
160
+ mean: 0.009,
161
+ sd: 0.001,
162
+ },
163
+ },
164
+ {
165
+ distribution: :gaussian,
166
+ args: {
167
+ mean: 0.009,
168
+ sd: 0.001,
169
+ },
170
+ },
171
+ {
172
+ distribution: :gaussian,
173
+ args: {
174
+ mean: 0.009,
175
+ sd: 0.001,
176
+ },
177
+ },
178
+ {
179
+ distribution: :gaussian,
180
+ args: {
181
+ mean: 0.009,
182
+ sd: 0.001,
183
+ },
184
+ },
185
+ ],
186
+ # location 2
187
+ [
188
+ {
189
+ distribution: :gaussian,
190
+ args: {
191
+ mean: 0.009,
192
+ sd: 0.001,
193
+ },
194
+ },
195
+ {
196
+ distribution: :gaussian,
197
+ args: {
198
+ mean: 0.009,
199
+ sd: 0.001,
200
+ },
201
+ },
202
+ {
203
+ distribution: :gaussian,
204
+ args: {
205
+ mean: 0.009,
206
+ sd: 0.001,
207
+ },
208
+ },
209
+ {
210
+ distribution: :gaussian,
211
+ args: {
212
+ mean: 0.009,
213
+ sd: 0.001,
214
+ },
215
+ },
216
+ {
217
+ distribution: :gaussian,
218
+ args: {
219
+ mean: 0.009,
220
+ sd: 0.001,
221
+ },
222
+ },
223
+ {
224
+ distribution: :gaussian,
225
+ args: {
226
+ mean: 0.009,
227
+ sd: 0.001,
228
+ },
229
+ },
230
+ ],
231
+ # location 3
232
+ [
233
+ {
234
+ distribution: :gaussian,
235
+ args: {
236
+ mean: 0.009,
237
+ sd: 0.001,
238
+ },
239
+ },
240
+ {
241
+ distribution: :gaussian,
242
+ args: {
243
+ mean: 0.009,
244
+ sd: 0.001,
245
+ },
246
+ },
247
+ {
248
+ distribution: :gaussian,
249
+ args: {
250
+ mean: 0.009,
251
+ sd: 0.001,
252
+ },
253
+ },
254
+ {
255
+ distribution: :gaussian,
256
+ args: {
257
+ mean: 0.009,
258
+ sd: 0.001,
259
+ },
260
+ },
261
+ {
262
+ distribution: :gaussian,
263
+ args: {
264
+ mean: 0.009,
265
+ sd: 0.001,
266
+ },
267
+ },
268
+ ],
269
+ # location 4
270
+ [
271
+ {
272
+ distribution: :gaussian,
273
+ args: {
274
+ mean: 0.009,
275
+ sd: 0.001,
276
+ },
277
+ },
278
+ {
279
+ distribution: :gaussian,
280
+ args: {
281
+ mean: 0.009,
282
+ sd: 0.001,
283
+ },
284
+ },
285
+ {
286
+ distribution: :gaussian,
287
+ args: {
288
+ mean: 0.009,
289
+ sd: 0.001,
290
+ },
291
+ },
292
+ {
293
+ distribution: :gaussian,
294
+ args: {
295
+ mean: 0.009,
296
+ sd: 0.001,
297
+ },
298
+ },
299
+ ],
300
+ # location 5
301
+ [
302
+ {
303
+ distribution: :gaussian,
304
+ args: {
305
+ mean: 0.009,
306
+ sd: 0.001,
307
+ },
308
+ },
309
+ {
310
+ distribution: :gaussian,
311
+ args: {
312
+ mean: 0.009,
313
+ sd: 0.001,
314
+ },
315
+ },
316
+ {
317
+ distribution: :gaussian,
318
+ args: {
319
+ mean: 0.009,
320
+ sd: 0.001,
321
+ },
322
+ },
323
+ ],
324
+ # location 6
325
+ [
326
+ {
327
+ distribution: :gaussian,
328
+ args: {
329
+ mean: 0.009,
330
+ sd: 0.001,
331
+ },
332
+ },
333
+ {
334
+ distribution: :gaussian,
335
+ args: {
336
+ mean: 0.009,
337
+ sd: 0.001,
338
+ },
339
+ },
340
+ ],
341
+ # location 7
342
+ [
343
+ {
344
+ distribution: :gaussian,
345
+ args: {
346
+ mean: 0.009,
347
+ sd: 0.001,
348
+ },
349
+ },
350
+ ],
351
+ ]
352
+ END
353
+
354
+
355
+ CUSTOMER_CHARACTERIZATION = <<END
356
+ customers \
357
+ [
358
+ # first customer (id: 0) is in location with id=5 (?)
359
+ { location_id: 5 },
360
+ # second customer (id: 1) is in location with id=6 (?)
361
+ { location_id: 6 },
362
+ # third customer (id: 2) is in location with id=7 (?)
363
+ { location_id: 7 },
364
+ # fourth customer (id: 3) is in location with id=8 (?)
365
+ { location_id: 8 },
366
+ ]
367
+ END
368
+
369
+
370
+ # characterization of component types
371
+ SERVICE_COMPONENT_TYPES_CHARACTERIZATION = <<END
372
+ service_component_types \
373
+ 'Web Server' => {
374
+ allowed_vm_types: [ :medium, :large ],
375
+ service_time_distribution: {
376
+ medium: { distribution: :gaussian,
377
+ mean: 0.009, # 1 request processed every 9ms
378
+ sd: 0.001 },
379
+ large: { distribution: :gaussian,
380
+ mean: 0.007, # 1 request processed every 7ms
381
+ sd: 0.001 } },
382
+ estimated_workload: 50,
383
+ },
384
+ 'App Server' => {
385
+ allowed_vm_types: [ :medium, :large, :huge ],
386
+ service_time_distribution: {
387
+ medium: { distribution: :gaussian,
388
+ mean: 0.015, # 1 request processed every 15ms
389
+ sd: 0.005 },
390
+ large: { distribution: :gaussian,
391
+ mean: 0.012, # 1 request processed every 12ms
392
+ sd: 0.003 },
393
+ huge: { distribution: :gaussian,
394
+ mean: 0.009, # 1 request processed every 7ms
395
+ sd: 0.002 } },
396
+ estimated_workload: 70,
397
+ },
398
+ 'Financial Transaction Server' => {
399
+ allowed_vm_types: [ :large, :huge ],
400
+ service_time_distribution: {
401
+ large: { distribution: :gaussian,
402
+ mean: 0.015, # 1 request processed every 15ms
403
+ sd: 0.004 },
404
+ huge: { distribution: :gaussian,
405
+ mean: 0.008, # 1 request processed every 8ms
406
+ sd: 0.003 } },
407
+ estimated_workload: 80,
408
+ }
409
+ END
410
+
411
+
412
+ # workflow (or job) types descriptions
413
+ WORKFLOW_TYPES_CHARACTERIZATION = <<END
414
+ workflow_types \
415
+ 1 => {
416
+ component_sequence: [
417
+ { name: 'Web Server' },
418
+ { name: 'App Server' },
419
+ { name: 'Financial Transaction Server' },
420
+ ],
421
+ next_component_selection: :random,
422
+ },
423
+ 2 => {
424
+ component_sequence: [
425
+ { name: 'Web Server' },
426
+ { name: 'App Server' },
427
+ ],
428
+ # next_component_selection: :least_loaded,
429
+ next_component_selection: :random,
430
+ }
431
+ END
432
+
433
+
434
+ CONSTRAINT_CHARACTERIZATION = <<END
435
+ constraints \
436
+ 'Web Server' => [
437
+ { data_center: 1, min: 0, max: 300 },
438
+ { data_center: 2, min: 0, max: 300 },
439
+ { data_center: 3, min: 0, max: 300 },
440
+ { data_center: 4, min: 0, max: 300 },
441
+ { data_center: 5, min: 0, max: 300 },
442
+ ],
443
+ 'App Server' => [
444
+ { data_center: 1, min: 0, max: 300 },
445
+ { data_center: 2, min: 0, max: 300 },
446
+ { data_center: 3, min: 0, max: 300 },
447
+ { data_center: 4, min: 0, max: 300 },
448
+ { data_center: 5, min: 0, max: 300 },
449
+ ],
450
+ 'Financial Transaction Server' => [
451
+ { data_center: 1, number: 1 },
452
+ { data_center: 2, number: 0 },
453
+ { data_center: 3, number: 0 },
454
+ { data_center: 4, number: 0 },
455
+ { data_center: 5, number: 0 },
456
+ ]
457
+ END
458
+
459
+
460
+ REQUEST_GENERATION_CHARACTERIZATION = <<END
461
+ request_generation \
462
+ command: "<pwd>/generator.R"
463
+ END
464
+
465
+
466
+ KPI_CUSTOMIZATION_CHARACTERIZATION = <<END
467
+ kpi_customization \
468
+ longer_than: [ 2.0, 5.0 ] # count number of requests longer than 2 and 5 seconds respectively
469
+ END
470
+
471
+
472
+ EVALUATION_CHARACTERIZATION = <<END
473
+ evaluation \
474
+ vm_hourly_cost: [
475
+ { data_center: 1, vm_type: :medium, cost: 0.160 },
476
+ { data_center: 1, vm_type: :large, cost: 0.320 },
477
+ { data_center: 2, vm_type: :medium, cost: 0.184 },
478
+ { data_center: 2, vm_type: :large, cost: 0.368 }
479
+ ],
480
+ # 500$ penalties if MTTR takes more than 50 msecs
481
+ penalties: lambda {|kpis,dc_kpis| 500.0 if kpis[:mttr] > 0.050 }
482
+ END
483
+
484
+ # this is the whole reference configuration
485
+ # (useful for spec'ing configuration.rb)
486
+ REFERENCE_CONFIGURATION =
487
+ SIMULATION_CHARACTERIZATION +
488
+ DATA_CENTERS_CHARACTERIZATION +
489
+ LATENCY_MODELS_CHARACTERIZATION +
490
+ CUSTOMER_CHARACTERIZATION +
491
+ SERVICE_COMPONENT_TYPES_CHARACTERIZATION +
492
+ WORKFLOW_TYPES_CHARACTERIZATION +
493
+ CONSTRAINT_CHARACTERIZATION +
494
+ REQUEST_GENERATION_CHARACTERIZATION +
495
+ KPI_CUSTOMIZATION_CHARACTERIZATION +
496
+ EVALUATION_CHARACTERIZATION
497
+
498
+
499
+ evaluator = Object.new
500
+ evaluator.extend SISFC::Configurable
501
+ evaluator.instance_eval(REFERENCE_CONFIGURATION)
502
+
503
+ # these are preprocessed portions of the reference configuration
504
+ # (useful for spec'ing everything else)
505
+ DATA_CENTERS = evaluator.data_centers
506
+ SERVICE_COMPONENT_TYPES = evaluator.service_component_types
507
+ WORKFLOW_TYPES = evaluator.workflow_types
508
+ EVALUATION = evaluator.evaluation
509
+ LATENCY_MODELS = evaluator.latency_models
510
+
511
+
512
+ def with_reference_config(opts={})
513
+ begin
514
+ # create temporary file with reference configuration
515
+ tf = Tempfile.open('REFERENCE_CONFIGURATION')
516
+ tf.write(REFERENCE_CONFIGURATION)
517
+ tf.close
518
+
519
+ # create a configuration object from the reference configuration file
520
+ conf = SISFC::Configuration.load_from_file(tf.path)
521
+
522
+ # apply any change from the opts parameter and validate the modified configuration
523
+ opts.each do |k,v|
524
+ conf.send(k, v)
525
+ end
526
+ conf.validate
527
+
528
+ # pass the configuration object to the block
529
+ yield conf
530
+ ensure
531
+ # delete temporary file
532
+ tf.delete
533
+ end
534
+ end