1function [QN,UN,RN,TN,AN,WN] = getEnsembleAvg(self)
2% [QN,UN,RN,TN,AN,WN] = GETENSEMBLEAVG(SELF)
4% Check
if solver was properly constructed (may have returned early due to unsupported features)
5if isempty(self.ensemble)
6 QN = []; UN = []; RN = []; TN = []; AN = []; WN = [];
10% Show library attribution if verbose and not yet shown
11if self.options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
12 libs = SolverLN.getLibrariesUsed([], self.options);
14 line_printf('The solver will leverage %s.\n', strjoin(libs, ', '));
15 GlobalConstants.setLibraryAttributionShown(true);
19iterate(self); % run iterations
20QN = nan(self.lqn.nidx,1);
21UN = nan(self.lqn.nidx,1);
22RN = nan(self.lqn.nidx,1);
23TN = nan(self.lqn.nidx,1);
24PN = nan(self.lqn.nidx,1); % utilization will be first stored here
25SN = nan(self.lqn.nidx,1); % response time will be first stored here
26WN = nan(self.lqn.nidx,1); % residence time
27AN = nan(self.lqn.nidx,1); % not available yet
30 clientIdx = self.ensemble{e}.attribute.clientIdx;
31 serverIdx = self.ensemble{e}.attribute.serverIdx;
32 sourceIdx = self.ensemble{e}.attribute.sourceIdx;
33 % determine processor metrics
34 if self.ensemble{e}.stations{serverIdx}.attribute.ishost
35 hidx = self.ensemble{e}.stations{serverIdx}.attribute.idx;
38 for c=1:self.ensemble{e}.getNumberOfClasses
39 if self.ensemble{e}.classes{c}.completes
43 t = max(t, self.results{end,e}.TN(clientIdx,c));
46 t = max(t, self.results{end,e}.TN(sourceIdx,c));
48 TN(hidx) = TN(hidx) + max(t,self.results{end,e}.TN(serverIdx,c));
50 type = self.ensemble{e}.classes{c}.attribute(1);
52 case LayeredNetworkElement.ACTIVITY
53 aidx = self.ensemble{e}.classes{c}.attribute(2);
54 tidx = self.lqn.parent(aidx);
55 if isnan(PN(aidx)), PN(aidx)=0; end
56 if isnan(PN(tidx)), PN(tidx)=0; end
57 PN(aidx) = PN(aidx) + self.results{end,e}.UN(serverIdx,c);
58 PN(tidx) = PN(tidx) + self.results{end,e}.UN(serverIdx,c);
59 PN(hidx) = PN(hidx) + self.results{end,e}.UN(serverIdx,c);
62 TN(hidx) = NaN; % added
for consistency with LQNS
65 % determine remaining metrics
66 for c=1:self.ensemble{e}.getNumberOfClasses
67 type = self.ensemble{e}.classes{c}.attribute(1);
69 case LayeredNetworkElement.TASK
70 tidx = self.ensemble{e}.classes{c}.attribute(2);
71 if self.ensemble{e}.stations{serverIdx}.attribute.ishost
73 % store the result in the processor
75 TN(tidx) = self.results{end,e}.TN(clientIdx,c);
80 case LayeredNetworkElement.ENTRY
81 eidx = self.ensemble{e}.classes{c}.attribute(2);
82 tidx = self.lqn.parent(eidx);
83 % For phase-2 models, use residt (caller
's view with overtaking)
84 % Otherwise use servt (total service time = response time)
85 if self.hasPhase2 && self.servt_ph2(eidx) > GlobalConstants.FineTol
86 SN(eidx) = self.residt(eidx); % Phase-1 + overtaking correction
88 SN(eidx) = self.servt(eidx);
90 if self.ensemble{e}.stations{serverIdx}.attribute.ishost
92 % store the result in the processor model
93 if isnan(TN(eidx)), TN(eidx)=0; end
94 TN(eidx) = self.results{end,e}.TN(clientIdx,c);
99 case LayeredNetworkElement.CALL
100 cidx = self.ensemble{e}.classes{c}.attribute(2);
101 aidx = self.lqn.callpair(cidx,1);
102 % Only sync calls contribute to caller's response time
103 if self.lqn.calltype(cidx) == CallType.SYNC
104 SN(aidx) = SN(aidx) + self.results{end,e}.RN(serverIdx,c) * self.lqn.callproc{cidx}.getMean();
106 if isnan(QN(aidx)), QN(aidx)=0; end
107 QN(aidx) = QN(aidx) + self.results{end,e}.QN(serverIdx,c);
108 case LayeredNetworkElement.ACTIVITY
109 aidx = self.ensemble{e}.classes{c}.attribute(2);
110 tidx = self.lqn.parent(aidx);
111 if isnan(QN(tidx)), QN(tidx)=0; end
112 QN(tidx) = QN(tidx) + self.results{end,e}.QN(serverIdx,c);
113 if isnan(TN(aidx)), TN(aidx)=0; end
114 if isnan(QN(aidx)), QN(aidx)=0; end
116 % For forwarding targets: propagate activity metrics to entry and task
117 % Check
if task has its own
class (non-forwarding targets
do)
118 hasTaskClass = any(self.ensemble{e}.attribute.tasks(:,2) == tidx);
120 % Propagate activity throughput to task
for forwarding targets
121 if isnan(TN(tidx)), TN(tidx)=0; end
122 switch self.ensemble{e}.classes{c}.type
123 case JobClassType.CLOSED
124 TN(tidx) = TN(tidx) + self.results{end,e}.TN(serverIdx,c);
125 case JobClassType.OPEN
126 TN(tidx) = TN(tidx) + self.results{end,e}.TN(sourceIdx,c);
130 % Find the entry
this activity
is bound to
131 for eidx_check = self.lqn.entriesof{tidx}
132 if self.lqn.graph(eidx_check, aidx) > 0 % Activity
is bound to
this entry
133 if isnan(TN(eidx_check)), TN(eidx_check)=0; end
134 if isnan(QN(eidx_check)), QN(eidx_check)=0; end
135 if isnan(SN(eidx_check)), SN(eidx_check)=0; end
136 % Add activity metrics to entry (
for entries without their own
classes)
138 switch self.ensemble{e}.classes{c}.type
139 case JobClassType.CLOSED
140 actTput = self.results{end,e}.TN(serverIdx,c);
141 case JobClassType.OPEN
142 actTput = self.results{end,e}.TN(sourceIdx,c);
144 % Only add
if entry doesn
't have its own class (forwarding target case)
145 hasEntryClass = any(self.ensemble{e}.attribute.entries(:,2) == eidx_check);
147 TN(eidx_check) = TN(eidx_check) + actTput;
148 QN(eidx_check) = QN(eidx_check) + self.results{end,e}.QN(serverIdx,c);
149 SN(eidx_check) = SN(eidx_check) + self.results{end,e}.RN(serverIdx,c);
154 switch self.ensemble{e}.classes{c}.type
155 case JobClassType.CLOSED
156 TN(aidx) = TN(aidx) + self.results{end,e}.TN(serverIdx,c);
157 case JobClassType.OPEN
158 TN(aidx) = TN(aidx) + self.results{end,e}.TN(sourceIdx,c);
160 % SN(aidx) = self.servt(aidx);
161 if isnan(SN(aidx)), SN(aidx)=0; end
162 SN(aidx) = SN(aidx) + self.results{end,e}.RN(serverIdx,c);
163 if isnan(RN(aidx)), RN(aidx)=0; end
164 RN(aidx) = RN(aidx) + self.results{end,e}.RN(serverIdx,c);
165 if isnan(WN(aidx)), WN(aidx)=0; end
166 if isnan(WN(tidx)), WN(tidx)=0; end
167 WN(aidx) = WN(aidx) + self.results{end,e}.WN(serverIdx,c);
168 WN(tidx) = WN(tidx) + self.results{end,e}.WN(serverIdx,c);
169 if isnan(QN(aidx)), QN(aidx)=0; end
170 QN(aidx) = QN(aidx) + self.results{end,e}.QN(serverIdx,c);
175for e=1:self.lqn.nentries
176 eidx = self.lqn.eshift + e;
177 tidx = self.lqn.parent(eidx);
178 if isnan(UN(tidx)), UN(tidx)=0; end
180 % Phase-2 support: utilization includes both phases
181 if self.hasPhase2 && self.servt_ph2(eidx) > GlobalConstants.FineTol
182 % Phase-1 utilization
183 self.util_ph1(eidx) = TN(eidx) * self.servt_ph1(eidx);
184 % Phase-2 utilization
185 self.util_ph2(eidx) = TN(eidx) * self.servt_ph2(eidx);
186 % Total utilization = both phases (server is busy during both)
187 UN(eidx) = self.util_ph1(eidx) + self.util_ph2(eidx);
189 % Standard calculation for entries without phase-2
190 UN(eidx) = TN(eidx)*SN(eidx);
193 for aidx=self.lqn.actsof{tidx}
194 UN(aidx) = TN(aidx)*SN(aidx);
196 UN(tidx) = UN(tidx) + UN(eidx);
199for idx=find(self.ignore)