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