1classdef LayeredNetworkGenerator < handle
2 % A generator
object that generates layered queueing network models
3 % based on user specification. Characteristics of generated
4 % models can be configured via the generator
's properties. See
5 % user guide in report for detailed usage instructions.
8 populationRange (1, 2) double
9 thinkTimeRange (1, 2) double
10 taskInfProbability (1, 1) double
11 procInfProbability (1, 1) double
12 taskMultiRange (1, 2) double
13 procMultiRange (1, 2) double
14 hostDemandRange (1, 2) double
15 synchCallRange (1, 2) double
18 properties (SetAccess = private)
32 function obj = LayeredNetworkGenerator(varargin)
34 addParameter(p, 'populationRange
', [1, 1]);
35 addParameter(p, 'thinkTimeRange
', [1, 1]);
36 addParameter(p, 'taskInfProbability
', 0);
37 addParameter(p, 'procInfProbability
', 0);
38 addParameter(p, 'taskMultiRange
', [1, 1]);
39 addParameter(p, 'procMultiRange
', [1, 1]);
40 addParameter(p, 'hostDemandRange
', [1, 1]);
41 addParameter(p, 'synchCallRange
', [1, 1]);
42 parse(p, varargin{:});
44 obj.populationRange = p.Results.populationRange;
45 obj.thinkTimeRange = p.Results.thinkTimeRange;
46 obj.taskInfProbability = p.Results.taskInfProbability;
47 obj.procInfProbability = p.Results.procInfProbability;
48 obj.taskMultiRange = p.Results.taskMultiRange;
49 obj.procMultiRange = p.Results.procMultiRange;
50 obj.hostDemandRange = p.Results.hostDemandRange;
51 obj.synchCallRange = p.Results.synchCallRange;
54 function set.populationRange(obj, range)
55 if range(1) > 0 && range(1) <= range(2)
56 obj.populationRange(1) = range(1);
57 obj.populationRange(2) = range(2);
59 error('NG:populationRange
', 'Population range
is not valid
');
63 function set.thinkTimeRange(obj, range)
64 if range(1) >= 0 && range(1) <= range(2)
65 obj.thinkTimeRange(1) = range(1);
66 obj.thinkTimeRange(2) = range(2);
68 error('NG:thinkTimeRange
', 'Think time range
is not valid
');
72 function set.taskInfProbability(obj, probability)
73 if probability >= 0 && probability <= 1
74 obj.taskInfProbability = probability;
76 error('NG:taskInfProbability
', 'Task infinite probability
is not valid
');
80 function set.procInfProbability(obj, probability)
81 if probability >= 0 && probability <= 1
82 obj.procInfProbability = probability;
84 error('NG:procInfProbability
', 'Processor infinite probability
is not valid
');
88 function set.taskMultiRange(obj, range)
89 if range(1) > 0 && range(1) <= range(2)
90 obj.taskMultiRange(1) = range(1);
91 obj.taskMultiRange(2) = range(2);
93 error('NG:taskMultiRange
', 'Task multiplicity range
is not valid
');
97 function set.procMultiRange(obj, range)
98 if range(1) > 0 && range(1) <= range(2)
99 obj.procMultiRange(1) = range(1);
100 obj.procMultiRange(2) = range(2);
102 error('NG:procMultiRange
', 'Processor multiplicity range
is not valid
');
106 function set.hostDemandRange(obj, range)
107 if range(1) >= 0 && range(1) <= range(2)
108 obj.hostDemandRange(1) = range(1);
109 obj.hostDemandRange(2) = range(2);
111 error('NG:hostDemandRange
', 'Host demand range
is not valid
');
115 function set.synchCallRange(obj, range)
116 if range(1) > 0 && range(1) <= range(2)
117 obj.synchCallRange(1) = range(1);
118 obj.synchCallRange(2) = range(2);
120 error('NG:synchCallRange
', 'Synchronous call range
is not valid
');
124 % Main function to call. Returns a generated LQN model according to
125 % specified properties of the LayeredNetworkGenerator object
126 function model = generate(obj, numClients, numLevels, numTasks, numProcessors)
127 obj.validateArgs(numClients, numLevels, numTasks, numProcessors);
128 model = LayeredNetwork('lnw
');
129 obj.createClients(model, numClients);
130 obj.createTasks(model, numTasks);
131 obj.createProcessors(model, numProcessors);
132 obj.assignTasks(numLevels, numTasks, numProcessors);
133 obj.connectClientsToTasks(numClients);
134 obj.connectTasksToTasks(numLevels);
135 obj.connectTasksToProcessors(numProcessors);
139 methods (Access = private)
140 % Validates that parameter values for the network are sound
141 function validateArgs(~, numClients, numLevels, numTasks, numProcessors)
143 error('NG:invalidArgs
', 'Number of clients
is less than one
');
145 error('NG:invalidArgs
', 'Number of levels
is less than one
');
147 error('NG:invalidArgs
', 'Number of tasks
is less than one
');
148 elseif numProcessors < 1
149 error('NG:invalidArgs
', 'Number of processors
is less than one
');
150 elseif numLevels > numTasks
151 error('NG:invalidArgs
', 'Number of levels
is greater than that of tasks
');
152 elseif numProcessors > numTasks
153 error('NG:invalidArgs
', 'Number of processors
is greater than that of tasks
');
157 % Creates the clients in the layered network
158 function createClients(obj, model, numClients)
159 obj.cActivities = cell(numClients, 1);
160 obj.cEntries = cell(numClients, 1);
161 obj.cTasks = cell(numClients, 1);
162 obj.cProcessors = cell(numClients, 1);
163 for c = 1 : numClients
164 population = LayeredNetworkGenerator.sampleIntegerValue(obj.populationRange);
165 thinkTime = LayeredNetworkGenerator.sampleRealValue(obj.thinkTimeRange);
167 obj.cActivities{c} = Activity(model, ['c_activity_
', int2str(c)], thinkTime);
168 obj.cEntries{c} = Entry(model, ['c_entry_
', int2str(c)]);
169 obj.cTasks{c} = Task(model, ['c_task_
', int2str(c)], population, SchedStrategy.REF);
170 obj.cProcessors{c} = Processor(model, ['c_processor_
', int2str(c)], Inf, SchedStrategy.INF);
172 obj.cActivities{c}.on(obj.cTasks{c}).boundTo(obj.cEntries{c});
173 obj.cEntries{c}.on(obj.cTasks{c});
174 obj.cTasks{c}.on(obj.cProcessors{c});
178 % Creates the tasks in the layered network
179 function createTasks(obj, model, numTasks)
180 obj.activities = cell(numTasks, 1);
181 obj.entries = cell(numTasks, 1);
182 obj.tasks = cell(numTasks, 1);
184 isInfinite = LayeredNetworkGenerator.chooseBooleanValue(obj.taskInfProbability);
187 scheduling = SchedStrategy.INF;
189 multiplicity = LayeredNetworkGenerator.sampleIntegerValue(obj.taskMultiRange);
190 scheduling = SchedStrategy.FCFS;
192 hostDemand = LayeredNetworkGenerator.sampleRealValue(obj.hostDemandRange);
194 obj.activities{t} = Activity(model, ['activity_
', int2str(t)], hostDemand);
195 obj.entries{t} = Entry(model, ['entry_
', int2str(t)]);
196 obj.tasks{t} = Task(model, ['task_
', int2str(t)], multiplicity, scheduling);
198 obj.activities{t}.on(obj.tasks{t}).boundTo(obj.entries{t}).repliesTo(obj.entries{t});
199 obj.entries{t}.on(obj.tasks{t});
203 % Creates the processors in the layered network
204 function createProcessors(obj, model, numProcessors)
205 obj.processors = cell(numProcessors, 1);
206 for i = 1 : numProcessors
207 isInfinite = LayeredNetworkGenerator.chooseBooleanValue(obj.procInfProbability);
210 scheduling = SchedStrategy.INF;
212 multiplicity = LayeredNetworkGenerator.sampleIntegerValue(obj.procMultiRange);
213 scheduling = SchedStrategy.PS;
216 obj.processors{i} = Processor(model, ['processor_
', int2str(i)], multiplicity, scheduling);
220 % Assigns the tasks to different levels and processors
221 function assignTasks(obj, numLevels, numTasks, numProcessors)
222 obj.numTasksPerLevel = LayeredNetworkGenerator.makeIntegerVector(numLevels, numTasks);
223 obj.numTasksPerProcessor = LayeredNetworkGenerator.makeIntegerVector(numProcessors, numTasks);
226 % Connects the clients to the tasks
227 function connectClientsToTasks(obj, numClients)
228 clientConnected = false(1, numClients);
229 for t = 1 : obj.numTasksPerLevel(1)
230 synchCall = LayeredNetworkGenerator.sampleRealValue(obj.synchCallRange);
232 c = LayeredNetworkGenerator.sampleIntegerValue([1, numClients]);
233 obj.cActivities{c}.synchCall(obj.entries{t}, synchCall);
234 clientConnected(c) = true;
237 for c = 1 : numClients
238 if clientConnected(c)
242 synchCall = LayeredNetworkGenerator.sampleRealValue(obj.synchCallRange);
244 t = LayeredNetworkGenerator.sampleIntegerValue([1, obj.numTasksPerLevel(1)]);
245 obj.cActivities{c}.synchCall(obj.entries{t}, synchCall);
246 clientConnected(c) = true;
250 % Connects the tasks between adjacent levels
251 function connectTasksToTasks(obj, numLevels)
252 numTasks = obj.numTasksPerLevel(1);
253 for l = 2 : numLevels
254 for t2 = numTasks + (1 : obj.numTasksPerLevel(l))
255 synchCall = LayeredNetworkGenerator.sampleRealValue(obj.synchCallRange);
257 t1 = LayeredNetworkGenerator.sampleIntegerValue(numTasks - [obj.numTasksPerLevel(l - 1) - 1, 0]);
258 obj.activities{t1}.synchCall(obj.entries{t2}, synchCall);
260 numTasks = numTasks + obj.numTasksPerLevel(l);
264 % Connects the tasks to the processors
265 function connectTasksToProcessors(obj, numProcessors)
267 for p = 1 : numProcessors
268 for t = numTasks + (1 : obj.numTasksPerProcessor(p))
269 obj.tasks{t}.on(obj.processors{p});
271 numTasks = numTasks + obj.numTasksPerProcessor(p);
277 % Samples an integer value from a given range
278 function value = sampleIntegerValue(range)
279 value = randi([ceil(range(1)), floor(range(2))]);
282 % Samples a real value from a given range
283 function value = sampleRealValue(range)
284 value = range(1) + (range(2) - range(1)) * rand();
287 % Chooses a boolean value for a given probability
288 function value = chooseBooleanValue(probability)
289 value = rand() < probability;
292 % Makes an integer vector with given length and sum
293 function vector = makeIntegerVector(length, sum)
294 vector = ones(length, 1);
295 for s = 1 : sum - length
296 i = randi([1, length]);
297 vector(i) = vector(i) + 1;