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 outprob = [];
14 outprob_k = [];
15 for kentry = 1:K(class)
16 space_var_k = space_var;
17 space_srv_k = space_srv;
18 space_buf_k = space_buf;
19 switch sn.sched(ist)
20 case SchedStrategy.EXT % source, can receive any "virtual" arrival from the sink as long as it is from an open class
21 if isinf(sn.njobs(class))
22 outspace = inspace;
23 outrate = -1*zeros(size(outspace,1)); % passive action, rate is unspecified
24 outprob = ones(size(outspace,1));
25 break
26 end
27 case {SchedStrategy.PS, SchedStrategy.INF, SchedStrategy.DPS, SchedStrategy.GPS, SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, SchedStrategy.LPS}
28 % job enters service immediately
29 if space_srv_k(:,Ks(class)+kentry) < classcap(ist,class)
30 space_srv_k(:,Ks(class)+kentry) = space_srv_k(:,Ks(class)+kentry) + 1;
31 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
32 else
33 outprob_k = pentry(kentry)*zeros(size(space_srv_k,1));
34 end
35 case {SchedStrategy.SIRO, SchedStrategy.SEPT, SchedStrategy.LEPT}
36 if ni<S(ist)
37 space_srv_k(:,Ks(class)+kentry) = space_srv_k(:,Ks(class)+kentry) + 1;
38 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
39 else
40 space_buf_k(:,class) = space_buf_k(:,class) + 1;
41 outprob_k = pentry(kentry)*ones(size(space_srv_k,1));
42 end
43 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS, SchedStrategy.LCFSPRIO}
44 % find states with all servers busy - this
45 % needs not to be moved
46
47 % if MAP service, when empty restart from the phase
48 % stored in space_var for this class
49 if ~ismkvmodclass(class) || (ismkvmodclass(class) && kentry == space_var(sum(sn.nvars(ind,1:class))))
50 if ismkvmodclass(class)
51 pentry = zeros(size(pentry));
52 pentry(kentry) = 1.0;
53 end
54 all_busy_srv = sum(space_srv_k,2) >= S(ist);
55
56 % find and modify states with an idle server
57 idle_srv = sum(space_srv_k,2) < S(ist);
58 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
59
60 % this section dynamically grows the number of
61 % elements in the buffer
62
63 if any(ni < capacity(ist))
64 if any(nir(:,class) < classcap(ist,class)) % if there is room
65 if ~any(space_buf_k(:)==0) % but the buffer has no empty slots
66 % append job slot
67 space_buf_k = [zeros(size(space_buf_k,1),1),space_buf_k];
68 end
69 end
70 end
71 %end
72 %get position of first empty slot
73 empty_slots = -1*ones(size(all_busy_srv,1),1);
74 if size(space_buf_k,2) == 0
75 empty_slots(all_busy_srv) = false;
76 elseif size(space_buf_k,2) == 1
77 empty_slots(all_busy_srv) = space_buf_k(all_busy_srv,:)==0;
78 else
79 empty_slots(all_busy_srv) = max(bsxfun(@times, space_buf_k(all_busy_srv,:)==0, [1:size(space_buf_k,2)]),[],2);
80 end
81
82 % ignore states where the buffer has no empty slots
83 wbuf_empty = empty_slots>0;
84 if any(wbuf_empty)
85 space_srv_k = space_srv_k(wbuf_empty,:);
86 space_buf_k = space_buf_k(wbuf_empty,:);
87 space_var_k = space_var_k(wbuf_empty,:);
88 empty_slots = empty_slots(wbuf_empty);
89 space_buf_k(sub2ind(size(space_buf_k),1:size(space_buf_k,1),empty_slots')) = class;
90 %outspace(all_busy_srv(wbuf_empty),:) = [space_buf, space_srv, space_var];
91 end
92 outprob_k = pentry(kentry)*ones(size(space_srv_k,1),1);
93 else
94 outprob_k = 0*ones(size(space_srv_k,1),1); % zero probability event
95 end
96 case {SchedStrategy.LCFSPR,SchedStrategy.LCFSPI,SchedStrategy.LCFSPRPRIO,SchedStrategy.LCFSPIPRIO}
97 % find states with all servers busy - this
98 % must not be moved
99 all_busy_srv = sum(space_srv_k,2) >= S(ist);
100 % find states with an idle server
101 idle_srv = sum(space_srv_k,2) < S(ist);
102
103 % reorder states so that idle ones come first
104 space_buf_k_reord = space_buf_k(idle_srv,:);
105 space_srv_k_reord = space_srv_k(idle_srv,:);
106 space_var_k_reord = space_var_k(idle_srv,:);
107
108 % if idle, the job enters service in phase kentry
109 if any(idle_srv)
110 space_srv_k_reord(:, end-sum(K)+Ks(class)+kentry) = space_srv_k_reord(:,end-sum(K)+Ks(class)+kentry) + 1;
111 outprob_k = pentry(kentry);
112 else
113 % if all busy, expand output states for all possible choices of job class to preempt
114 psentry = ones(size(space_buf_k_reord,1),1); % probability scaling due to preemption
115 for classpreempt = 1:R
116 for phasepreempt = 1:K(classpreempt) % phase of job to preempt
117 si_preempt = space_srv_k(:, (end-sum(K)+Ks(classpreempt)+phasepreempt));
118 busy_preempt = si_preempt > 0; % states where there is at least on class-r job in execution
119 if any(busy_preempt)
120 psentry = [psentry; si_preempt(busy_preempt) ./ sum(space_srv_k,2)];
121 space_srv_k_preempt = space_srv_k(busy_preempt,:);
122 space_buf_k_preempt = space_buf_k(busy_preempt,:);
123 space_var_k_preempt = space_var_k(busy_preempt,:);
124 space_srv_k_preempt(:, end-sum(K)+Ks(classpreempt)+phasepreempt) = space_srv_k_preempt(:,end-sum(K)+Ks(classpreempt)+phasepreempt) - 1; % remove preempted job
125 space_srv_k_preempt(:, end-sum(K)+Ks(class)+kentry) = space_srv_k_preempt(:,end-sum(K)+Ks(class)+kentry) + 1;
126
127 % dynamically grow buffer lenght in
128 % simulation
129 if isSimulation
130 if ni < capacity(ist) && nir(class) < classcap(ist,class) % if there is room
131 if ~any(space_buf_k_preempt(:)==0) % but the buffer has no empty slots
132 % append job slot
133 space_buf_k_preempt = [zeros(size(space_buf_k_preempt,1),2),space_buf_k]; % append two columns for (class, preempt-phase)
134 end
135 end
136 end
137
138 %get position of first empty slot
139 empty_slots = -1*ones(sum(busy_preempt),1);
140 if size(space_buf_k_preempt,2) == 0
141 empty_slots(busy_preempt) = false;
142 elseif size(space_buf_k_preempt,2) == 2 % 2 due to (class, preempt-phase) pairs
143 empty_slots(busy_preempt) = space_buf_k_preempt(busy_preempt,1:2:end)==0;
144 else
145 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
146 end
147
148 % ignore states where the buffer has no empty slots
149 wbuf_empty = empty_slots>0;
150 if any(wbuf_empty)
151 space_srv_k_preempt = space_srv_k_preempt(wbuf_empty,:);
152 space_buf_k_preempt = space_buf_k_preempt(wbuf_empty,:);
153 space_var_k_preempt = space_var_k_preempt(wbuf_empty,:);
154 empty_slots = empty_slots(wbuf_empty);
155 if sn.sched(ist) == SchedStrategy.LCFSPR % preempt-resume
156 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')+1) = phasepreempt;
157 elseif sn.sched(ist) == SchedStrategy.LCFSPI % preempt-independent
158 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')+1) = 1;
159 end
160 space_buf_k_preempt(sub2ind(size(space_buf_k_preempt),1:size(space_buf_k_preempt,1),empty_slots')) = classpreempt;
161 %outspace(all_busy_srv(wbuf_empty),:) = [space_buf, space_srv, space_var];
162 end
163 space_srv_k_reord = [space_srv_k_reord; space_srv_k_preempt];
164 space_buf_k_reord = [space_buf_k_reord; space_buf_k_preempt];
165 space_var_k_reord = [space_var_k_reord; space_var_k_preempt];
166 end
167 end
168 end
169 outprob_k = pentry(kentry) * psentry .* ones(size(space_srv_k_reord,1),1);
170 end
171 space_buf_k = space_buf_k_reord; % save reordered output states
172 space_srv_k = space_srv_k_reord; % save reordered output states
173 space_var_k = space_var_k_reord; % save reordered output states
174 end
175 % form the new state
176 outspace_k = [space_buf_k, space_srv_k, space_var_k];
177 % remove states where new arrival violates capacity or cutoff constraints
178 [oi,oir] = State.toMarginalAggr(sn,ind,outspace_k,K,Ks,space_buf_k,space_srv_k,space_var_k);
179 en_o = classcap(ist,class)>= oir(:,class) | capacity(ist)*ones(size(oi,1),1) >= oi;
180
181 if size(outspace,2)>size(outspace_k(en_o,:),2)
182 outspace = [outspace; zeros(1,size(outspace,2)-size(outspace_k(en_o,:),2)),outspace_k(en_o,:)];
183 elseif size(outspace,2)<size(outspace_k(en_o,:),2)
184 outspace = [zeros(size(outspace,1),size(outspace_k(en_o,:),2)-size(outspace,2)), outspace; outspace_k(en_o,:)];
185 else
186 outspace = [outspace; outspace_k(en_o,:)];
187 end
188 outrate = [outrate; -1*ones(size(outspace_k(en_o,:),1),1)]; % passive action, rate is unspecified
189 outprob = [outprob; outprob_k(en_o,:)];
190 end
191 if isSimulation
192 if size(outprob,1) > 1
193 cum_prob = cumsum(outprob) / sum(outprob);
194 firing_ctr = 1 + max([0,find( rand > cum_prob' )]); % select action
195 outspace = outspace(firing_ctr,:);
196 outrate = -1;
197 outprob = 1;
198 end
199 end
200 case EventType.DEP
201 if any(any(space_srv(:,(Ks(class)+1):(Ks(class)+K(class))))) % something is busy
202 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)
203 nir = space_srv;
204 ni = sum(nir,2);
205 sir = nir;
206 kir = sir;
207 else
208 [ni,nir,sir,kir] = State.toMarginal(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
209 end
210 switch sn.routing(ind,class)
211 case RoutingStrategy.RROBIN
212 idx = find(space_var(sum(sn.nvars(ind,1:(R+class)))) == sn.nodeparam{ind}{class}.outlinks);
213 if idx < length(sn.nodeparam{ind}{class}.outlinks)
214 space_var(sum(sn.nvars(ind,1:(R+class)))) = sn.nodeparam{ind}{class}.outlinks(idx+1);
215 else
216 space_var(sum(sn.nvars(ind,1:(R+class)))) = sn.nodeparam{ind}{class}.outlinks(1);
217 end
218 end
219 if sir(class)>0 % is a job of class is in service
220 outprob = [];
221 for k=1:K(class)
222 space_srv = inspace(:,(end-sum(K)-V+1):(end-V)); % server state
223 space_buf = inspace(:,1:(end-sum(K)-V)); % buffer state
224 rate = zeros(size(space_srv,1),1);
225 en = space_srv(:,Ks(class)+k) > 0;
226 if any(en)
227 switch sn.sched(ist)
228 case SchedStrategy.EXT % source, can produce an arrival from phase-k as long as it is from an open class
229 if isinf(sn.njobs(class))
230 pentry = pie{ist}{class};
231 for kentry = 1:K(class)
232 space_srv = inspace(:,(end-sum(K)-V+1):(end-V)); % server state
233 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
234 space_srv(en,Ks(class)+kentry) = space_srv(en,Ks(class)+kentry) + 1; % new job
235 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
236 if isinf(ni) % hit limited load-dependence
237 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*pentry(kentry)*mu{ist}{class}(k)*phi{ist}{class}(k)*ones(size(inspace(en,:),1),1)];
238 else
239 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*pentry(kentry)*mu{ist}{class}(k)*phi{ist}{class}(k)*ones(size(inspace(en,:),1),1)];
240 end
241 outprob = [outprob; ones(size(space_buf(en,:),1),1)];
242 end
243 end
244 case SchedStrategy.INF % move first job in service
245 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
246 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(en,class,k); % assume active
247 % if state is unchanged, still add with rate 0
248 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(end,:)];
249 if isinf(ni) % hit limited load-dependence
250 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
251 else
252 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
253 end
254 outprob = [outprob; ones(size(rate(en,:),1),1)];
255 case SchedStrategy.PS % move first job in service
256 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
257 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./ni(en)).*min(ni(en),S(ist)); % assume active
258 % if state is unchanged, still add with rate 0
259 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
260 if isinf(ni) % hit limited load-dependence
261 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
262 else
263 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
264 end
265 outprob = [outprob; ones(size(rate(en,:),1),1)];
266 % end
267 case SchedStrategy.PSPRIO
268 % unclear if LD scaling should be with
269 % ni or with niprio, for now left as ni
270 % for consistency with HOL multiserver
271 if sn.classprio(class) == max(sn.classprio(nir>0)) % if this class is in the highest priority group at the station
272 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
273 niprio(en) = sum(nir(sn.classprio==sn.classprio(class))); % jobs at the same priority class
274 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*(kir(en,class,k)./niprio(en)).*min(niprio(en),S(ist)); % assume active
275 % if state is unchanged, still add with rate 0
276 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
277 if isinf(ni) % hit limited load-dependence
278 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
279 else
280 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
281 end
282 outprob = [outprob; ones(size(rate(en,:),1),1)];
283 else % set state unchanged and zero rate
284 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
285 outrate = [outrate; zeros(size(rate(en,:),1),1)];
286 outprob = [outprob; ones(size(rate(en,:),1),1)];
287 end
288 case SchedStrategy.DPS
289 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
290 if S(ist) > 1
291 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
292 end
293 % in GPS, the scheduling parameter are the weights
294 w_i = sn.schedparam(ist,:);
295 w_i = w_i / sum(w_i);
296 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));
297 % if state is unchanged, still add with rate 0
298 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
299 if isinf(ni) % hit limited load-dependence
300 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
301 else
302 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
303 end
304 outprob = [outprob; ones(size(rate(en,:),1),1)];
305 case SchedStrategy.DPSPRIO
306 if sn.classprio(class) == max(sn.classprio(nir>0)) % if this class is in the highest priority group at the station
307 nirprio = nir;
308 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
309 niprio = sum(nirprio);
310 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
311 if S(ist) > 1
312 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
313 end
314 % in GPS, the scheduling parameter are the weights
315 w_i = sn.schedparam(ist,:);
316 w_i = w_i / sum(w_i);
317 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));
318 % if state is unchanged, still add with rate 0
319 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
320 if isinf(ni) % hit limited load-dependence
321 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,end).*rate(en,:)];
322 else
323 outrate = [outrate; cdscaling{ist}(nirprio).*lldscaling(ist,min(niprio(en),lldlimit)).*rate(en,:)];
324 end
325 outprob = [outprob; ones(size(rate(en,:),1),1)];
326 else % set state unchanged and zero rate
327 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
328 outrate = [outrate; zeros(size(rate(en,:),1),1)];
329 outprob = [outprob; ones(size(rate(en,:),1),1)];
330 end
331 case SchedStrategy.GPS
332 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
333 if S(ist) > 1
334 line_error(mfilename,'Multi-server GPS stations are not supported yet.');
335 end
336 % in GPS, the scheduling parameter are the weights
337 w_i = sn.schedparam(ist,:);
338 w_i = w_i / sum(w_i);
339 cir = min(nir,ones(size(nir)));
340 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nir(class))*w_i(class)/(w_i*cir(:)); % assume active
341 % if state is unchanged, still add with rate 0
342 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
343 if isinf(ni) % hit limited load-dependence
344 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
345 else
346 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
347 end
348 outprob = [outprob; ones(size(rate(en,:),1),1)];
349 case SchedStrategy.GPSPRIO
350 if sn.classprio(class) == max(sn.classprio(nir>0)) % if this class is in the highest priority group at the station
351 nirprio = nir;
352 nirprio(sn.classprio~=sn.classprio(class)) = 0; % ignore jobs of lower priority
353 niprio = sum(nirprio);
354 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
355 if S(ist) > 1
356 line_error(mfilename,'Multi-server DPS stations are not supported yet.');
357 end
358 % in GPS, the scheduling parameter are the weights
359 w_i = sn.schedparam(ist,:);
360 w_i = w_i / sum(w_i);
361 cir = min(nirprio,ones(size(nirprio)));
362 rate = mu{ist}{class}(k)*(phi{ist}{class}(k))*(kir(en,class,k)/nirprio(class))*w_i(class)/(w_i*cir(:)); % assume active
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 % set state unchanged and zero rate
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.FCFS % move first job in service
377 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
378 en_wbuf = en & ni>S(ist); %states with jobs in buffer
379 for kdest=1:K(class) % new phase
380 space_buf_kd = space_buf;
381 space_var_kd = space_var;
382 if ismkvmodclass(class)
383 space_var_kd(en,sum(sn.nvars(ind,1:class))) = kdest;
384 end
385 rate_kd = rate;
386 rate_kd(en) = proc{ist}{class}{2}(k,kdest).*kir(en,class,k); % assume active
387 % first process states without jobs in buffer
388 en_wobuf = ~en_wbuf;
389 if any(en_wobuf) %any state without jobs in buffer
390 outspace = [outspace; space_buf_kd(en_wobuf,:), space_srv(en_wobuf,:), space_var_kd(en_wobuf,:)];
391 if isinf(ni) % hit limited load-dependence
392 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_kd(en_wobuf,:)];
393 else
394 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_kd(en_wobuf,:)];
395 end
396 end
397 % now process states with jobs in buffer
398 outprob = [outprob; ones(size(rate_kd(en_wobuf,:),1),1)];
399 if any(en_wbuf) %any state with jobs in buffer
400 % get class of job at head
401 start_svc_class = space_buf_kd(en_wbuf,end);
402 if start_svc_class > 0 % redunant if?
403 % update input buffer
404 space_buf_kd(en_wbuf,:) = [zeros(sum(en_wbuf),1),space_buf_kd(en_wbuf,1:end-1)];
405 % probability vector for the next job of starting in phase kentry
406 if ismkvmodclass(start_svc_class) % if markov-modulated
407 if start_svc_class==class % if successive service from the same class
408 kentry_range = kdest; % new job enters in phase left by departing job
409 else % resume phase from local variables
410 kentry_range = space_var_kd(en,sum(sn.nvars(ind,1:start_svc_class)));
411 end
412 pentry_svc_class = 0*pie{ist}{start_svc_class};
413 pentry_svc_class(kentry_range) = 1.0;
414 else % if i.i.d.
415 pentry_svc_class = pie{ist}{start_svc_class};
416 kentry_range = 1:K(start_svc_class);
417 end
418 for kentry = kentry_range
419 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
420 outspace = [outspace; space_buf_kd(en,:), space_srv(en,:), space_var_kd(en,:)];
421 rate_k = rate_kd;
422 rate_k(en_wbuf,:) = rate_kd(en_wbuf,:)*pentry_svc_class(kentry);
423 if isinf(ni) % use limited load-dependence at the latest user-provided level
424 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
425 else
426 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
427 end
428 outprob_cur = ones(size(rate_kd(en,:),1),1);
429 outprob_cur(outrate==0.0) = 0;
430 outprob = [outprob; outprob_cur'];
431 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
432 end
433 end
434 end
435 end
436 % if state is unchanged, still add with rate 0
437 case SchedStrategy.HOL % FCFS priority
438 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
439 en_wbuf = en & ni>S(ist); %states with jobs in buffer
440 en_wobuf = ~en_wbuf;
441 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
442 priogroup = [0,sn.classprio];
443 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
444 start_classprio = max(space_buf_groupg(en_wbuf,:),[],2);
445 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
446 [~,rightmostMaxPosFlipped]=max(fliplr(isrowmax),[],2);
447 rightmostMaxPos = size(isrowmax,2) - rightmostMaxPosFlipped + 1;
448 start_svc_class = space_buf(en_wbuf, rightmostMaxPos);
449 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
450 if isinf(ni) % hit limited load-dependence
451 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
452 else
453 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
454 end
455 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
456 if start_svc_class > 0
457 pentry_svc_class = pie{ist}{start_svc_class};
458 for kentry = 1:K(start_svc_class)
459 space_srv_k = space_srv;
460 space_buf_k = space_buf;
461 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
462 for j=find(en_wbuf)'
463 space_buf_k(j,:) = [0, space_buf_k(j,1:rightmostMaxPos(j)-1), space_buf_k(j,(rightmostMaxPos(j)+1):end)];
464 end
465 % if state is unchanged, still add with rate 0
466 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
467 rate_k = rate;
468 rate_k(en_wbuf,:) = rate(en_wbuf,:) * pentry_svc_class(kentry);
469 if isinf(ni) % hit limited load-dependence
470 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
471 else
472 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
473 end
474 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
475 end
476 end
477 case SchedStrategy.LCFSPRIO % LCFS priority - like HOL but LCFS order within priority groups
478 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
479 en_wbuf = en & ni>S(ist); %states with jobs in buffer
480 en_wobuf = ~en_wbuf;
481 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
482 priogroup = [0,sn.classprio];
483 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
484 start_classprio = max(space_buf_groupg(en_wbuf,:),[],2);
485 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
486 % LCFS: Find leftmost (first) position instead of rightmost for LCFS order
487 [~,leftmostMaxPos]=max(isrowmax,[],2);
488 start_svc_class = space_buf(en_wbuf, leftmostMaxPos);
489 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
490 if isinf(ni) % hit limited load-dependence
491 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
492 else
493 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
494 end
495 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
496 if start_svc_class > 0
497 pentry_svc_class = pie{ist}{start_svc_class};
498 for kentry = 1:K(start_svc_class)
499 space_srv_k = space_srv;
500 space_buf_k = space_buf;
501 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
502 for j=find(en_wbuf)'
503 % LCFS: Remove from leftmost position instead of rightmost
504 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+1):end)];
505 end
506 % if state is unchanged, still add with rate 0
507 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
508 rate_k = rate;
509 rate_k(en_wbuf,:) = rate_k(en_wbuf,:)*pentry_svc_class(kentry);
510 if isinf(ni) % hit limited load-dependence
511 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
512 else
513 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
514 end
515 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
516 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) - 1;
517 end
518 end
519 case SchedStrategy.LCFS % move last job in service
520 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
521 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
522 en_wbuf = en & ni>S(ist); %states with jobs in buffer
523 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
524 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
525 space_buf(en_wbuf,colfirstnnz)=0;
526 if isempty(start_svc_class)
527 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
528 if isinf(ni) % hit limited load-dependence
529 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
530 else
531 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
532 end
533 outprob = [outprob; ones(size(rate(en,:),1),1)];
534 if isSimulation && nargin>=7 && isobject(eventCache)
535 eventCache(key) = {outprob, outspace,outrate};
536 end
537 return
538 end
539 for kentry = 1:K(start_svc_class)
540 pentry_svc_class = pie{ist}{start_svc_class};
541 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
542 % if state is unchanged, still add with rate 0
543 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
544 rate_k = rate;
545 rate_k(en_wbuf,:) = rate(en_wbuf,:)*pentry_svc_class(kentry);
546 if isinf(ni) % hit limited load-dependence
547 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
548 else
549 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
550 end
551 outprob = [outprob; ones(size(rate(en,:),1),1)];
552 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) - 1;
553 end
554 case SchedStrategy.LCFSPR % move last job in service (preempt-resume)
555 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
556 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
557 en_wbuf = en & ni>S(ist); %states with jobs in buffer
558 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
559 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
560 kentry = space_buf(en_wbuf,colfirstnnz+1); % entry phase of job resuming service
561 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
562 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase
563 if isempty(start_svc_class)
564 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
565 if isinf(ni) % hit limited load-dependence
566 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
567 else
568 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
569 end
570 outprob = [outprob; ones(size(rate(en,:),1),1)];
571 if isSimulation && nargin>=7 && isobject(eventCache)
572 eventCache(key) = {outprob, outspace,outrate};
573 end
574 return
575 end
576 space_srv(en_wbuf,Ks(start_svc_class)+kentry) = space_srv(en_wbuf,Ks(start_svc_class)+kentry) + 1;
577 % if state is unchanged, still add with rate 0
578 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
579 if isinf(ni) % hit limited load-dependence
580 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
581 else
582 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
583 end
584 outprob = [outprob; ones(size(rate(en,:),1),1)];
585 case SchedStrategy.LCFSPI % move last job in service (preempt-independent)
586 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
587 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
588 en_wbuf = en & ni>S(ist); %states with jobs in buffer
589 [~, colfirstnnz] = max( space_buf(en_wbuf,:) ~=0, [], 2 ); % find first nnz column
590 start_svc_class = space_buf(en_wbuf,colfirstnnz); % job entering service
591 space_buf(en_wbuf,colfirstnnz)=0;% zero popped job
592 space_buf(en_wbuf,colfirstnnz+1)=0; % zero popped phase (ignored for LCFSPI)
593 if isempty(start_svc_class)
594 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
595 if isinf(ni) % hit limited load-dependence
596 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en,:)];
597 else
598 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en,:)];
599 end
600 outprob = [outprob; ones(size(rate(en,:),1),1)];
601 if isSimulation && nargin>=7 && isobject(eventCache)
602 eventCache(key) = {outprob, outspace,outrate};
603 end
604 return
605 end
606 % For LCFSPI, jobs restart from pie distribution instead of stored phase
607 pentry_svc_class = pie{ist}{start_svc_class};
608 for kentry = 1:K(start_svc_class)
609 space_srv_k = space_srv;
610 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
611 % if state is unchanged, still add with rate 0
612 outspace = [outspace; space_buf(en,:), space_srv_k(en,:), space_var(en,:)];
613 rate_k = rate;
614 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
615 if isinf(ni) % hit limited load-dependence
616 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
617 else
618 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
619 end
620 outprob = [outprob; ones(size(rate_k(en,:),1),1)];
621 end
622 case SchedStrategy.LCFSPRPRIO % LCFS preempt-resume with priority groups
623 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
624 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
625 en_wbuf = en & ni>S(ist); %states with jobs in buffer
626 en_wobuf = ~en_wbuf;
627 priogroup = [0,sn.classprio];
628 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
629 start_classprio = max(space_buf_groupg(en_wbuf,:),[],2);
630 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
631 % LCFS: Find leftmost (first) position for highest priority class
632 [~,leftmostMaxPos]=max(isrowmax,[],2);
633 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
634 kentry = space_buf(en_wbuf, leftmostMaxPos+1); % entry phase of job resuming service (preempt-resume)
635
636 % Handle states without buffer jobs
637 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
638 if isinf(ni)
639 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
640 else
641 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
642 end
643 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
644
645 % Handle states with buffer jobs
646 if any(en_wbuf) && start_svc_class > 0
647 space_srv_k = space_srv;
648 space_buf_k = space_buf;
649 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
650 for j=find(en_wbuf)'
651 % Remove both class and phase from leftmost position (preempt-resume)
652 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
653 end
654 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
655 if isinf(ni)
656 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wbuf,:)];
657 else
658 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wbuf,:)];
659 end
660 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
661 end
662 case SchedStrategy.LCFSPIPRIO % LCFS preempt-independent with priority groups
663 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
664 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % assume active
665 en_wbuf = en & ni>S(ist); %states with jobs in buffer
666 en_wobuf = ~en_wbuf;
667 priogroup = [0,sn.classprio];
668 space_buf_groupg = arrayfun(@(x) priogroup(1+x), space_buf);
669 start_classprio = max(space_buf_groupg(en_wbuf,:),[],2);
670 isrowmax = space_buf_groupg == repmat(start_classprio, 1, size(space_buf_groupg,2));
671 % LCFS: Find leftmost (first) position for highest priority class
672 [~,leftmostMaxPos]=max(isrowmax,[],2);
673 start_svc_class = space_buf(en_wbuf, leftmostMaxPos); % job entering service
674
675 % Handle states without buffer jobs
676 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
677 if isinf(ni)
678 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
679 else
680 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
681 end
682 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
683
684 % Handle states with buffer jobs
685 if any(en_wbuf) && start_svc_class > 0
686 % For LCFSPIPRIO, jobs restart from pie distribution instead of stored phase
687 pentry_svc_class = pie{ist}{start_svc_class};
688 for kentry = 1:K(start_svc_class)
689 space_srv_k = space_srv;
690 space_buf_k = space_buf;
691 space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) = space_srv_k(en_wbuf,Ks(start_svc_class)+kentry) + 1;
692 for j=find(en_wbuf)'
693 % Remove both class and phase from leftmost position (preempt-independent ignores stored phase)
694 space_buf_k(j,:) = [0, space_buf_k(j,1:leftmostMaxPos(j)-1), space_buf_k(j,(leftmostMaxPos(j)+2):end), 0];
695 end
696 outspace = [outspace; space_buf_k(en_wbuf,:), space_srv_k(en_wbuf,:), space_var(en_wbuf,:)];
697 rate_k = rate;
698 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
699 if isinf(ni)
700 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
701 else
702 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
703 end
704 outprob = [outprob; ones(size(rate_k(en_wbuf,:),1),1)];
705 end
706 end
707 case SchedStrategy.SIRO
708 rate = zeros(size(space_srv,1),1);
709 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
710 space_srv = inspace(:,end-sum(K)+1:end); % server state
711 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
712 % first record departure in states where the buffer is empty
713 en_wobuf = en & sum(space_buf(en,:),2) == 0;
714 outspace = [outspace; space_buf(en_wobuf,:), space_srv(en_wobuf,:), space_var(en_wobuf,:)];
715 if isinf(ni) % hit limited load-dependence
716 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate(en_wobuf,:)];
717 else
718 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate(en_wobuf,:)];
719 end
720 outprob = [outprob; ones(size(rate(en_wobuf,:),1),1)];
721 % let's go now to states where the buffer is non-empty
722 for r=1:R % pick a job of a random class
723 rate_r = rate;
724 space_buf = inspace(:,1:(end-sum(K))); % buffer state
725 en_wbuf = en & space_buf(en,r) > 0; % states where the buffer is non-empty
726 space_buf(en_wbuf,r) = space_buf(en_wbuf,r) - 1; % remove from buffer
727 space_srv_r = space_srv;
728 pentry_svc_class = pie{ist}{r};
729 pick_prob = (nir(r)-sir(r)) / (ni-sum(sir));
730 if pick_prob >= 0
731 rate_r(en_wbuf,:) = rate_r(en_wbuf,:) * pick_prob;
732 end
733 for kentry=1:K(r)
734 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) + 1; % bring job in service
735 outspace = [outspace; space_buf(en_wbuf,:), space_srv_r(en_wbuf,:), space_var(en_wbuf,:)];
736 rate_k = rate_r;
737 rate_k(en_wbuf,:) = rate_k(en_wbuf,:) * pentry_svc_class(kentry);
738 if isinf(ni) % hit limited load-dependence
739 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en_wbuf,:)];
740 else
741 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en_wbuf,:)];
742 end
743 outprob = [outprob; ones(size(rate(en_wbuf,:),1),1)];
744 space_srv_r(en_wbuf,Ks(r)+kentry) = space_srv_r(en_wbuf,Ks(r)+kentry) - 1; % bring job in service
745 end
746 end
747 case {SchedStrategy.SEPT,SchedStrategy.LEPT} % move last job in service
748 rate = zeros(size(space_srv,1),1);
749 rate(en) = mu{ist}{class}(k)*(phi{ist}{class}(k)).*kir(:,class,k); % this is for states not in en_buf
750 space_srv = inspace(:,end-sum(K)+1:end); % server state
751 space_srv(en,Ks(class)+k) = space_srv(en,Ks(class)+k) - 1; % record departure
752 space_buf = inspace(:,1:(end-sum(K))); % buffer state
753 % in SEPT, the scheduling parameter is the priority order of the class means
754 % en_wbuf: states where the buffer is non-empty
755 % sept_class: class to pick in service
756 [en_wbuf, first_class_inrow] = max(space_buf(:,sn.schedparam(ist,:))~=0, [], 2);
757 sept_class = sn.schedparam(ist,first_class_inrow); % this is different for sept and lept
758
759 space_buf(en_wbuf,sept_class) = space_buf(en_wbuf,sept_class) - 1; % remove from buffer
760 pentry = pie{ist}{sept_class};
761 for kentry=1:K(sept_class)
762 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) + 1; % bring job in service
763 if isSimulation
764 % break the tie
765 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
766 rate_k = rate;
767 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
768 if isinf(ni) % hit limited load-dependence
769 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
770 else
771 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
772 end
773 outprob = [outprob; ones(size(rate(en,:),1),1)];
774 else
775 outspace = [outspace; space_buf(en,:), space_srv(en,:), space_var(en,:)];
776 rate_k = rate;
777 rate_k(en,:) = rate_k(en,:) * pentry(kentry);
778 if isinf(ni) % hit limited load-dependence
779 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate_k(en,:)];
780 else
781 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate_k(en,:)];
782 end
783 outprob = [outprob; ones(size(rate(en,:),1),1)];
784 end
785 space_srv(en_wbuf,Ks(sept_class)+kentry) = space_srv(en_wbuf,Ks(sept_class)+kentry) - 1; % bring job in service
786 end
787 otherwise
788 line_error(mfilename,sprintf('Scheduling strategy %s is not supported.', SchedStrategy.toText(sn.sched(ist))));
789 end
790 end
791 end
792 if isSimulation
793 if nargin>=7 && isobject(eventCache)
794 eventCache(key) = {outprob, outspace,outrate};
795 end
796
797 if size(outspace,1) > 1
798 tot_rate = sum(outrate);
799 cum_rate = cumsum(outrate) / tot_rate;
800 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
801 outspace = outspace(firing_ctr,:);
802 outrate = sum(outrate);
803 outprob = outprob(firing_ctr,:);
804 end
805 end
806 end
807 end
808 case EventType.PHASE
809 outspace = [];
810 outrate = [];
811 outprob = [];
812 [ni,nir,~,kir] = State.toMarginal(sn,ind,inspace,K,Ks,space_buf,space_srv,space_var);
813 if nir(class)>0
814 for k=1:K(class)
815 en = space_srv(:,Ks(class)+k) > 0;
816 if any(en)
817 for kdest=setdiff(1:K(class),k) % new phase
818 rate = 0;
819 space_srv_k = space_srv(en,:);
820 space_buf_k = space_buf(en,:);
821 space_var_k = space_var(en,:);
822 if ismkvmodclass(class)
823 space_var_k(sum(sn.nvars(ind,1:class))) = kdest;
824 end
825 space_srv_k(:,Ks(class)+k) = space_srv_k(:,Ks(class)+k) - 1;
826 space_srv_k(:,Ks(class)+kdest) = space_srv_k(:,Ks(class)+kdest) + 1;
827 switch sn.sched(ist)
828 case SchedStrategy.EXT
829 rate = proc{ist}{class}{1}(k,kdest); % move next job forward
830 case SchedStrategy.INF
831 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
832 case {SchedStrategy.PS, SchedStrategy.PSPRIO, SchedStrategy.DPSPRIO, SchedStrategy.GPSPRIO, SchedStrategy.LPS}
833 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)./ni(:).*min(ni(:),S(ist)); % assume active
834 case SchedStrategy.DPS
835 if S(ist) > 1
836 line_error(mfilename,'Multi-server DPS not supported yet');
837 end
838 w_i = sn.schedparam(ist,:);
839 w_i = w_i / sum(w_i);
840 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
841 case SchedStrategy.GPS
842 if S(ist) > 1
843 line_error(mfilename,'Multi-server GPS not supported yet');
844 end
845 cir = min(nir,ones(size(nir)));
846 w_i = sn.schedparam(ist,:); w_i = w_i / sum(w_i);
847 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k)/nir(class)*w_i(class)/(w_i*cir(:)); % assume active
848
849 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.LCFS, SchedStrategy.LCFSPR, SchedStrategy.LCFSPI, SchedStrategy.LCFSPRIO, SchedStrategy.SIRO, SchedStrategy.SEPT, SchedStrategy.LEPT}
850 rate = proc{ist}{class}{1}(k,kdest)*kir(:,class,k); % assume active
851 end
852 % if the class cannot be served locally,
853 % then rate = NaN since mu{i,class}=NaN
854 if isinf(ni) % hit limited load-dependence
855 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,end).*rate];
856 else
857 outrate = [outrate; cdscaling{ist}(nir).*lldscaling(ist,min(ni(en),lldlimit)).*rate];
858 end
859 outspace = [outspace; space_buf_k, space_srv_k, space_var_k];
860 outprob = [outprob; ones(size(rate,1),1)];
861 end
862 end
863 end
864 if isSimulation
865 if nargin>=7 && isobject(eventCache)
866 eventCache(key) = {outprob, outspace,outrate};
867 end
868
869 if size(outspace,1) > 1
870 tot_rate = sum(outrate);
871 cum_rate = cumsum(outrate) / tot_rate;
872 firing_ctr = 1 + max([0,find( rand > cum_rate' )]); % select action
873 outspace = outspace(firing_ctr,:);
874 outrate = sum(outrate);
875 outprob = outprob(firing_ctr,:);
876 end
877 end
878 end
879end
880
881end