LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
updateMetricsMomentBased.m
1function updateMetricsMomentBased(self,it)
2ensemble = self.ensemble;
3lqn = self.lqn;
4if ~self.hasconverged
5 % first obtain servt of activities at hostlayers
6 self.servt = zeros(lqn.nidx,1);
7 self.residt = zeros(lqn.nidx,1);
8 for r=1:size(self.servt_classes_updmap,1)
9 idx = self.servt_classes_updmap(r,1);
10 aidx = self.servt_classes_updmap(r,2);
11 nodeidx = self.servt_classes_updmap(r,3);
12 classidx = self.servt_classes_updmap(r,4);
13 self.servt(aidx) = self.results{end,self.idxhash(idx)}.RN(nodeidx,classidx);
14 self.tput(aidx) = self.results{end,self.idxhash(idx)}.TN(nodeidx,classidx);
15 self.servtproc{aidx} = Exp.fitMean(self.servt(aidx));
16
17 % Compute residt from QN/TN_ref (matching updateMetricsDefault)
18 layerIdx = self.idxhash(idx);
19 layerSn = ensemble{layerIdx}.getStruct();
20 c = find(layerSn.chains(:, classidx), 1);
21 refclass_c = layerSn.refclass(c);
22 refstat_k = layerSn.refstat(classidx);
23 TN_ref = self.results{end,layerIdx}.TN(refstat_k, refclass_c);
24 if TN_ref > GlobalConstants.FineTol
25 self.residt(aidx) = self.results{end,layerIdx}.QN(nodeidx,classidx) / TN_ref;
26 else
27 self.residt(aidx) = self.results{end,layerIdx}.WN(nodeidx,classidx);
28 end
29
30 % Think time in series with the host demand, as in updateMetricsDefault.
31 % The mean is carried here for the entry servt aggregation; the full
32 % distribution is convolved into the CDF moments in the converged branch
33 % below.
34 zt_act = lqn_act_thinktime(lqn, aidx);
35 if zt_act > 0
36 self.servt(aidx) = self.servt(aidx) + zt_act;
37 self.residt(aidx) = self.residt(aidx) + zt_act;
38 self.servtproc{aidx} = Exp.fitMean(self.servt(aidx));
39 end
40 end
41
42 % estimate call response times at hostlayers
43 self.callservt = zeros(lqn.ncalls,1);
44 self.callresidt = zeros(lqn.ncalls,1);
45 for r=1:size(self.call_classes_updmap,1)
46 idx = self.call_classes_updmap(r,1);
47 cidx = self.call_classes_updmap(r,2);
48 nodeidx = self.call_classes_updmap(r,3);
49 classidx = self.call_classes_updmap(r,4);
50 if self.call_classes_updmap(r,3) > 1
51 if nodeidx == 1
52 self.callservt(cidx) = 0;
53 self.callresidt(cidx) = 0;
54 else
55 % Include call multiplicity in callservt (matching updateMetricsDefault)
56 self.callservt(cidx) = self.results{end, self.idxhash(idx)}.RN(nodeidx,classidx) * self.lqn.callproc{cidx}.getMean;
57 % callresidt uses WN which already includes visit multiplicity
58 self.callresidt(cidx) = self.results{end, self.idxhash(idx)}.WN(nodeidx,classidx);
59 end
60 end
61 end
62
63 % then resolve the entry servt summing up these contributions
64 entry_servt = (eye(lqn.nidx+lqn.ncalls)-self.servtmatrix)\[self.servt;self.callservt];
65 entry_servt(1:lqn.eshift) = 0;
66
67 % Propagate forwarding calls: add target entry's service time to source entry
68 for cidx = 1:lqn.ncalls
69 if lqn.calltype(cidx) == CallType.FWD
70 source_eidx = lqn.callpair(cidx, 1);
71 target_eidx = lqn.callpair(cidx, 2);
72 fwd_prob = lqn.callproc{cidx}.getMean();
73 entry_servt(source_eidx) = entry_servt(source_eidx) + fwd_prob * entry_servt(target_eidx);
74 end
75 end
76
77 self.servt(lqn.eshift+1:lqn.eshift+lqn.nentries) = entry_servt(lqn.eshift+1:lqn.eshift+lqn.nentries);
78 entry_servt((lqn.ashift+1):end) = 0;
79
80 % Compute entry-level residt using servtmatrix and activity residt
81 % callresidt uses WN which already includes visit multiplicity
82 entry_residt = self.servtmatrix*[self.residt;self.callresidt(:)];
83 entry_residt(1:lqn.eshift) = 0;
84 % Scale entry residt by task/entry throughput ratio (matching updateMetricsDefault)
85 for eidx=(lqn.eshift+1):(lqn.eshift+lqn.nentries)
86 tidx = lqn.parent(eidx);
87 hidx = lqn.parent(tidx);
88 if ~self.ignore(tidx) && ~self.ignore(hidx)
89 hasSyncCallers = full(any(lqn.issynccaller(:, eidx)));
90 if hasSyncCallers
91 tidxclass = ensemble{self.idxhash(hidx)}.attribute.tasks(find(ensemble{self.idxhash(hidx)}.attribute.tasks(:,2) == tidx),1);
92 eidxclass = ensemble{self.idxhash(hidx)}.attribute.entries(find(ensemble{self.idxhash(hidx)}.attribute.entries(:,2) == eidx),1);
93 task_tput = sum(self.results{end,self.idxhash(hidx)}.TN(ensemble{self.idxhash(hidx)}.attribute.clientIdx,tidxclass));
94 entry_tput = sum(self.results{end,self.idxhash(hidx)}.TN(ensemble{self.idxhash(hidx)}.attribute.clientIdx,eidxclass));
95 self.servt(eidx) = entry_servt(eidx) * task_tput / max(GlobalConstants.Zero, entry_tput);
96 self.residt(eidx) = entry_residt(eidx) * task_tput / max(GlobalConstants.Zero, entry_tput);
97 else
98 self.residt(eidx) = entry_residt(eidx);
99 end
100 end
101 end
102
103 for r=1:size(self.call_classes_updmap,1)
104 cidx = self.call_classes_updmap(r,2);
105 eidx = lqn.callpair(cidx,2);
106 if self.call_classes_updmap(r,3) > 1
107 self.servtproc{eidx} = Exp.fitMean(self.servt(eidx));
108 end
109 end
110
111 % determine call response times processes
112 for r=1:size(self.call_classes_updmap,1)
113 cidx = self.call_classes_updmap(r,2);
114 eidx = lqn.callpair(cidx,2);
115 if self.call_classes_updmap(r,3) > 1
116 if it==1
117 % note that respt is per visit, so number of calls is 1
118 self.callservt(cidx) = self.servt(eidx);
119 self.callservtproc{cidx} = self.servtproc{eidx};
120 else
121 % note that respt is per visit, so number of calls is 1
122 self.callservtproc{cidx} = Exp.fitMean(self.callservt(cidx));
123 end
124 end
125 end
126else
127 self.servtcdf = cell(lqn.nidx,1);
128 repo = [];
129
130 % first obtain servt of activities at hostlayers
131 self.servt = zeros(lqn.nidx,1);
132 self.residt = zeros(lqn.nidx,1);
133 for r=1:size(self.servt_classes_updmap,1)
134 idx = self.servt_classes_updmap(r,1);
135 aidx = self.servt_classes_updmap(r,2);
136 nodeidx = self.servt_classes_updmap(r,3);
137 classidx = self.servt_classes_updmap(r,4);
138 self.tput(aidx) = self.results{end,self.idxhash(idx)}.TN(nodeidx,classidx);
139
140 % Compute residt from QN/TN_ref (matching updateMetricsDefault)
141 layerIdx = self.idxhash(idx);
142 layerSn = ensemble{layerIdx}.getStruct();
143 c = find(layerSn.chains(:, classidx), 1);
144 refclass_c = layerSn.refclass(c);
145 refstat_k = layerSn.refstat(classidx);
146 TN_ref = self.results{end,layerIdx}.TN(refstat_k, refclass_c);
147 if TN_ref > GlobalConstants.FineTol
148 self.residt(aidx) = self.results{end,layerIdx}.QN(nodeidx,classidx) / TN_ref;
149 else
150 self.residt(aidx) = self.results{end,layerIdx}.WN(nodeidx,classidx);
151 end
152
153 submodelidx = self.idxhash(idx);
154 if submodelidx>length(repo)
155 % Try SolverFluid first for actual response time CDFs with
156 % higher-moment information; fall back to layer solver's
157 % exponential approximation if Fluid fails on the layer model
158 try
159 repo{submodelidx} = SolverFluid(ensemble{submodelidx}).getCdfRespT;
160 catch
161 repo{submodelidx} = self.solvers{submodelidx}.getCdfRespT;
162 end
163 end
164 self.servtcdf{aidx} = repo{submodelidx}{nodeidx,classidx};
165 end
166
167 self.callservtcdf = cell(lqn.ncalls,1);
168
169 % estimate call response times at hostlayers
170 self.callservt = zeros(lqn.ncalls,1);
171 self.callresidt = zeros(lqn.ncalls,1);
172 for r=1:size(self.call_classes_updmap,1)
173 idx = self.call_classes_updmap(r,1);
174 cidx = self.call_classes_updmap(r,2);
175 nodeidx = self.call_classes_updmap(r,3);
176 classidx = self.call_classes_updmap(r,4);
177 if self.call_classes_updmap(r,3) > 1
178 submodelidx = self.idxhash(idx);
179 if submodelidx>length(repo)
180 try
181 repo{submodelidx} = SolverFluid(ensemble{submodelidx}).getCdfRespT;
182 catch
183 repo{submodelidx} = self.solvers{submodelidx}.getCdfRespT;
184 end
185 end
186 try
187 self.callservtcdf{cidx} = repo{submodelidx}{nodeidx,classidx};
188 catch
189 self.callservtcdf{cidx} = repo{submodelidx};
190 end
191 % Also set callresidt from WN (includes visit multiplicity)
192 if nodeidx > 1
193 self.callresidt(cidx) = self.results{end, self.idxhash(idx)}.WN(nodeidx,classidx);
194 end
195 end
196 end
197 cdf = [self.servtcdf;self.callservtcdf];
198
199 % then resolve the entry servt summing up these contributions
200 matrix = inv((eye(lqn.nidx+lqn.ncalls)-self.servtmatrix));
201 for i = 1:1:lqn.nentries
202 eidx = lqn.eshift+i;
203 convolidx = find(matrix(eidx,:)>0);
204 convolidx(find(convolidx<=lqn.eshift+lqn.nentries))=[];
205 num = 0;
206 ParamCell = {};
207 while num<length(convolidx)
208 fitidx = convolidx(num+1);
209 [m1,m2,m3,~,~] = EmpiricalCDF(cdf{fitidx}).getMoments;
210
211 % The layer CDF carries only the activity's host demand and queueing;
212 % the think time is a delay in series (held at the task, off the
213 % processor), so its full distribution is convolved: for independent
214 % X+T the raw moments compose as m1+t1, m2+2*m1*t1+t2,
215 % m3+3*m2*t1+3*m1*t2+t3. Raw moments of T come from the Distribution
216 % object (mean, SCV, skewness), since no PH raw-moment API exists.
217 if fitidx <= lqn.nidx && lqn_act_thinktime(lqn, fitidx) > 0
218 ztd = lqn.actthink{fitidx};
219 t1 = ztd.getMean();
220 sig2 = ztd.getSCV()*t1^2;
221 t2 = sig2 + t1^2;
222 t3 = ztd.getSkewness()*sig2^1.5 + 3*t1*t2 - 2*t1^3;
223 m3 = m3 + 3*m2*t1 + 3*m1*t2 + t3;
224 m2 = m2 + 2*m1*t1 + t2;
225 m1 = m1 + t1;
226 end
227 % Use CoarseTol to skip near-zero mean CDFs (e.g., Immediate activities)
228 % whose APH fitting produces extreme rate parameters that cause
229 % matrix exponential evaluation to hang
230 if m1>GlobalConstants.CoarseTol
231 fitdist = APH.fitRawMoments(m1,m2,m3);
232 aphparam{1} = fitdist.params{1}.paramValue; % alpha
233 aphparam{2} = fitdist.params{2}.paramValue; % T
234
235 % For call indices, multiply repetitions by mean number of calls
236 % servtmatrix has 1.0 for calls, but we need callproc.getMean() repetitions
237 reps = matrix(eidx,fitidx);
238 if fitidx > lqn.nidx
239 cidx_local = fitidx - lqn.nidx;
240 reps = reps * lqn.callproc{cidx_local}.getMean();
241 end
242 integerRepetitions = floor(reps);
243 fractionalPartRepetitions = reps - integerRepetitions;
244
245 if fractionalPartRepetitions == 0
246 ParamCell = [ParamCell,repmat(aphparam,1,integerRepetitions)];
247 elseif integerRepetitions>0 && fractionalPartRepetitions>0
248 ParamCell = [ParamCell,repmat(aphparam,1,integerRepetitions)];
249 % Near-instant branch, taken by the fraction of the mix that
250 % performs no further repetition. It is built as an APH
251 % directly: APH.fitMeanAndSCV with a mean at or below FineTol
252 % returns an Exp, which carries a single parameter, so
253 % reading params{2} for the subgenerator threw and this whole
254 % fractional-repetition branch was dead.
255 zerodist = APH(1, -GlobalConstants.Immediate);
256 zeroparam{1} = zerodist.params{1}.paramValue;
257 zeroparam{2} = zerodist.params{2}.paramValue;
258 aph_pattern = 3; % branch structure
259 [aphparam{1},aphparam{2}] = aph_simplify(aphparam{1},aphparam{2},zeroparam{1},zeroparam{2},fractionalPartRepetitions,1-fractionalPartRepetitions, aph_pattern);
260 ParamCell = [ParamCell,aphparam];
261 else
262 % Near-instant branch, taken by the fraction of the mix that
263 % performs no further repetition. It is built as an APH
264 % directly: APH.fitMeanAndSCV with a mean at or below FineTol
265 % returns an Exp, which carries a single parameter, so
266 % reading params{2} for the subgenerator threw and this whole
267 % fractional-repetition branch was dead.
268 zerodist = APH(1, -GlobalConstants.Immediate);
269 zeroparam{1} = zerodist.params{1}.paramValue;
270 zeroparam{2} = zerodist.params{2}.paramValue;
271 aph_pattern = 3; % branch structure
272 [aphparam{1},aphparam{2}] = aph_simplify(aphparam{1},aphparam{2},zeroparam{1},zeroparam{2},fractionalPartRepetitions,1-fractionalPartRepetitions, aph_pattern);
273 ParamCell = [ParamCell,aphparam];
274 end
275 if fitidx <= lqn.nidx
276 self.servtproc{fitidx} = Exp.fitMean(m1);
277 self.servt(fitidx) = m1;
278 else
279 self.callservtproc{fitidx-lqn.nidx} = Exp.fitMean(m1);
280 self.callservt(fitidx-lqn.nidx) = m1;
281 end
282 end
283 num = num+1;
284 end
285 if isempty(ParamCell)
286 self.servt(eidx) = 0;
287 else
288 [alpha,T] = aph_convseq(ParamCell); % convolution of sequential activities
289 entry_dist = APH(alpha,T);
290 self.entryproc{eidx-(lqn.nhosts+lqn.ntasks)} = entry_dist;
291 self.servt(eidx) = entry_dist.getMean;
292 self.servtproc{eidx} = Exp.fitMean(self.servt(eidx));
293 self.entrycdfrespt{eidx-(lqn.nhosts+lqn.ntasks)} = entry_dist.evalCDF;
294 end
295 end
296
297 % Propagate forwarding calls: add target entry's service time to source entry
298 for cidx = 1:lqn.ncalls
299 if lqn.calltype(cidx) == CallType.FWD
300 source_eidx = lqn.callpair(cidx, 1);
301 target_eidx = lqn.callpair(cidx, 2);
302 fwd_prob = lqn.callproc{cidx}.getMean();
303 self.servt(source_eidx) = self.servt(source_eidx) + fwd_prob * self.servt(target_eidx);
304 self.servtproc{source_eidx} = Exp.fitMean(self.servt(source_eidx));
305 end
306 end
307
308 % Compute entry-level residt using servtmatrix and activity residt
309 % callresidt uses WN which already includes visit multiplicity
310 entry_residt = self.servtmatrix*[self.residt;self.callresidt(:)];
311 entry_residt(1:lqn.eshift) = 0;
312 for eidx=(lqn.eshift+1):(lqn.eshift+lqn.nentries)
313 tidx = lqn.parent(eidx);
314 hidx = lqn.parent(tidx);
315 if ~self.ignore(tidx) && ~self.ignore(hidx)
316 hasSyncCallers = full(any(lqn.issynccaller(:, eidx)));
317 if hasSyncCallers
318 tidxclass = ensemble{self.idxhash(hidx)}.attribute.tasks(find(ensemble{self.idxhash(hidx)}.attribute.tasks(:,2) == tidx),1);
319 eidxclass = ensemble{self.idxhash(hidx)}.attribute.entries(find(ensemble{self.idxhash(hidx)}.attribute.entries(:,2) == eidx),1);
320 task_tput = sum(self.results{end,self.idxhash(hidx)}.TN(ensemble{self.idxhash(hidx)}.attribute.clientIdx,tidxclass));
321 entry_tput = sum(self.results{end,self.idxhash(hidx)}.TN(ensemble{self.idxhash(hidx)}.attribute.clientIdx,eidxclass));
322 self.residt(eidx) = entry_residt(eidx) * task_tput / max(GlobalConstants.Zero, entry_tput);
323 else
324 self.residt(eidx) = entry_residt(eidx);
325 end
326 end
327 end
328
329 % determine call response times processes
330 for r=1:size(self.call_classes_updmap,1)
331 cidx = self.call_classes_updmap(r,2);
332 eidx = lqn.callpair(cidx,2);
333 if self.call_classes_updmap(r,3) > 1
334 if it==1
335 self.callservt(cidx) = self.servt(eidx);
336 self.callservtproc{cidx} = Exp.fitMean(self.servt(eidx));
337 end
338 end
339 end
340end
341self.ensemble = ensemble;
342end
Definition Station.m:245