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 D1_srv = proc{ist}{class}{2};
245 for kentry = 1:K(class)
246 arv_rate = D1_srv(k, kentry);
247 if arv_rate <= 0
248 continue
249 end
250 space_srv = inspace(:,(end-sum(K)-V+1):(end-V));
251 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1;
252 space_srv(en,Ks(class)+kentry) = space_srv(en,Ks(class)+kentry) + 1;
253 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
254 if isinf(ni)
255 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*arv_rate*ones(size(inspace(en,:),1),1)];
256 else
257 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*arv_rate*ones(size(inspace(en,:),1),1)];
258 end
259 outprob = [outprob; ones(size(space_buf(en,:),1),1)];
260 end
261 end
262 case SchedStrategy.INF % move first job in service
263 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
264 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(en,class,k); % assume active
265 % if state is unchanged, still add with rate 0
266 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
267 if isinf(ni) % hit limited load-dependence
268 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
269 else
270 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
271 end
272 outprob = [outprob; ones(size(rate(en,:),1),1)];
273 case SchedStrategy.PS % move first job in service
274 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
275 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./ni(en)).*min(ni(en),S(ist)); % assume active
276 % if state is unchanged, still add with rate 0
277 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
278 if isinf(ni) % hit limited load-dependence
279 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
280 else
281 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
282 end
283 outprob = [outprob; ones(size(rate(en,:),1),1)];
284 % end
285 case SchedStrategy.PSPRIO
286 % unclear if LD scaling should be with
287 % ni or with niprio, for now left as ni
288 % for consistency with HOL multiserver
289 if all(ni(en) <= S(ist))
290 % n <= c: all jobs get service, priority doesn't matter
291 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
292 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./ni(en)).*min(ni(en),S(ist)); % assume active
293 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
294 if isinf(ni) % hit limited load-dependence
295 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
296 else
297 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
298 end
299 outprob = [outprob; ones(size(rate(en,:),1),1)];
300 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)
301 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
302 niprio(en) = sum(nir(sn.classprio==sn.classprio(class))); % jobs at the same priority class
303 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./niprio(en)).*min(niprio(en),S(ist)); % assume active
304 % if state is unchanged, still add with rate 0
305 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
306 if isinf(ni) % hit limited load-dependence
307 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
308 else
309 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
310 end
311 outprob = [outprob; ones(size(rate(en,:),1),1)];
312 else % n > c and not highest priority: set rate to zero
313 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
314 outrate = [outrate; zeros(size(rate(en,:),1),1)];
315 outprob = [outprob; ones(size(rate(en,:),1),1)];
316 end
317 case SchedStrategy.DPS
318 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
319 if S(ist) > 1
320 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
321 end
322 % in GPS, the scheduling parameter are the weights
323 w_i = sn.schedparam(ist,:);
324 w_i = w_i / sum(w_i);
325 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));
326 % if state is unchanged, still add with rate 0
327 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
328 if isinf(ni) % hit limited load-dependence
329 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
330 else
331 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
332 end
333 outprob = [outprob; ones(size(rate(en,:),1),1)];
334 case SchedStrategy.DPSPRIO
335 if all(ni(en) <= S(ist))
336 % n <= c: all jobs get service, behave like regular DPS
337 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
338 if S(ist) > 1
339 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
340 end
341 w_i = sn.schedparam(ist,:);
342 w_i = w_i / sum(w_i);
343 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));
344 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
345 if isinf(ni) % hit limited load-dependence
346 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
347 else
348 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
349 end
350 outprob = [outprob; ones(size(rate(en,:),1),1)];
351 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)
352 nirprio = nir;
353 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
354 niprio = sum(nirprio);
355 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
356 if S(ist) > 1
357 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
358 end
359 % in GPS, the scheduling parameter are the weights
360 w_i = sn.schedparam(ist,:);
361 w_i = w_i / sum(w_i);
362 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));
363 % if state is unchanged, still add with rate 0
364 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
365 if isinf(ni) % hit limited load-dependence
366 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,end).*rate(en,:)];
367 else
368 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
369 end
370 outprob = [outprob; ones(size(rate(en,:),1),1)];
371 else % n > c and not most urgent priority: set rate to zero
372 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
373 outrate = [outrate; zeros(size(rate(en,:),1),1)];
374 outprob = [outprob; ones(size(rate(en,:),1),1)];
375 end
376 case SchedStrategy.GPS
377 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
378 if S(ist) > 1
379 line_error(mfilename,'Multi-server GPS stations are not supported yet.');
380 end
381 % in GPS, the scheduling parameter are the weights
382 w_i = sn.schedparam(ist,:);
383 w_i = w_i / sum(w_i);
384 cir = min(nir,ones(size(nir)));
385 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)/(w_i*cir(:)); % assume active
386 % if state is unchanged, still add with rate 0
387 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
388 if isinf(ni) % hit limited load-dependence
389 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
390 else
391 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
392 end
393 outprob = [outprob; ones(size(rate(en,:),1),1)];
394 case SchedStrategy.GPSPRIO
395 if all(ni(en) <= S(ist))
396 % n <= c: all jobs get service, behave like regular GPS
397 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
398 if S(ist) > 1
399 line_error(mfilename,'Multi-server GPS stations are not supported yet.');
400 end
401 w_i = sn.schedparam(ist,:);
402 w_i = w_i / sum(w_i);
403 cir = min(nir,ones(size(nir)));
404 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)/(w_i*cir(:)); % assume active
405 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
406 if isinf(ni) % hit limited load-dependence
407 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
408 else
409 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
410 end
411 outprob = [outprob; ones(size(rate(en,:),1),1)];
412 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)
413 nirprio = nir;
414 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
415 niprio = sum(nirprio);
416 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
417 if S(ist) > 1
418 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
419 end
420 % in GPS, the scheduling parameter are the weights
421 w_i = sn.schedparam(ist,:);
422 w_i = w_i / sum(w_i);
423 cir = min(nirprio,ones(size(nirprio)));
424 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nirprio(class))*w_i(class)/(w_i*cir(:)); % assume active
425 % if state is unchanged, still add with rate 0
426 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
427 if isinf(ni) % hit limited load-dependence
428 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,end).*rate(en,:)];
429 else
430 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
431 end
432 outprob = [outprob; ones(size(rate(en,:),1),1)];
433 else % n > c and not most urgent priority: set rate to zero
434 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
435 outrate = [outrate; zeros(size(rate(en,:),1),1)];
436 outprob = [outprob; ones(size(rate(en,:),1),1)];
437 end
438 case SchedStrategy.FCFS % move first job in service
439 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
440 en_wbuf = en & ni>S(ist); %states with jobs in buffer
441 for kdest=1:K(class) % new phase
442 space_buf_kd = space_buf;
443 space_var_kd = space_var;
444 if ismkvmodclass(class)
445 space_var_kd(en,sum(sn.nvars(ind,1:class))) = kdest;
446 end
447 rate_kd = rate;
448 rate_kd(en) = proc{ist}{class}{2}(k,kdest).*kir(en,class,k); % assume active
449 % first process states without jobs in buffer
450 en_wobuf = ~en_wbuf;
451 if any(en_wobuf) %any state without jobs in buffer
452 outspace = [outspace; space_buf_kd(en_wobuf,:), space_srv(en_wobuf,:), space_var_kd(en_wobuf,:)];
453 if isinf(ni) % hit limited load-dependence
454 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_kd(en_wobuf,:)];
455 else
456 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_kd(en_wobuf,:)];
457 end
458 end
459 % now process states with jobs in buffer
460 outprob = [outprob; ones(size(rate_kd(en_wobuf,:),1),1)];
461 if any(en_wbuf) %any state with jobs in buffer
462 % get class of job at head
463 start_svc_class = space_buf_kd(en_wbuf,end);
464 if start_svc_class > 0 % redunant if?
465 % update input buffer
466 space_buf_kd(en_wbuf,:) = [zeros(sum(en_wbuf),1),space_buf_kd(en_wbuf,1:end-1)];
467 % probability vector for the next job of starting in phase kentry
468 if ismkvmodclass(start_svc_class) % if markov-modulated
469 if start_svc_class==class % if successive service from the same class
470 kentry_range = kdest; % new job enters in phase left by departing job
471 else % resume phase from local variables
472 kentry_range = space_var_kd(en,sum(sn.nvars(ind,1:start_svc_class)));
473 end
474 pentry_svc_class = 0*pie{ist}{start_svc_class};
475 pentry_svc_class(kentry_range) = 1.0;
476 else % if i.i.d.
477 pentry_svc_class = pie{ist}{start_svc_class};
478 kentry_range = 1:K(start_svc_class);
479 end
480 for kentry = kentry_range
481 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
482 outspace = [outspace; space_buf_kd(en,:), space_srv(en,:), space_var_kd(en,:)];
483 rate_k = rate_kd;
484 rate_k(en_wbuf,:) = rate_kd(en_wbuf,:)*pentry_svc_class(kentry);
485 if isinf(ni) % use limited load-dependence at the latest user-provided level
486 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
487 else
488 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
489 end
490 outprob_cur = ones(size(rate_kd(en,:),1),1);
491 outprob_cur(outrate==0.0) = 0;
492 outprob = [outprob; outprob_cur'];
493 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
494 end
495 end
496 end
497 end
498 % if state is unchanged, still add with rate 0
499 case SchedStrategy.HOL % FCFS priority
500 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
501 en_wbuf = en & ni>S(ist); %states with jobs in buffer
502 en_wobuf = ~en_wbuf;
503 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
504 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
505 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
506 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
507 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
508 [~,rightmostMaxPosFlipped]=max(fliplr(isrowmax),[],2);
509 rightmostMaxPos = size(isrowmax,2) - rightmostMaxPosFlipped + 1;
510 start_svc_class = space_buf(en_wbuf, rightmostMaxPos);
511 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
512 if isinf(ni) % hit limited load-dependence
513 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
514 else
515 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
516 end
517 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
518 if start_svc_class > 0
519 pentry_svc_class = pie{ist}{start_svc_class};
520 for kentry = 1:K(start_svc_class)
521 space_srv_k = space_srv;
522 space_buf_k = space_buf;
523 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
524 for j=find(en_wbuf)'
525 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+1):end)];
526 end
527 % if state is unchanged, still add with rate 0
528 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
529 rate_k = rate;
530 rate_k(en_wbuf,:) = rate(en_wbuf,:) * pentry_svc_class(kentry);
531 if isinf(ni) % hit limited load-dependence
532 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
533 else
534 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
535 end
536 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
537 end
538 end
539 case SchedStrategy.LCFSPRIO % LCFS priority - like HOL but LCFS order within priority groups
540 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
541 en_wbuf = en & ni>S(ist); %states with jobs in buffer
542 en_wobuf = ~en_wbuf;
543 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
544 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
545 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
546 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
547 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
548 % LCFS: Find leftmost (first) position instead of rightmost for LCFS order
549 [~,leftmostMaxPos]=max(isrowmax,[],2);
550 start_svc_class = space_buf(en_wbuf, leftmostMaxPos);
551 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
552 if isinf(ni) % hit limited load-dependence
553 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
554 else
555 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
556 end
557 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
558 if start_svc_class > 0
559 pentry_svc_class = pie{ist}{start_svc_class};
560 for kentry = 1:K(start_svc_class)
561 space_srv_k = space_srv;
562 space_buf_k = space_buf;
563 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
564 for j=find(en_wbuf)'
565 % LCFS: Remove from leftmost position instead of rightmost
566 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+1):end)];
567 end
568 % if state is unchanged, still add with rate 0
569 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
570 rate_k = rate;
571 rate_k(en_wbuf,:) = rate_k(en_wbuf,:)*pentry_svc_class(kentry);
572 if isinf(ni) % hit limited load-dependence
573 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
574 else
575 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
576 end
577 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
578 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) - 1;
579 end
580 end
581 case SchedStrategy.LCFS % move last job in service
582 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
583 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
584 en_wbuf = en & ni>S(ist); %states with jobs in buffer
585 hasDiffPrio_dep = ~all(sn.classprio == sn.classprio(1));
586 if hasDiffPrio_dep && any(en_wbuf)
587 % Priority-aware: find leftmost (most recent) among highest-priority class
588 priogroup = [Inf, sn.classprio]; % Inf for empty (0) positions
589 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
590 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2);
591 isrowmax = space_buf_groupg(en_wbuf,:) == repmat(start_classprio, 1, size(space_buf_groupg,2));
592 [~,colfirstnnz] = max(isrowmax,[],2); % leftmost = most recent in LCFS buffer
593 else
594 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
595 end
596 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
597 space_buf(en_wbuf,colfirstnnz)=0;
598 if isempty(start_svc_class)
599 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
600 if isinf(ni) % hit limited load-dependence
601 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
602 else
603 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
604 end
605 outprob = [outprob; ones(size(rate(en,:),1),1)];
606 if isSimulation && nargin>=7 && isobject(eventCache)
607 eventCache(key) = {outprob, outspace,outrate};
608 end
609 return
610 end
611 for kentry = 1:K(start_svc_class)
612 pentry_svc_class = pie{ist}{start_svc_class};
613 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
614 % if state is unchanged, still add with rate 0
615 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
616 rate_k = rate;
617 rate_k(en_wbuf,:) = rate(en_wbuf,:)*pentry_svc_class(kentry);
618 if isinf(ni) % hit limited load-dependence
619 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
620 else
621 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
622 end
623 outprob = [outprob; ones(size(rate(en,:),1),1)];
624 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
625 end
626 case SchedStrategy.LCFSPR % move last job in service (preempt-resume)
627 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
628 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
629 en_wbuf = en & ni>S(ist); %states with jobs in buffer
630 hasDiffPrio_dep = ~all(sn.classprio == sn.classprio(1));
631 if hasDiffPrio_dep && any(en_wbuf)
632 % Priority-aware: find leftmost among highest-priority class in buffer
633 priogroup = [Inf, sn.classprio];
634 class_cols = 1:2:size(space_buf,2);
635 space_buf_class = space_buf(:, class_cols);
636 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
637 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2);
638 isrowmax = space_buf_class_groupg(en_wbuf,:) == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
639 [~,leftmostClassPos] = max(isrowmax,[],2);
640 colfirstnnz = 2*leftmostClassPos - 1;
641 else
642 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
643 end
644 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
645 kentry = space_buf(en_wbuf,colfirstnnz+1); % entry phase of job resuming service
646 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
647 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase
648 if isempty(start_svc_class)
649 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
650 if isinf(ni) % hit limited load-dependence
651 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
652 else
653 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
654 end
655 outprob = [outprob; ones(size(rate(en,:),1),1)];
656 if isSimulation && nargin>=7 && isobject(eventCache)
657 eventCache(key) = {outprob, outspace,outrate};
658 end
659 return
660 end
661 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
662 % if state is unchanged, still add with rate 0
663 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
664 if isinf(ni) % hit limited load-dependence
665 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
666 else
667 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
668 end
669 outprob = [outprob; ones(size(rate(en,:),1),1)];
670 case SchedStrategy.LCFSPI % move last job in service (preempt-independent)
671 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
672 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
673 en_wbuf = en & ni>S(ist); %states with jobs in buffer
674 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
675 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
676 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
677 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase (ignored for LCFSPI)
678 if isempty(start_svc_class)
679 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
680 if isinf(ni) % hit limited load-dependence
681 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
682 else
683 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
684 end
685 outprob = [outprob; ones(size(rate(en,:),1),1)];
686 if isSimulation && nargin>=7 && isobject(eventCache)
687 eventCache(key) = {outprob, outspace,outrate};
688 end
689 return
690 end
691 % For LCFSPI, jobs restart from pie distribution instead of stored phase
692 pentry_svc_class = pie{ist}{start_svc_class};
693 for kentry = 1:K(start_svc_class)
694 space_srv_k = space_srv;
695 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
696 % if state is unchanged, still add with rate 0
697 outspace = [outspace; space_buf(en,:), space_srv_k(en,:), space_var(en,:)];
698 rate_k = rate;
699 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
700 if isinf(ni) % hit limited load-dependence
701 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
702 else
703 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
704 end
705 outprob = [outprob; ones(size(rate_k(en,:),1),1)];
706 end
707 case SchedStrategy.FCFSPR % FCFS preempt-resume (no priority)
708 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
709 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
710 en_wbuf = en & ni>S(ist); %states with jobs in buffer
711 % FCFS: Find rightmost (last) non-zero position (longest waiting job)
712 [~, colLastNnz] = max(fliplr(space_buf(en_wbuf,:) ~= 0), [], 2);
713 colLastNnz = size(space_buf,2) - colLastNnz; % convert to actual position (odd index for class)
714 start_svc_class = space_buf(en_wbuf, colLastNnz); % job entering service
715 kentry = space_buf(en_wbuf, colLastNnz+1); % entry phase of job resuming service
716 space_buf(en_wbuf, colLastNnz) = 0; % zero popped job
717 space_buf(en_wbuf, colLastNnz+1) = 0; % zero popped phase
718 if isempty(start_svc_class)
719 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
720 if isinf(ni)
721 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
722 else
723 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
724 end
725 outprob = [outprob; ones(size(rate(en,:),1),1)];
726 if isSimulation && nargin>=7 && isobject(eventCache)
727 eventCache(key) = {outprob, outspace, outrate};
728 end
729 return
730 end
731 space_srv(en_wbuf, Ks(start_svc_class)+kentry) = space_srv(en_wbuf, Ks(start_svc_class)+kentry) + 1;
732 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
733 if isinf(ni)
734 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
735 else
736 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
737 end
738 outprob = [outprob; ones(size(rate(en,:),1),1)];
739 case SchedStrategy.FCFSPI % FCFS preempt-independent (no priority)
740 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
741 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
742 en_wbuf = en & ni>S(ist); %states with jobs in buffer
743 % FCFS: Find rightmost (last) non-zero position (longest waiting job)
744 [~, colLastNnz] = max(fliplr(space_buf(en_wbuf,:) ~= 0), [], 2);
745 colLastNnz = size(space_buf,2) - colLastNnz; % convert to actual position (odd index for class)
746 start_svc_class = space_buf(en_wbuf, colLastNnz); % job entering service
747 space_buf(en_wbuf, colLastNnz) = 0; % zero popped job
748 space_buf(en_wbuf, colLastNnz+1) = 0; % zero popped phase (ignored for FCFSPI)
749 if isempty(start_svc_class)
750 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
751 if isinf(ni)
752 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
753 else
754 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
755 end
756 outprob = [outprob; ones(size(rate(en,:),1),1)];
757 if isSimulation && nargin>=7 && isobject(eventCache)
758 eventCache(key) = {outprob, outspace, outrate};
759 end
760 return
761 end
762 % For FCFSPI, jobs restart from pie distribution instead of stored phase
763 pentry_svc_class = pie{ist}{start_svc_class};
764 for kentry = 1:K(start_svc_class)
765 space_srv_k = space_srv;
766 space_srv_k(en_wbuf, Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf, Ks(start_svc_class)+kentry) + 1;
767 outspace = [outspace; space_buf(en,:), space_srv_k(en,:), space_var(en,:)];
768 rate_k = rate;
769 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
770 if isinf(ni)
771 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
772 else
773 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
774 end
775 outprob = [outprob; ones(size(rate_k(en,:),1),1)];
776 end
777 case SchedStrategy.FCFSPRPRIO % FCFS preempt-resume with priority groups
778 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
779 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
780 en_wbuf = en & ni>S(ist); %states with jobs in buffer
781 en_wobuf = ~en_wbuf;
782 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
783 % Buffer stores [class,phase,class,phase,...] pairs;
784 % only inspect class columns (odd: 1,3,5,...) for priority
785 class_cols = 1:2:size(space_buf,2);
786 space_buf_class = space_buf(:, class_cols);
787 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
788 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2); % min finds highest priority
789 isrowmax = space_buf_class_groupg == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
790 % FCFS: Find rightmost (last) class position for highest priority class (longest waiting)
791 [~,rightmostClassPos]=max(fliplr(isrowmax),[],2);
792 rightmostClassPos = size(space_buf_class_groupg,2) - rightmostClassPos + 1;
793 rightmostMaxPos = 2*rightmostClassPos - 1; % convert to buffer column index
794 start_svc_class = space_buf(en_wbuf, rightmostMaxPos); % job entering service
795 kentry = space_buf(en_wbuf, rightmostMaxPos+1); % entry phase of job resuming service (preempt-resume)
796
797 % Handle states without buffer jobs
798 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
799 if isinf(ni)
800 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
801 else
802 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
803 end
804 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
805
806 % Handle states with buffer jobs
807 if any(en_wbuf) && start_svc_class > 0
808 space_srv_k = space_srv;
809 space_buf_k = space_buf;
810 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
811 for j=find(en_wbuf)'
812 % Remove both class and phase from rightmost position (preempt-resume)
813 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+2):end), 0];
814 end
815 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
816 if isinf(ni)
817 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wbuf,:)];
818 else
819 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wbuf,:)];
820 end
821 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
822 end
823 case SchedStrategy.LCFSPRPRIO % LCFS preempt-resume with priority groups
824 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
825 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
826 en_wbuf = en & ni>S(ist); %states with jobs in buffer
827 en_wobuf = ~en_wbuf;
828 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
829 % Buffer stores [class,phase,class,phase,...] pairs;
830 % only inspect class columns (odd: 1,3,5,...) for priority
831 class_cols = 1:2:size(space_buf,2);
832 space_buf_class = space_buf(:, class_cols);
833 space_buf_class_groupg = arrayfun(@(x) priogroup(1+x), space_buf_class);
834 start_classprio = min(space_buf_class_groupg(en_wbuf,:),[],2); % min finds highest priority
835 isrowmax = space_buf_class_groupg == repmat(start_classprio, 1, size(space_buf_class_groupg,2));
836 % LCFS: Find leftmost (first) class position for highest priority class (most recently preempted)
837 [~,leftmostClassPos]=max(isrowmax,[],2);
838 leftmostMaxPos = 2*leftmostClassPos - 1; % convert to buffer column index
839 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
840 kentry = space_buf(en_wbuf, leftmostMaxPos+1); % entry phase of job resuming service (preempt-resume)
841
842 % Handle states without buffer jobs
843 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
844 if isinf(ni)
845 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
846 else
847 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
848 end
849 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
850
851 % Handle states with buffer jobs
852 if any(en_wbuf) && start_svc_class > 0
853 space_srv_k = space_srv;
854 space_buf_k = space_buf;
855 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
856 for j=find(en_wbuf)'
857 % Remove both class and phase from leftmost position (preempt-resume)
858 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
859 end
860 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
861 if isinf(ni)
862 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wbuf,:)];
863 else
864 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wbuf,:)];
865 end
866 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
867 end
868 case SchedStrategy.FCFSPIPRIO % FCFS preempt-independent with priority groups
869 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
870 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
871 en_wbuf = en & ni>S(ist); %states with jobs in buffer
872 en_wobuf = ~en_wbuf;
873 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
874 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
875 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
876 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
877 % FCFS: Find rightmost (last) position for highest priority class
878 [~,rightmostMaxPos]=max(fliplr(isrowmax),[],2);
879 rightmostMaxPos = size(space_buf_groupg,2) - rightmostMaxPos + 1;
880 start_svc_class = space_buf(en_wbuf, rightmostMaxPos); % job entering service
881
882 % Handle states without buffer jobs
883 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
884 if isinf(ni)
885 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
886 else
887 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
888 end
889 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
890
891 % Handle states with buffer jobs
892 if any(en_wbuf) && start_svc_class > 0
893 % For FCFSPIPRIO, jobs restart from pie distribution instead of stored phase
894 pentry_svc_class = pie{ist}{start_svc_class};
895 for kentry = 1:K(start_svc_class)
896 space_srv_k = space_srv;
897 space_buf_k = space_buf;
898 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
899 for j=find(en_wbuf)'
900 % Remove both class and phase from rightmost position (preempt-independent ignores stored phase)
901 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+2):end), 0];
902 end
903 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
904 rate_k = rate;
905 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
906 if isinf(ni)
907 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
908 else
909 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
910 end
911 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
912 end
913 end
914 case SchedStrategy.LCFSPIPRIO % LCFS preempt-independent with priority groups
915 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
916 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
917 en_wbuf = en & ni>S(ist); %states with jobs in buffer
918 en_wobuf = ~en_wbuf;
919 priogroup = [Inf,sn.classprio]; % Inf for empty positions (lower value = higher priority)
920 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
921 start_classprio = min(space_buf_groupg(en_wbuf,:),[],2); % min finds highest priority
922 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
923 % LCFS: Find leftmost (first) position for highest priority class
924 [~,leftmostMaxPos]=max(isrowmax,[],2);
925 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
926
927 % Handle states without buffer jobs
928 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
929 if isinf(ni)
930 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
931 else
932 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
933 end
934 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
935
936 % Handle states with buffer jobs
937 if any(en_wbuf) && start_svc_class > 0
938 % For LCFSPIPRIO, jobs restart from pie distribution instead of stored phase
939 pentry_svc_class = pie{ist}{start_svc_class};
940 for kentry = 1:K(start_svc_class)
941 space_srv_k = space_srv;
942 space_buf_k = space_buf;
943 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
944 for j=find(en_wbuf)'
945 % Remove both class and phase from leftmost position (preempt-independent ignores stored phase)
946 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
947 end
948 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
949 rate_k = rate;
950 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
951 if isinf(ni)
952 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
953 else
954 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
955 end
956 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
957 end
958 end
959 case SchedStrategy.SIRO
960 rate = zeros(size(space_srv,1),1);
961 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
962 space_srv = inspace(:,end-sum(K)+1:end); % server state
963 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
964 % first record departure in states where the buffer is empty
965 en_wobuf = en & sum(space_buf(en,:),2) == 0;
966 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
967 if isinf(ni) % hit limited load-dependence
968 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
969 else
970 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
971 end
972 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
973 % let's go now to states where the buffer is non-empty
974 for r=1:R % pick a job of a random class
975 rate_r = rate;
976 space_buf = inspace(:,1:(end-sum(K))); % buffer state
977 en_wbuf = en & space_buf(en,r) > 0; % states where the buffer is non-empty
978 space_buf(en_wbuf,r) = space_buf(en_wbuf,r) - 1; % remove from buffer
979 space_srv_r = space_srv;
980 pentry_svc_class = pie{ist}{r};
981 pick_prob = (nir(r)-sir(r)) / (ni-sum(sir));
982 if pick_prob >= 0
983 rate_r(en_wbuf,:) = rate_r(en_wbuf,:) * pick_prob;
984 end
985 for kentry=1:K(r)
986 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) + 1; % bring job in service
987 outspace = [outspace; space_buf(en_wbuf,:), space_srv_r(en_wbuf,:), space_var(en_wbuf,:)];
988 rate_k = rate_r;
989 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
990 if isinf(ni) % hit limited load-dependence
991 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
992 else
993 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
994 end
995 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
996 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) - 1; % bring job in service
997 end
998 end
999 case {SchedStrategy.SEPT,SchedStrategy.LEPT} % move last job in service
1000 rate = zeros(size(space_srv,1),1);
1001 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
1002 space_srv = inspace(:,end-sum(K)+1:end); % server state
1003 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
1004 space_buf = inspace(:,1:(end-sum(K))); % buffer state
1005 % in SEPT, the scheduling parameter is the priority order of the class means
1006 % en_wbuf: states where the buffer is non-empty
1007 % sept_class: class to pick in service
1008 [en_wbuf, first_class_inrow] = max(space_buf(:,sn.schedparam(ist,:))~=0, [], 2);
1009 sept_class = sn.schedparam(ist,first_class_inrow); % this is different for sept and lept
1010
1011 space_buf(en_wbuf,sept_class) = space_buf(en_wbuf,sept_class) - 1; % remove from buffer
1012 pentry = pie{ist}{sept_class};
1013 for kentry=1:K(sept_class)
1014 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) + 1; % bring job in service
1015 if isSimulation
1016 % break the tie
1017 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
1018 rate_k = rate;
1019 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
1020 if isinf(ni) % hit limited load-dependence
1021 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
1022 else
1023 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
1024 end
1025 outprob = [outprob; ones(size(rate(en,:),1),1)];
1026 else
1027 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
1028 rate_k = rate;
1029 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
1030 if isinf(ni) % hit limited load-dependence
1031 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
1032 else
1033 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
1034 end
1035 outprob = [outprob; ones(size(rate(en,:),1),1)];
1036 end
1037 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) - 1; % bring job in service
1038 end
1039 otherwise
1040 line_error(mfilename,sprintf('Scheduling strategy %s is not supported.', SchedStrategy.toText(sn.sched(ist))));
1041 end
1042 end
1043 end
1044 if isSimulation
1045 if nargin>=7 && isobject(eventCache)
1046 eventCache(key) = {outprob, outspace,outrate};
1047 end
1048
1049 if size(outspace,1) > 1
1050 tot_rate = sum(outrate);
1051 cum_rate = cumsum(outrate) / tot_rate;
1052 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
1053 outspace = outspace(firing_ctr,:);
1054 outrate = sum(outrate);
1055 outprob = outprob(firing_ctr,:);
1056 end
1057 end
1058 end
1059 end
1060 case EventType.PHASE
1061 outspace = [];
1062 outrate = [];
1063 outprob = [];
1064 [ni,nir,~,kir] = State.toMarginal(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
1065 if nir(class)>0
1066 for k=1:K(class)
1067 en = space_srv(:,Ks(class)+k) > 0;
1068 if any(en)
1069 for kdest=setdiff(1:K(class),k) % new phase
1070 rate = 0;
1071 space_srv_k = space_srv(en,:);
1072 space_buf_k = space_buf(en,:);
1073 space_var_k = space_var(en,:);
1074 if ismkvmodclass(class) && ~isempty(space_var_k)
1075 space_var_k(sum(sn.nvars(ind,1:class))) = kdest;
1076 end
1077 space_srv_k(:,Ks(class)+k) = space_srv_k(:,Ks(class)+k) - 1;
1078 space_srv_k(:,Ks(class)+kdest) = space_srv_k(:,Ks(class)+kdest) + 1;
1079 switch sn.sched(ist)
1080 case SchedStrategy.EXT
1081 rate = proc{ist}{class}{1}(k,kdest); % move next job forward
1082 case SchedStrategy.INF
1083 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
1084 case {SchedStrategy.PS, SchedStrategy.LPS}
1085 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)./ni(:).*min(ni(:),S(ist)); % assume active
1086 case SchedStrategy.PSPRIO
1087 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1088 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)./ni(:).*min(ni(:),S(ist)); % assume active
1089 else
1090 rate = 0; % not in most urgent priority group
1091 end
1092 case SchedStrategy.DPSPRIO
1093 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1094 w_i = sn.schedparam(ist,:);
1095 w_i = w_i / sum(w_i);
1096 nirprio = nir;
1097 if ~all(ni <= S(ist))
1098 nirprio(sn.classprio~=sn.classprio(class)) = 0;
1099 end
1100 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
1101 else
1102 rate = 0; % not in most urgent priority group
1103 end
1104 case SchedStrategy.GPSPRIO
1105 if all(ni <= S(ist)) || sn.classprio(class) == min(sn.classprio(nir>0))
1106 w_i = sn.schedparam(ist,:);
1107 w_i = w_i / sum(w_i);
1108 nirprio = nir;
1109 if ~all(ni <= S(ist))
1110 nirprio(sn.classprio~=sn.classprio(class)) = 0;
1111 end
1112 cir = min(nirprio,ones(size(nirprio)));
1113 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)/nirprio(class)*w_i(class)/(w_i*cir(:)); % assume active
1114 else
1115 rate = 0; % not in most urgent priority group
1116 end
1117 case SchedStrategy.DPS
1118 if S(ist) > 1
1119 line_error(mfilename,'Multi-server DPS not supported yet');
1120 end
1121 w_i = sn.schedparam(ist,:);
1122 w_i = w_i / sum(w_i);
1123 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
1124 case SchedStrategy.GPS
1125 if S(ist) > 1
1126 line_error(mfilename,'Multi-server GPS not supported yet');
1127 end
1128 cir = min(nir,ones(size(nir)));
1129 w_i = sn.schedparam(ist,:); w_i = w_i / sum(w_i);
1130 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)/nir(class)*w_i(class)/(w_i*cir(:)); % assume active
1131
1132 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS, SchedStrategy.LCFSPR, SchedStrategy.LCFSPI, SchedStrategy.LCFSPRIO, SchedStrategy.SIRO, SchedStrategy.SEPT, SchedStrategy.LEPT}
1133 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
1134 end
1135 % if the class cannot be served locally,
1136 % then rate = NaN since mu{i,class}=NaN
1137 if isinf(ni) % hit limited load-dependence
1138 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate];
1139 else
1140 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate];
1141 end
1142 outspace = [outspace; space_buf_k, space_srv_k, space_var_k];
1143 outprob = [outprob; ones(size(rate,1),1)];
1144 end
1145 end
1146 end
1147 if isSimulation
1148 if nargin>=7 && isobject(eventCache)
1149 eventCache(key) = {outprob, outspace,outrate};
1150 end
1151
1152 if size(outspace,1) > 1
1153 tot_rate = sum(outrate);
1154 cum_rate = cumsum(outrate) / tot_rate;
1155 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
1156 outspace = outspace(firing_ctr,:);
1157 outrate = sum(outrate);
1158 outprob = outprob(firing_ctr,:);
1159 end
1160 end
1161 end
1162end
1163
1164end
Definition mmt.m:124