LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
afterEventStation.m
1function [outspace, outrate, outprob, eventCache] = afterEventStation(sn, ind, inspace, event, class, isSimulation, eventCache, ...
2 M, R, S, phasessz, phaseshift, pie, isf, ismkvmod, ismkvmodclass, lldscaling, lldlimit, cdscaling, ...
3 hasOnlyExp, ist, K, Ks, mu, phi, proc, capacity, classcap, V, space_buf, space_srv, space_var, key)
4outspace = [];
5outrate = [];
6outprob = 1;
7switch event
8 case EventType.ARV %% passive
9 % return if there is no space to accept the arrival
10 [ni,nir] = State.toMarginalAggr(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
11 % otherwise check scheduling strategy
12 pentry = pie{ist}{class};
13 % For Place nodes (INF scheduling with NaN service), use uniform entry probability
14 if all(isnan(pentry))
15 pentry = ones(size(pentry)) / length(pentry);
16 end
17 outprob = [];
18 outprob_k = [];
19 for kentry = 1:K(class)
20 space_var_k = space_var;
21 space_srv_k = space_srv;
22 space_buf_k = space_buf;
23 switch sn.sched(ist)
24 case SchedStrategy.EXT % source, can receive any "virtual" arrival from the sink as long as it is from an open class
25 if isinf(sn.njobs(class))
26 outspace = inspace;
27 outrate = -1*zeros(size(outspace,1)); % passive action, rate is unspecified
28 outprob = ones(size(outspace,1));
29 break
30 end
31 case {SchedStrategy.PS, SchedStrategy.INF, SchedStrategy.DPS, SchedStrategy.GPS, SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, SchedStrategy.LPS}
32 % job enters service immediately
33 if space_srv_k(:,Ks(class)+kentry) < classcap(ist,class)
34 space_srv_k(:,Ks(class)+kentry) = space_srv_k(:,Ks(class)+kentry) + 1;
35 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
36 else
37 outprob_k = pentry(kentry)*zeros(size(space_srv_k,1));
38 end
39 case {SchedStrategy.SIRO, SchedStrategy.SEPT, SchedStrategy.LEPT}
40 if ni<S(ist)
41 space_srv_k(:,Ks(class)+kentry) = space_srv_k(:,Ks(class)+kentry) + 1;
42 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
43 else
44 space_buf_k(:,class) = space_buf_k(:,class) + 1;
45 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
46 end
47 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS, SchedStrategy.LCFSPRIO}
48 % find states with all servers busy - this
49 % needs not to be moved
50
51 % if MAP service, when empty restart from the phase
52 % stored in space_var for this class
53 if ~ismkvmodclass(class) || (ismkvmodclass(class) && kentry == space_var(sum(sn.nvars(ind,1:class))))
54 if ismkvmodclass(class)
55 pentry = zeros(size(pentry));
56 pentry(kentry) = 1.0;
57 end
58 all_busy_srv = sum(space_srv_k,2) >= S(ist);
59
60 % find and modify states with an idle server
61 idle_srv = sum(space_srv_k,2) < S(ist);
62 space_srv_k(idle_srv, end-sum(K)+Ks(class)+kentry) = space_srv_k(idle_srv,end-sum(K)+Ks(class)+kentry) + 1; % job enters service
63
64 % this section dynamically grows the number of
65 % elements in the buffer
66
67 if any(ni < capacity(ist))
68 if any(nir(:,class) < classcap(ist,class)) % if there is room
69 if ~any(space_buf_k(:)==0) % but the buffer has no empty slots
70 % append job slot
71 space_buf_k = [zeros(size(space_buf_k,1),1),space_buf_k];
72 end
73 end
74 end
75 %end
76 %get position of first empty slot
77 empty_slots = -1*ones(size(all_busy_srv,1),1);
78 if size(space_buf_k,2) == 0
79 empty_slots(all_busy_srv) = false;
80 elseif size(space_buf_k,2) == 1
81 empty_slots(all_busy_srv) = space_buf_k(all_busy_srv,:)==0;
82 else
83 empty_slots(all_busy_srv) = max(bsxfun(@times, space_buf_k(all_busy_srv,:)==0, [1:size(space_buf_k,2)]),[],2);
84 end
85
86 % ignore states where the buffer has no empty slots
87 wbuf_empty = empty_slots>0;
88 if any(wbuf_empty)
89 space_srv_k = space_srv_k(wbuf_empty,:);
90 space_buf_k = space_buf_k(wbuf_empty,:);
91 space_var_k = space_var_k(wbuf_empty,:);
92 empty_slots = empty_slots(wbuf_empty);
93 space_buf_k(sub2ind(size(space_buf_k),1:size(space_buf_k,1),empty_slots')) = class;
94 %outspace(all_busy_srv(wbuf_empty),:) = [space_buf, space_srv, space_var];
95 end
96 outprob_k = pentry(kentry)*ones(size(space_srv_k,1),1);
97 else
98 outprob_k = 0*ones(size(space_srv_k,1),1); % zero probability event
99 end
100 case {SchedStrategy.FCFSPR,SchedStrategy.FCFSPI,SchedStrategy.FCFSPRPRIO,SchedStrategy.FCFSPIPRIO,SchedStrategy.LCFSPR,SchedStrategy.LCFSPI,SchedStrategy.LCFSPRPRIO,SchedStrategy.LCFSPIPRIO}
101 % find states with all servers busy - this
102 % must not be moved
103 all_busy_srv = sum(space_srv_k,2) >= S(ist);
104 % find states with an idle server
105 idle_srv = sum(space_srv_k,2) < S(ist);
106
107 % reorder states so that idle ones come first
108 space_buf_k_reord = space_buf_k(idle_srv,:);
109 space_srv_k_reord = space_srv_k(idle_srv,:);
110 space_var_k_reord = space_var_k(idle_srv,:);
111
112 % if idle, the job enters service in phase kentry
113 if any(idle_srv)
114 space_srv_k_reord(:, end-sum(K)+Ks(class)+kentry) = space_srv_k_reord(:,end-sum(K)+Ks(class)+kentry) + 1;
115 outprob_k = pentry(kentry);
116 else
117 % if all busy, expand output states for all possible choices of job class to preempt
118 psentry = ones(size(space_buf_k_reord,1),1); % probability scaling due to preemption
119 hasDiffPrio = ~all(sn.classprio == sn.classprio(1));
120 for classpreempt = 1:R
121 % For priority variants (or LCFSPR/FCFSPR when priorities differ),
122 % only higher-priority jobs can preempt
123 isPrioSched = (sn.sched(ist) == SchedStrategy.FCFSPRPRIO || sn.sched(ist) == SchedStrategy.FCFSPIPRIO || sn.sched(ist) == SchedStrategy.LCFSPRPRIO || sn.sched(ist) == SchedStrategy.LCFSPIPRIO);
124 isPrioAware = isPrioSched || (hasDiffPrio && (sn.sched(ist) == SchedStrategy.LCFSPR || sn.sched(ist) == SchedStrategy.FCFSPR));
125 if isPrioAware
126 if sn.classprio(class) >= sn.classprio(classpreempt) % arriving job has same or lower priority, cannot preempt
127 continue;
128 end
129 end
130 for phasepreempt = 1:K(classpreempt) % phase of job to preempt
131 si_preempt = space_srv_k(:, (end-sum(K)+Ks(classpreempt)+phasepreempt));
132 busy_preempt = si_preempt > 0; % states where there is at least on class-r job in execution
133 if any(busy_preempt)
134 psentry = [psentry; si_preempt(busy_preempt) ./ sum(space_srv_k,2)];
135 space_srv_k_preempt = space_srv_k(busy_preempt,:);
136 space_buf_k_preempt = space_buf_k(busy_preempt,:);
137 space_var_k_preempt = space_var_k(busy_preempt,:);
138 space_srv_k_preempt(:, end-sum(K)+Ks(classpreempt)+phasepreempt) = space_srv_k_preempt(:,end-sum(K)+Ks(classpreempt)+phasepreempt) - 1; % remove preempted job
139 space_srv_k_preempt(:, end-sum(K)+Ks(class)+kentry) = space_srv_k_preempt(:,end-sum(K)+Ks(class)+kentry) + 1;
140
141 % dynamically grow buffer lenght in
142 % simulation
143 if isSimulation
144 if ni < capacity(ist) && nir(class) < classcap(ist,class) % if there is room
145 if ~any(space_buf_k_preempt(:)==0) % but the buffer has no empty slots
146 % append job slot
147 space_buf_k_preempt = [zeros(size(space_buf_k_preempt,1),2),space_buf_k]; % append two columns for (class, preempt-phase)
148 end
149 end
150 end
151
152 %get position of first empty slot
153 empty_slots = -1*ones(sum(busy_preempt),1);
154 if size(space_buf_k_preempt,2) == 0
155 empty_slots(busy_preempt) = false;
156 elseif size(space_buf_k_preempt,2) == 2 % 2 due to (class, preempt-phase) pairs
157 empty_slots(busy_preempt) = space_buf_k_preempt(busy_preempt,1:2:end)==0;
158 else
159 empty_slots(busy_preempt) = max(bsxfun(@times, space_buf_k_preempt(busy_preempt,:)==0, [1:size(space_buf_k_preempt,2)]),[],2)-1; %-1 due to (class, preempt-phase) pairs
160 end
161
162 % ignore states where the buffer has no empty slots
163 wbuf_empty = empty_slots>0;
164 if any(wbuf_empty)
165 space_srv_k_preempt = space_srv_k_preempt(wbuf_empty,:);
166 space_buf_k_preempt = space_buf_k_preempt(wbuf_empty,:);
167 space_var_k_preempt = space_var_k_preempt(wbuf_empty,:);
168 empty_slots = empty_slots(wbuf_empty);
169 if sn.sched(ist) == SchedStrategy.LCFSPR || sn.sched(ist) == SchedStrategy.LCFSPRPRIO || sn.sched(ist) == SchedStrategy.FCFSPR || sn.sched(ist) == SchedStrategy.FCFSPRPRIO % preempt-resume
170 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')+1) = phasepreempt;
171 elseif sn.sched(ist) == SchedStrategy.LCFSPI || sn.sched(ist) == SchedStrategy.LCFSPIPRIO || sn.sched(ist) == SchedStrategy.FCFSPI || sn.sched(ist) == SchedStrategy.FCFSPIPRIO % preempt-independent
172 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')+1) = 1;
173 end
174 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')) = classpreempt;
175 %outspace(all_busy_srv(wbuf_empty),:) = [space_buf, space_srv, space_var];
176 end
177 space_srv_k_reord = [space_srv_k_reord; space_srv_k_preempt];
178 space_buf_k_reord = [space_buf_k_reord; space_buf_k_preempt];
179 space_var_k_reord = [space_var_k_reord; space_var_k_preempt];
180 end
181 end
182 end
183 outprob_k = pentry(kentry) * psentry .* ones(size(space_srv_k_reord,1),1);
184 end
185 space_buf_k = space_buf_k_reord; % save reordered output states
186 space_srv_k = space_srv_k_reord; % save reordered output states
187 space_var_k = space_var_k_reord; % save reordered output states
188 end
189 % form the new state
190 outspace_k = [space_buf_k, space_srv_k, space_var_k];
191 % remove states where new arrival violates capacity or cutoff constraints
192 [oi,oir] = State.toMarginalAggr(sn,ind,outspace_k,K,Ks,space_buf_k,space_srv_k,space_var_k);
193 en_o = classcap(ist,class)>= oir(:,class) & capacity(ist)*ones(size(oi,1),1) >= oi;
194
195 if size(outspace,2)>size(outspace_k(en_o,:),2)
196 outspace = [outspace; zeros(1,size(outspace,2)-size(outspace_k(en_o,:),2)),outspace_k(en_o,:)];
197 elseif size(outspace,2)<size(outspace_k(en_o,:),2)
198 outspace = [zeros(size(outspace,1),size(outspace_k(en_o,:),2)-size(outspace,2)), outspace; outspace_k(en_o,:)];
199 else
200 outspace = [outspace; outspace_k(en_o,:)];
201 end
202 outrate = [outrate; -1*ones(size(outspace_k(en_o,:),1),1)]; % passive action, rate is unspecified
203 outprob = [outprob; outprob_k(en_o,:)];
204 end
205 if isSimulation
206 if size(outprob,1) > 1
207 cum_prob = cumsum(outprob) / sum(outprob);
208 firing_ctr = 1 + max([0,find( rand > cum_prob' )]); % select action
209 outspace = outspace(firing_ctr,:);
210 outrate = -1;
211 outprob = 1;
212 end
213 end
214 case EventType.DEP
215 if any(any(space_srv(:,(Ks(class)+1):(Ks(class)+K(class))))) % something is busy
216 if hasOnlyExp && (sn.sched(ist) == SchedStrategy.PS || sn.sched(ist) == SchedStrategy.DPS || sn.sched(ist) == SchedStrategy.GPS || sn.sched(ist) == SchedStrategy.INF || sn.sched(ist) == SchedStrategy.PSPRIO || sn.sched(ist) == SchedStrategy.DPSPRIO || sn.sched(ist) == SchedStrategy.GPSPRIO || sn.sched(ist) == SchedStrategy.LPS)
217 nir = space_srv;
218 ni = sum(nir,2);
219 sir = nir;
220 kir = sir;
221 else
222 [ni,nir,sir,kir] = State.toMarginal(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
223 end
224 switch sn.routing(ind,class)
225 case RoutingStrategy.RROBIN
226 idx = find(space_var(sum(sn.nvars(ind,1:(R+class)))) == sn.nodeparam{ind}{class}.outlinks);
227 if idx < length(sn.nodeparam{ind}{class}.outlinks)
228 space_var(sum(sn.nvars(ind,1:(R+class)))) = sn.nodeparam{ind}{class}.outlinks(idx+1);
229 else
230 space_var(sum(sn.nvars(ind,1:(R+class)))) = sn.nodeparam{ind}{class}.outlinks(1);
231 end
232 end
233 if sir(class)>0 % is a job of class is in service
234 outprob = [];
235 for k=1:K(class)
236 space_srv = inspace(:,(end-sum(K)-V+1):(end-V)); % server state
237 space_buf = inspace(:,1:(end-sum(K)-V)); % buffer state
238 rate = zeros(size(space_srv,1),1);
239 en = space_srv(:,Ks(class)+k) > 0;
240 if any(en)
241 switch sn.sched(ist)
242 case SchedStrategy.EXT % source, can produce an arrival from phase-k as long as it is from an open class
243 if isinf(sn.njobs(class))
244 pentry = pie{ist}{class};
245 for kentry = 1:K(class)
246 space_srv = inspace(:,(end-sum(K)-V+1):(end-V)); % server state
247 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
248 space_srv(en,Ks(class)+kentry) = space_srv(en,Ks(class)+kentry) + 1; % new job
249 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
250 if isinf(ni) % hit limited load-dependence
251 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*pentry(kentry)*mu{ist}{class}(k)*phi{ist}{class}(k)*ones(size(inspace(en,:),1),1)];
252 else
253 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*pentry(kentry)*mu{ist}{class}(k)*phi{ist}{class}(k)*ones(size(inspace(en,:),1),1)];
254 end
255 outprob = [outprob; ones(size(space_buf(en,:),1),1)];
256 end
257 end
258 case SchedStrategy.INF % move first job in service
259 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
260 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(en,class,k); % assume active
261 % if state is unchanged, still add with rate 0
262 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
263 if isinf(ni) % hit limited load-dependence
264 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
265 else
266 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
267 end
268 outprob = [outprob; ones(size(rate(en,:),1),1)];
269 case SchedStrategy.PS % move first job in service
270 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
271 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./ni(en)).*min(ni(en),S(ist)); % assume active
272 % if state is unchanged, still add with rate 0
273 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
274 if isinf(ni) % hit limited load-dependence
275 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
276 else
277 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
278 end
279 outprob = [outprob; ones(size(rate(en,:),1),1)];
280 % end
281 case SchedStrategy.PSPRIO
282 % unclear if LD scaling should be with
283 % ni or with niprio, for now left as ni
284 % for consistency with HOL multiserver
285 if all(ni(en) <= S(ist))
286 % n <= c: all jobs get service, priority doesn't matter
287 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
288 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./ni(en)).*min(ni(en),S(ist)); % assume active
289 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
290 if isinf(ni) % hit limited load-dependence
291 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
292 else
293 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
294 end
295 outprob = [outprob; ones(size(rate(en,:),1),1)];
296 elseif sn.classprio(class) == min(sn.classprio(nir>0)) % if this class is in the most urgent priority group (lower value = higher priority in LINE)
297 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
298 niprio(en) = sum(nir(sn.classprio==sn.classprio(class))); % jobs at the same priority class
299 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./niprio(en)).*min(niprio(en),S(ist)); % assume active
300 % if state is unchanged, still add with rate 0
301 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
302 if isinf(ni) % hit limited load-dependence
303 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
304 else
305 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
306 end
307 outprob = [outprob; ones(size(rate(en,:),1),1)];
308 else % n > c and not highest priority: set rate to zero
309 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
310 outrate = [outrate; zeros(size(rate(en,:),1),1)];
311 outprob = [outprob; ones(size(rate(en,:),1),1)];
312 end
313 case SchedStrategy.DPS
314 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
315 if S(ist) > 1
316 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
317 end
318 % in GPS, the scheduling parameter are the weights
319 w_i = sn.schedparam(ist,:);
320 w_i = w_i / sum(w_i);
321 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)*nir(class)./(sum(repmat(w_i,sum(en),1)*nir',2));
322 % if state is unchanged, still add with rate 0
323 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
324 if isinf(ni) % hit limited load-dependence
325 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
326 else
327 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
328 end
329 outprob = [outprob; ones(size(rate(en,:),1),1)];
330 case SchedStrategy.DPSPRIO
331 if all(ni(en) <= S(ist))
332 % n <= c: all jobs get service, behave like regular DPS
333 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
334 if S(ist) > 1
335 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
336 end
337 w_i = sn.schedparam(ist,:);
338 w_i = w_i / sum(w_i);
339 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)*nir(class)./(sum(repmat(w_i,sum(en),1)*nir',2));
340 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
341 if isinf(ni) % hit limited load-dependence
342 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
343 else
344 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
345 end
346 outprob = [outprob; ones(size(rate(en,:),1),1)];
347 elseif sn.classprio(class) == min(sn.classprio(nir>0)) % if this class is in the most urgent priority group (lower value = higher priority in LINE)
348 nirprio = nir;
349 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
350 niprio = sum(nirprio);
351 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
352 if S(ist) > 1
353 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
354 end
355 % in GPS, the scheduling parameter are the weights
356 w_i = sn.schedparam(ist,:);
357 w_i = w_i / sum(w_i);
358 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nirprio(class))*w_i(class)*nirprio(class)./(sum(repmat(w_i,sum(en),1)*nirprio',2));
359 % if state is unchanged, still add with rate 0
360 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
361 if isinf(ni) % hit limited load-dependence
362 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,end).*rate(en,:)];
363 else
364 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
365 end
366 outprob = [outprob; ones(size(rate(en,:),1),1)];
367 else % n > c and not most urgent priority: set rate to zero
368 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
369 outrate = [outrate; zeros(size(rate(en,:),1),1)];
370 outprob = [outprob; ones(size(rate(en,:),1),1)];
371 end
372 case SchedStrategy.GPS
373 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
374 if S(ist) > 1
375 line_error(mfilename,'Multi-server GPS stations are not supported yet.');
376 end
377 % in GPS, the scheduling parameter are the weights
378 w_i = sn.schedparam(ist,:);
379 w_i = w_i / sum(w_i);
380 cir = min(nir,ones(size(nir)));
381 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)/(w_i*cir(:)); % assume active
382 % if state is unchanged, still add with rate 0
383 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
384 if isinf(ni) % hit limited load-dependence
385 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
386 else
387 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
388 end
389 outprob = [outprob; ones(size(rate(en,:),1),1)];
390 case SchedStrategy.GPSPRIO
391 if all(ni(en) <= S(ist))
392 % n <= c: all jobs get service, behave like regular GPS
393 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
394 if S(ist) > 1
395 line_error(mfilename,'Multi-server GPS stations are not supported yet.');
396 end
397 w_i = sn.schedparam(ist,:);
398 w_i = w_i / sum(w_i);
399 cir = min(nir,ones(size(nir)));
400 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)/(w_i*cir(:)); % assume active
401 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
402 if isinf(ni) % hit limited load-dependence
403 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
404 else
405 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
406 end
407 outprob = [outprob; ones(size(rate(en,:),1),1)];
408 elseif sn.classprio(class) == min(sn.classprio(nir>0)) % if this class is in the most urgent priority group (lower value = higher priority in LINE)
409 nirprio = nir;
410 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
411 niprio = sum(nirprio);
412 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
413 if S(ist) > 1
414 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
415 end
416 % in GPS, the scheduling parameter are the weights
417 w_i = sn.schedparam(ist,:);
418 w_i = w_i / sum(w_i);
419 cir = min(nirprio,ones(size(nirprio)));
420 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nirprio(class))*w_i(class)/(w_i*cir(:)); % assume active
421 % if state is unchanged, still add with rate 0
422 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
423 if isinf(ni) % hit limited load-dependence
424 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,end).*rate(en,:)];
425 else
426 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
427 end
428 outprob = [outprob; ones(size(rate(en,:),1),1)];
429 else % n > c and not most urgent priority: set rate to zero
430 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
431 outrate = [outrate; zeros(size(rate(en,:),1),1)];
432 outprob = [outprob; ones(size(rate(en,:),1),1)];
433 end
434 case SchedStrategy.FCFS % move first job in service
435 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
436 en_wbuf = en & ni>S(ist); %states with jobs in buffer
437 for kdest=1:K(class) % new phase
438 space_buf_kd = space_buf;
439 space_var_kd = space_var;
440 if ismkvmodclass(class)
441 space_var_kd(en,sum(sn.nvars(ind,1:class))) = kdest;
442 end
443 rate_kd = rate;
444 rate_kd(en) = proc{ist}{class}{2}(k,kdest).*kir(en,class,k); % assume active
445 % first process states without jobs in buffer
446 en_wobuf = ~en_wbuf;
447 if any(en_wobuf) %any state without jobs in buffer
448 outspace = [outspace; space_buf_kd(en_wobuf,:), space_srv(en_wobuf,:), space_var_kd(en_wobuf,:)];
449 if isinf(ni) % hit limited load-dependence
450 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_kd(en_wobuf,:)];
451 else
452 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_kd(en_wobuf,:)];
453 end
454 end
455 % now process states with jobs in buffer
456 outprob = [outprob; ones(size(rate_kd(en_wobuf,:),1),1)];
457 if any(en_wbuf) %any state with jobs in buffer
458 % get class of job at head
459 start_svc_class = space_buf_kd(en_wbuf,end);
460 if start_svc_class > 0 % redunant if?
461 % update input buffer
462 space_buf_kd(en_wbuf,:) = [zeros(sum(en_wbuf),1),space_buf_kd(en_wbuf,1:end-1)];
463 % probability vector for the next job of starting in phase kentry
464 if ismkvmodclass(start_svc_class) % if markov-modulated
465 if start_svc_class==class % if successive service from the same class
466 kentry_range = kdest; % new job enters in phase left by departing job
467 else % resume phase from local variables
468 kentry_range = space_var_kd(en,sum(sn.nvars(ind,1:start_svc_class)));
469 end
470 pentry_svc_class = 0*pie{ist}{start_svc_class};
471 pentry_svc_class(kentry_range) = 1.0;
472 else % if i.i.d.
473 pentry_svc_class = pie{ist}{start_svc_class};
474 kentry_range = 1:K(start_svc_class);
475 end
476 for kentry = kentry_range
477 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
478 outspace = [outspace; space_buf_kd(en,:), space_srv(en,:), space_var_kd(en,:)];
479 rate_k = rate_kd;
480 rate_k(en_wbuf,:) = rate_kd(en_wbuf,:)*pentry_svc_class(kentry);
481 if isinf(ni) % use limited load-dependence at the latest user-provided level
482 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
483 else
484 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
485 end
486 outprob_cur = ones(size(rate_kd(en,:),1),1);
487 outprob_cur(outrate==0.0) = 0;
488 outprob = [outprob; outprob_cur'];
489 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
490 end
491 end
492 end
493 end
494 % if state is unchanged, still add with rate 0
495 case SchedStrategy.HOL % FCFS priority
496 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
497 en_wbuf = en & ni>S(ist); %states with jobs in buffer
498 en_wobuf = ~en_wbuf;
499 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
500 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
501 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
502 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
503 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
504 [~,rightmostMaxPosFlipped]=max(fliplr(isrowmax),[],2);
505 rightmostMaxPos = size(isrowmax,2) - rightmostMaxPosFlipped + 1;
506 start_svc_class = space_buf(en_wbuf, rightmostMaxPos);
507 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
508 if isinf(ni) % hit limited load-dependence
509 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
510 else
511 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
512 end
513 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
514 if start_svc_class > 0
515 pentry_svc_class = pie{ist}{start_svc_class};
516 for kentry = 1:K(start_svc_class)
517 space_srv_k = space_srv;
518 space_buf_k = space_buf;
519 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
520 for j=find(en_wbuf)'
521 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+1):end)];
522 end
523 % if state is unchanged, still add with rate 0
524 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
525 rate_k = rate;
526 rate_k(en_wbuf,:) = rate(en_wbuf,:) * pentry_svc_class(kentry);
527 if isinf(ni) % hit limited load-dependence
528 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
529 else
530 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
531 end
532 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
533 end
534 end
535 case SchedStrategy.LCFSPRIO % LCFS priority - like HOL but LCFS order within priority groups
536 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
537 en_wbuf = en & ni>S(ist); %states with jobs in buffer
538 en_wobuf = ~en_wbuf;
539 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
540 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
541 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
542 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
543 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
544 % LCFS: Find leftmost (first) position instead of rightmost for LCFS order
545 [~,leftmostMaxPos]=max(isrowmax,[],2);
546 start_svc_class = space_buf(en_wbuf, leftmostMaxPos);
547 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
548 if isinf(ni) % hit limited load-dependence
549 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
550 else
551 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
552 end
553 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
554 if start_svc_class > 0
555 pentry_svc_class = pie{ist}{start_svc_class};
556 for kentry = 1:K(start_svc_class)
557 space_srv_k = space_srv;
558 space_buf_k = space_buf;
559 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
560 for j=find(en_wbuf)'
561 % LCFS: Remove from leftmost position instead of rightmost
562 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+1):end)];
563 end
564 % if state is unchanged, still add with rate 0
565 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
566 rate_k = rate;
567 rate_k(en_wbuf,:) = rate_k(en_wbuf,:)*pentry_svc_class(kentry);
568 if isinf(ni) % hit limited load-dependence
569 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
570 else
571 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
572 end
573 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
574 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) - 1;
575 end
576 end
577 case SchedStrategy.LCFS % move last job in service
578 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
579 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
580 en_wbuf = en & ni>S(ist); %states with jobs in buffer
581 hasDiffPrio_dep = ~all(sn.classprio == sn.classprio(1));
582 if hasDiffPrio_dep && any(en_wbuf)
583 % Priority-aware: find leftmost (most recent) among highest-priority class
584 priogroup = [Inf, sn.classprio]; % Inf for empty (0) positions
585 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
586 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2);
587 isrowmax = space_buf_groupg(en_wbuf,:) == repmat(start_classprio, 1, size(space_buf_groupg,2));
588 [~,colfirstnnz] = max(isrowmax,[],2); % leftmost = most recent in LCFS buffer
589 else
590 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
591 end
592 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
593 space_buf(en_wbuf,colfirstnnz)=0;
594 if isempty(start_svc_class)
595 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
596 if isinf(ni) % hit limited load-dependence
597 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
598 else
599 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
600 end
601 outprob = [outprob; ones(size(rate(en,:),1),1)];
602 if isSimulation && nargin>=7 && isobject(eventCache)
603 eventCache(key) = {outprob, outspace,outrate};
604 end
605 return
606 end
607 for kentry = 1:K(start_svc_class)
608 pentry_svc_class = pie{ist}{start_svc_class};
609 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
610 % if state is unchanged, still add with rate 0
611 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
612 rate_k = rate;
613 rate_k(en_wbuf,:) = rate(en_wbuf,:)*pentry_svc_class(kentry);
614 if isinf(ni) % hit limited load-dependence
615 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
616 else
617 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
618 end
619 outprob = [outprob; ones(size(rate(en,:),1),1)];
620 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
621 end
622 case SchedStrategy.LCFSPR % move last job in service (preempt-resume)
623 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
624 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
625 en_wbuf = en & ni>S(ist); %states with jobs in buffer
626 hasDiffPrio_dep = ~all(sn.classprio == sn.classprio(1));
627 if hasDiffPrio_dep && any(en_wbuf)
628 % Priority-aware: find leftmost among highest-priority class in buffer
629 priogroup = [Inf, sn.classprio];
630 class_cols = 1:2:size(space_buf,2);
631 space_buf_class = space_buf(:, class_cols);
632 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
633 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2);
634 isrowmax = space_buf_class_groupg(en_wbuf,:) == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
635 [~,leftmostClassPos] = max(isrowmax,[],2);
636 colfirstnnz = 2*leftmostClassPos - 1;
637 else
638 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
639 end
640 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
641 kentry = space_buf(en_wbuf,colfirstnnz+1); % entry phase of job resuming service
642 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
643 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase
644 if isempty(start_svc_class)
645 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
646 if isinf(ni) % hit limited load-dependence
647 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
648 else
649 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
650 end
651 outprob = [outprob; ones(size(rate(en,:),1),1)];
652 if isSimulation && nargin>=7 && isobject(eventCache)
653 eventCache(key) = {outprob, outspace,outrate};
654 end
655 return
656 end
657 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
658 % if state is unchanged, still add with rate 0
659 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
660 if isinf(ni) % hit limited load-dependence
661 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
662 else
663 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
664 end
665 outprob = [outprob; ones(size(rate(en,:),1),1)];
666 case SchedStrategy.LCFSPI % move last job in service (preempt-independent)
667 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
668 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
669 en_wbuf = en & ni>S(ist); %states with jobs in buffer
670 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
671 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
672 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
673 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase (ignored for LCFSPI)
674 if isempty(start_svc_class)
675 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
676 if isinf(ni) % hit limited load-dependence
677 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
678 else
679 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
680 end
681 outprob = [outprob; ones(size(rate(en,:),1),1)];
682 if isSimulation && nargin>=7 && isobject(eventCache)
683 eventCache(key) = {outprob, outspace,outrate};
684 end
685 return
686 end
687 % For LCFSPI, jobs restart from pie distribution instead of stored phase
688 pentry_svc_class = pie{ist}{start_svc_class};
689 for kentry = 1:K(start_svc_class)
690 space_srv_k = space_srv;
691 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
692 % if state is unchanged, still add with rate 0
693 outspace = [outspace; space_buf(en,:), space_srv_k(en,:), space_var(en,:)];
694 rate_k = rate;
695 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
696 if isinf(ni) % hit limited load-dependence
697 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
698 else
699 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
700 end
701 outprob = [outprob; ones(size(rate_k(en,:),1),1)];
702 end
703 case SchedStrategy.FCFSPR % FCFS preempt-resume (no priority)
704 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
705 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
706 en_wbuf = en & ni>S(ist); %states with jobs in buffer
707 % FCFS: Find rightmost (last) non-zero position (longest waiting job)
708 [~, colLastNnz] = max(fliplr(space_buf(en_wbuf,:) ~= 0), [], 2);
709 colLastNnz = size(space_buf,2) - colLastNnz; % convert to actual position (odd index for class)
710 start_svc_class = space_buf(en_wbuf, colLastNnz); % job entering service
711 kentry = space_buf(en_wbuf, colLastNnz+1); % entry phase of job resuming service
712 space_buf(en_wbuf, colLastNnz) = 0; % zero popped job
713 space_buf(en_wbuf, colLastNnz+1) = 0; % zero popped phase
714 if isempty(start_svc_class)
715 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
716 if isinf(ni)
717 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
718 else
719 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
720 end
721 outprob = [outprob; ones(size(rate(en,:),1),1)];
722 if isSimulation && nargin>=7 && isobject(eventCache)
723 eventCache(key) = {outprob, outspace, outrate};
724 end
725 return
726 end
727 space_srv(en_wbuf, Ks(start_svc_class)+kentry) = space_srv(en_wbuf, Ks(start_svc_class)+kentry) + 1;
728 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
729 if isinf(ni)
730 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
731 else
732 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
733 end
734 outprob = [outprob; ones(size(rate(en,:),1),1)];
735 case SchedStrategy.FCFSPI % FCFS preempt-independent (no priority)
736 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
737 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
738 en_wbuf = en & ni>S(ist); %states with jobs in buffer
739 % FCFS: Find rightmost (last) non-zero position (longest waiting job)
740 [~, colLastNnz] = max(fliplr(space_buf(en_wbuf,:) ~= 0), [], 2);
741 colLastNnz = size(space_buf,2) - colLastNnz; % convert to actual position (odd index for class)
742 start_svc_class = space_buf(en_wbuf, colLastNnz); % job entering service
743 space_buf(en_wbuf, colLastNnz) = 0; % zero popped job
744 space_buf(en_wbuf, colLastNnz+1) = 0; % zero popped phase (ignored for FCFSPI)
745 if isempty(start_svc_class)
746 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
747 if isinf(ni)
748 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
749 else
750 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
751 end
752 outprob = [outprob; ones(size(rate(en,:),1),1)];
753 if isSimulation && nargin>=7 && isobject(eventCache)
754 eventCache(key) = {outprob, outspace, outrate};
755 end
756 return
757 end
758 % For FCFSPI, jobs restart from pie distribution instead of stored phase
759 pentry_svc_class = pie{ist}{start_svc_class};
760 for kentry = 1:K(start_svc_class)
761 space_srv_k = space_srv;
762 space_srv_k(en_wbuf, Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf, Ks(start_svc_class)+kentry) + 1;
763 outspace = [outspace; space_buf(en,:), space_srv_k(en,:), space_var(en,:)];
764 rate_k = rate;
765 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
766 if isinf(ni)
767 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
768 else
769 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
770 end
771 outprob = [outprob; ones(size(rate_k(en,:),1),1)];
772 end
773 case SchedStrategy.FCFSPRPRIO % FCFS preempt-resume with priority groups
774 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
775 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
776 en_wbuf = en & ni>S(ist); %states with jobs in buffer
777 en_wobuf = ~en_wbuf;
778 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
779 % Buffer stores [class,phase,class,phase,...] pairs;
780 % only inspect class columns (odd: 1,3,5,...) for priority
781 class_cols = 1:2:size(space_buf,2);
782 space_buf_class = space_buf(:, class_cols);
783 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
784 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2); % min finds highest priority
785 isrowmax = space_buf_class_groupg == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
786 % FCFS: Find rightmost (last) class position for highest priority class (longest waiting)
787 [~,rightmostClassPos]=max(fliplr(isrowmax),[],2);
788 rightmostClassPos = size(space_buf_class_groupg,2) - rightmostClassPos + 1;
789 rightmostMaxPos = 2*rightmostClassPos - 1; % convert to buffer column index
790 start_svc_class = space_buf(en_wbuf, rightmostMaxPos); % job entering service
791 kentry = space_buf(en_wbuf, rightmostMaxPos+1); % entry phase of job resuming service (preempt-resume)
792
793 % Handle states without buffer jobs
794 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
795 if isinf(ni)
796 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
797 else
798 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
799 end
800 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
801
802 % Handle states with buffer jobs
803 if any(en_wbuf) && start_svc_class > 0
804 space_srv_k = space_srv;
805 space_buf_k = space_buf;
806 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
807 for j=find(en_wbuf)'
808 % Remove both class and phase from rightmost position (preempt-resume)
809 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+2):end), 0];
810 end
811 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
812 if isinf(ni)
813 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wbuf,:)];
814 else
815 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wbuf,:)];
816 end
817 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
818 end
819 case SchedStrategy.LCFSPRPRIO % LCFS preempt-resume with priority groups
820 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
821 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
822 en_wbuf = en & ni>S(ist); %states with jobs in buffer
823 en_wobuf = ~en_wbuf;
824 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
825 % Buffer stores [class,phase,class,phase,...] pairs;
826 % only inspect class columns (odd: 1,3,5,...) for priority
827 class_cols = 1:2:size(space_buf,2);
828 space_buf_class = space_buf(:, class_cols);
829 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
830 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2); % min finds highest priority
831 isrowmax = space_buf_class_groupg == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
832 % LCFS: Find leftmost (first) class position for highest priority class (most recently preempted)
833 [~,leftmostClassPos]=max(isrowmax,[],2);
834 leftmostMaxPos = 2*leftmostClassPos - 1; % convert to buffer column index
835 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
836 kentry = space_buf(en_wbuf, leftmostMaxPos+1); % entry phase of job resuming service (preempt-resume)
837
838 % Handle states without buffer jobs
839 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
840 if isinf(ni)
841 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
842 else
843 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
844 end
845 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
846
847 % Handle states with buffer jobs
848 if any(en_wbuf) && start_svc_class > 0
849 space_srv_k = space_srv;
850 space_buf_k = space_buf;
851 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
852 for j=find(en_wbuf)'
853 % Remove both class and phase from leftmost position (preempt-resume)
854 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
855 end
856 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
857 if isinf(ni)
858 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wbuf,:)];
859 else
860 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wbuf,:)];
861 end
862 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
863 end
864 case SchedStrategy.FCFSPIPRIO % FCFS preempt-independent with priority groups
865 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
866 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
867 en_wbuf = en & ni>S(ist); %states with jobs in buffer
868 en_wobuf = ~en_wbuf;
869 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
870 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
871 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
872 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
873 % FCFS: Find rightmost (last) position for highest priority class
874 [~,rightmostMaxPos]=max(fliplr(isrowmax),[],2);
875 rightmostMaxPos = size(space_buf_groupg,2) - rightmostMaxPos + 1;
876 start_svc_class = space_buf(en_wbuf, rightmostMaxPos); % job entering service
877
878 % Handle states without buffer jobs
879 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
880 if isinf(ni)
881 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
882 else
883 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
884 end
885 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
886
887 % Handle states with buffer jobs
888 if any(en_wbuf) && start_svc_class > 0
889 % For FCFSPIPRIO, jobs restart from pie distribution instead of stored phase
890 pentry_svc_class = pie{ist}{start_svc_class};
891 for kentry = 1:K(start_svc_class)
892 space_srv_k = space_srv;
893 space_buf_k = space_buf;
894 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
895 for j=find(en_wbuf)'
896 % Remove both class and phase from rightmost position (preempt-independent ignores stored phase)
897 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+2):end), 0];
898 end
899 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
900 rate_k = rate;
901 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
902 if isinf(ni)
903 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
904 else
905 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
906 end
907 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
908 end
909 end
910 case SchedStrategy.LCFSPIPRIO % LCFS preempt-independent with priority groups
911 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
912 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
913 en_wbuf = en & ni>S(ist); %states with jobs in buffer
914 en_wobuf = ~en_wbuf;
915 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
916 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
917 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
918 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
919 % LCFS: Find leftmost (first) position for highest priority class
920 [~,leftmostMaxPos]=max(isrowmax,[],2);
921 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
922
923 % Handle states without buffer jobs
924 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
925 if isinf(ni)
926 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
927 else
928 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
929 end
930 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
931
932 % Handle states with buffer jobs
933 if any(en_wbuf) && start_svc_class > 0
934 % For LCFSPIPRIO, jobs restart from pie distribution instead of stored phase
935 pentry_svc_class = pie{ist}{start_svc_class};
936 for kentry = 1:K(start_svc_class)
937 space_srv_k = space_srv;
938 space_buf_k = space_buf;
939 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
940 for j=find(en_wbuf)'
941 % Remove both class and phase from leftmost position (preempt-independent ignores stored phase)
942 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
943 end
944 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
945 rate_k = rate;
946 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
947 if isinf(ni)
948 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
949 else
950 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
951 end
952 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
953 end
954 end
955 case SchedStrategy.SIRO
956 rate = zeros(size(space_srv,1),1);
957 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
958 space_srv = inspace(:,end-sum(K)+1:end); % server state
959 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
960 % first record departure in states where the buffer is empty
961 en_wobuf = en & sum(space_buf(en,:),2) == 0;
962 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
963 if isinf(ni) % hit limited load-dependence
964 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
965 else
966 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
967 end
968 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
969 % let's go now to states where the buffer is non-empty
970 for r=1:R % pick a job of a random class
971 rate_r = rate;
972 space_buf = inspace(:,1:(end-sum(K))); % buffer state
973 en_wbuf = en & space_buf(en,r) > 0; % states where the buffer is non-empty
974 space_buf(en_wbuf,r) = space_buf(en_wbuf,r) - 1; % remove from buffer
975 space_srv_r = space_srv;
976 pentry_svc_class = pie{ist}{r};
977 pick_prob = (nir(r)-sir(r)) / (ni-sum(sir));
978 if pick_prob >= 0
979 rate_r(en_wbuf,:) = rate_r(en_wbuf,:) * pick_prob;
980 end
981 for kentry=1:K(r)
982 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) + 1; % bring job in service
983 outspace = [outspace; space_buf(en_wbuf,:), space_srv_r(en_wbuf,:), space_var(en_wbuf,:)];
984 rate_k = rate_r;
985 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
986 if isinf(ni) % hit limited load-dependence
987 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
988 else
989 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
990 end
991 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
992 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) - 1; % bring job in service
993 end
994 end
995 case {SchedStrategy.SEPT,SchedStrategy.LEPT} % move last job in service
996 rate = zeros(size(space_srv,1),1);
997 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
998 space_srv = inspace(:,end-sum(K)+1:end); % server state
999 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
1000 space_buf = inspace(:,1:(end-sum(K))); % buffer state
1001 % in SEPT, the scheduling parameter is the priority order of the class means
1002 % en_wbuf: states where the buffer is non-empty
1003 % sept_class: class to pick in service
1004 [en_wbuf, first_class_inrow] = max(space_buf(:,sn.schedparam(ist,:))~=0, [], 2);
1005 sept_class = sn.schedparam(ist,first_class_inrow); % this is different for sept and lept
1006
1007 space_buf(en_wbuf,sept_class) = space_buf(en_wbuf,sept_class) - 1; % remove from buffer
1008 pentry = pie{ist}{sept_class};
1009 for kentry=1:K(sept_class)
1010 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) + 1; % bring job in service
1011 if isSimulation
1012 % break the tie
1013 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
1014 rate_k = rate;
1015 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
1016 if isinf(ni) % hit limited load-dependence
1017 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
1018 else
1019 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
1020 end
1021 outprob = [outprob; ones(size(rate(en,:),1),1)];
1022 else
1023 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
1024 rate_k = rate;
1025 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
1026 if isinf(ni) % hit limited load-dependence
1027 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
1028 else
1029 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
1030 end
1031 outprob = [outprob; ones(size(rate(en,:),1),1)];
1032 end
1033 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) - 1; % bring job in service
1034 end
1035 otherwise
1036 line_error(mfilename,sprintf('Scheduling strategy %s is not supported.', SchedStrategy.toText(sn.sched(ist))));
1037 end
1038 end
1039 end
1040 if isSimulation
1041 if nargin>=7 && isobject(eventCache)
1042 eventCache(key) = {outprob, outspace,outrate};
1043 end
1044
1045 if size(outspace,1) > 1
1046 tot_rate = sum(outrate);
1047 cum_rate = cumsum(outrate) / tot_rate;
1048 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
1049 outspace = outspace(firing_ctr,:);
1050 outrate = sum(outrate);
1051 outprob = outprob(firing_ctr,:);
1052 end
1053 end
1054 end
1055 end
1056 case EventType.PHASE
1057 outspace = [];
1058 outrate = [];
1059 outprob = [];
1060 [ni,nir,~,kir] = State.toMarginal(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
1061 if nir(class)>0
1062 for k=1:K(class)
1063 en = space_srv(:,Ks(class)+k) > 0;
1064 if any(en)
1065 for kdest=setdiff(1:K(class),k) % new phase
1066 rate = 0;
1067 space_srv_k = space_srv(en,:);
1068 space_buf_k = space_buf(en,:);
1069 space_var_k = space_var(en,:);
1070 if ismkvmodclass(class)
1071 space_var_k(sum(sn.nvars(ind,1:class))) = kdest;
1072 end
1073 space_srv_k(:,Ks(class)+k) = space_srv_k(:,Ks(class)+k) - 1;
1074 space_srv_k(:,Ks(class)+kdest) = space_srv_k(:,Ks(class)+kdest) + 1;
1075 switch sn.sched(ist)
1076 case SchedStrategy.EXT
1077 rate = proc{ist}{class}{1}(k,kdest); % move next job forward
1078 case SchedStrategy.INF
1079 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
1080 case {SchedStrategy.PS, SchedStrategy.LPS}
1081 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)./ni(:).*min(ni(:),S(ist)); % assume active
1082 case SchedStrategy.PSPRIO
1083 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1084 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)./ni(:).*min(ni(:),S(ist)); % assume active
1085 else
1086 rate = 0; % not in most urgent priority group
1087 end
1088 case SchedStrategy.DPSPRIO
1089 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1090 w_i = sn.schedparam(ist,:);
1091 w_i = w_i / sum(w_i);
1092 nirprio = nir;
1093 if ~all(ni <= S(ist))
1094 nirprio(sn.classprio~=sn.classprio(class)) = 0;
1095 end
1096 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)*w_i(class)./(sum(repmat(w_i,size(nirprio,1),1)*nirprio',2)); % assume active
1097 else
1098 rate = 0; % not in most urgent priority group
1099 end
1100 case SchedStrategy.GPSPRIO
1101 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1102 w_i = sn.schedparam(ist,:);
1103 w_i = w_i / sum(w_i);
1104 nirprio = nir;
1105 if ~all(ni <= S(ist))
1106 nirprio(sn.classprio~=sn.classprio(class)) = 0;
1107 end
1108 cir = min(nirprio,ones(size(nirprio)));
1109 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)/nirprio(class)*w_i(class)/(w_i*cir(:)); % assume active
1110 else
1111 rate = 0; % not in most urgent priority group
1112 end
1113 case SchedStrategy.DPS
1114 if S(ist) > 1
1115 line_error(mfilename,'Multi-server DPS not supported yet');
1116 end
1117 w_i = sn.schedparam(ist,:);
1118 w_i = w_i / sum(w_i);
1119 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)*w_i(class)./(sum(repmat(w_i,size(nir,1),1)*nir',2)); % assume active
1120 case SchedStrategy.GPS
1121 if S(ist) > 1
1122 line_error(mfilename,'Multi-server GPS not supported yet');
1123 end
1124 cir = min(nir,ones(size(nir)));
1125 w_i = sn.schedparam(ist,:); w_i = w_i / sum(w_i);
1126 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)/nir(class)*w_i(class)/(w_i*cir(:)); % assume active
1127
1128 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS, SchedStrategy.LCFSPR, SchedStrategy.LCFSPI, SchedStrategy.LCFSPRIO, SchedStrategy.SIRO, SchedStrategy.SEPT, SchedStrategy.LEPT}
1129 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
1130 end
1131 % if the class cannot be served locally,
1132 % then rate = NaN since mu{i,class}=NaN
1133 if isinf(ni) % hit limited load-dependence
1134 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate];
1135 else
1136 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate];
1137 end
1138 outspace = [outspace; space_buf_k, space_srv_k, space_var_k];
1139 outprob = [outprob; ones(size(rate,1),1)];
1140 end
1141 end
1142 end
1143 if isSimulation
1144 if nargin>=7 && isobject(eventCache)
1145 eventCache(key) = {outprob, outspace,outrate};
1146 end
1147
1148 if size(outspace,1) > 1
1149 tot_rate = sum(outrate);
1150 cum_rate = cumsum(outrate) / tot_rate;
1151 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
1152 outspace = outspace(firing_ctr,:);
1153 outrate = sum(outrate);
1154 outprob = outprob(firing_ctr,:);
1155 end
1156 end
1157 end
1158end
1159
1160end
Definition mmt.m:124