sisfc 0.1.0 → 0.2.0

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