LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
runAnalyzer.m
1
2function [runtime, tranSysState, tranSync] = runAnalyzer(self, options)
3% [RUNTIME, TRANSYSSTATE] = RUN()
4
5T0=tic;
6if nargin<2 %~exist('options','var')
7 options = self.getOptions;
8end
9% Wall-clock time-budget launch marker (see options.timeout / lineTimeoutExceeded)
10options.timeout_tic = T0;
11
12% options.events (DES event budget) overrides options.samples when set;
13% samples remains accepted as a deprecated alias for the event budget.
14if isfield(options,'events') && ~isempty(options.events) && isfinite(options.events) && options.events > 0
15 options.samples = round(options.events);
16end
17
18if strcmp(options.lang,'python')
19 line_debug(options, 'SSA: using lang=python, delegating to native line_solver');
20 tranSysState = [];
21 tranSync = [];
22 [QN,UN,RN,TN,AN,WN,runtime] = PYLINE.getAvg(self.name, self.model, options);
23 self.setAvgResults(QN,UN,RN,TN,AN,WN,[],[],runtime,options.method,NaN);
24 return
25end
26
27self.runAnalyzerChecks(options);
28Solver.resetRandomGeneratorSeed(options.seed);
29
30% Show library attribution if verbose and not yet shown
31if options.verbose ~= VerboseLevel.SILENT && ~GlobalConstants.isLibraryAttributionShown()
32 sn_temp = self.getStruct();
33 libs = SolverSSA.getLibrariesUsed(sn_temp, options);
34 if ~isempty(libs)
35 line_printf('The solver will leverage %s.\n', strjoin(libs, ', '));
36 GlobalConstants.setLibraryAttributionShown(true);
37 end
38end
39
40% Check if confidence intervals are requested
41[confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
42
43%options.lang = 'java';
44
45sn = getStruct(self);
46% Finite Capacity Region: enforced in solver_ssa.m by blocking arrivals that
47% would exceed a region's aggregate job/memory/linear cap (block-before-entry,
48% matching the SolverCTMC state-space filter).
49
50% Native fork-join support: simulate the tag-augmented copy and fold the
51% auxiliary sibling classes back into the original classes at the end
52isFJ = any(sn.nodetype == NodeType.Fork) || any(sn.nodetype == NodeType.Join);
53if isFJ
54 if strcmp(options.lang,'java')
55 line_warning(mfilename,'Fork-join models are not supported by the JLINE SSA backend, switching to lang=matlab.\n');
56 options.lang = 'matlab';
57 end
58 if strcmp(options.method,'parallel')
59 line_warning(mfilename,'The parallel method does not support fork-join models, switching to the serial method.\n');
60 end
61 options.method = 'serial';
62 sn_orig = sn;
63 Korig = sn.nclasses;
64 [~, fjsn, fjclassmap] = ModelAdapter.fjtag(self.model);
65 sn = fjsn;
66 line_debug(options, 'SSA: fork-join tag augmentation, %d classes (%d auxiliary), %d fork firings', sn.nclasses, sn.nclasses-Korig, length(sn.fjsync));
67end
68
69switch options.lang
70 case 'java'
71 line_debug(options, 'SSA: using lang=java, delegating to JLINE');
72 % When a transient trajectory is requested (nargout>1, e.g. by
73 % sample*/getProb*/sampleSys*), force the serial analyzer: it records the
74 % full state trajectory, which is marshalled back from the JLINE result
75 % below to reconstruct tranSysState/tranSync.
76 if nargout > 1
77 options.method = 'serial';
78 end
79 switch options.method
80 case {'default','serial','parallel'}
81 switch options.method
82 case 'default'
83 options.verbose = VerboseLevel.SILENT;
84 actualmethod = 'parallel';
85 end
86 jmodel = LINE2JLINE(self.model);
87 M = jmodel.getNumberOfStations;
88 R = jmodel.getNumberOfClasses;
89 tic;
90 jsolver = JLINE.SolverSSA(jmodel, options);
91 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
92
93 % Reconstruct the transient state trajectory from the JLINE serial
94 % result so sample*/getProb* work under lang='java'. The JLINE
95 % tranSysState map matches the MATLAB contract: key 0 = cumulative
96 % timestamps, key isf = raw state of stateful node isf (1..nstateful);
97 % tranSync holds 1-based sync-event indices.
98 if nargout > 1
99 jres = jsolver.result;
100 if isempty(jres.tranSysState)
101 line_error(mfilename,'SSA transient trajectory unavailable from JLINE (serial analyzer required).');
102 end
103 tranSysState = cell(1, sn.nstateful + 1);
104 tranSysState{1} = JLINE.from_jline_matrix(jres.tranSysState.get(java.lang.Integer(0)));
105 for isf = 1:sn.nstateful
106 tranSysState{1+isf} = JLINE.from_jline_matrix(jres.tranSysState.get(java.lang.Integer(isf)));
107 end
108 tranSync = JLINE.from_jline_matrix(jres.tranSync);
109 tranSync = tranSync(:)';
110 % The trajectory is all the sample*/getProb* callers need; skip
111 % the steady-state marshalling below (its reshape assumes the
112 % parallel avg-table layout, which the serial run does not use).
113 runtime = jsolver.result.runtime;
114 return;
115 end
116 CN = JLINE.from_jline_matrix(jsolver.getAvgSysRespT());
117 XN = JLINE.from_jline_matrix(jsolver.getAvgSysTput());
118 runtime = jsolver.result.runtime;
119 QN = reshape(QN',R,M)';
120 UN = reshape(UN',R,M)';
121 RN = reshape(RN',R,M)';
122 TN = reshape(TN',R,M)';
123 WN = reshape(WN',R,M)';
124 AN = reshape(AN',R,M)';
125 % Extract cache hit/miss probabilities from Java model
126 for ind = 1:sn.nnodes
127 if sn.nodetype(ind) == NodeType.Cache
128 hitRatioVec = JLINE.from_jline_matrix(jmodel.getNodeByIndex(ind-1).getHitRatio());
129 missRatioVec = JLINE.from_jline_matrix(jmodel.getNodeByIndex(ind-1).getMissRatio());
130 hitClass = self.model.nodes{ind}.getHitClass;
131 nk = length(hitClass);
132 hitprob = zeros(1, nk);
133 missprob = zeros(1, nk);
134 for k = 1:nk
135 if hitClass(k) > 0 && k <= length(hitRatioVec)
136 hitprob(k) = hitRatioVec(k);
137 missprob(k) = missRatioVec(k);
138 end
139 end
140 self.model.nodes{ind}.setResultHitProb(hitprob);
141 self.model.nodes{ind}.setResultMissProb(missprob);
142 end
143 end
144 if any(sn.nodetype == NodeType.Cache)
145 self.model.refreshStruct(true);
146 end
147 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime);
148
149 % Extract confidence intervals from Java solver results
150 if confintEnabled
151 result = jsolver.result;
152 % Helper to check for non-null Java objects
153 isValidMatrix = @(x) ~isempty(x) && isa(x, 'jline.util.matrix.Matrix');
154 if isValidMatrix(result.QNCI)
155 QNCI = JLINE.from_jline_matrix(result.QNCI);
156 QNCI = reshape(QNCI', R, M)';
157 else
158 QNCI = [];
159 end
160 if isValidMatrix(result.UNCI)
161 UNCI = JLINE.from_jline_matrix(result.UNCI);
162 UNCI = reshape(UNCI', R, M)';
163 else
164 UNCI = [];
165 end
166 if isValidMatrix(result.RNCI)
167 RNCI = JLINE.from_jline_matrix(result.RNCI);
168 RNCI = reshape(RNCI', R, M)';
169 else
170 RNCI = [];
171 end
172 if isValidMatrix(result.TNCI)
173 TNCI = JLINE.from_jline_matrix(result.TNCI);
174 TNCI = reshape(TNCI', R, M)';
175 else
176 TNCI = [];
177 end
178 if isValidMatrix(result.ANCI)
179 ANCI = JLINE.from_jline_matrix(result.ANCI);
180 ANCI = reshape(ANCI', R, M)';
181 else
182 ANCI = [];
183 end
184 if isValidMatrix(result.WNCI)
185 WNCI = JLINE.from_jline_matrix(result.WNCI);
186 WNCI = reshape(WNCI', R, M)';
187 else
188 WNCI = [];
189 end
190 % Store CI results
191 self.setAvgResultsCI(QNCI, UNCI, RNCI, TNCI, ANCI, WNCI, [], []);
192 end
193 otherwise
194 line_error(mfilename, ['the ',options.method',' method is not available.']);
195 end
196 case 'matlab'
197 line_debug(options, 'SSA: using lang=matlab');
198 [QN,UN,RN,TN,CN,XN,~,actualmethod,tranSysState, tranSync, sn, QNCI, UNCI, RNCI, TNCI, ANCI, WNCI] = solver_ssa_analyzer(sn, options);
199
200 for isf=1:sn.nstateful
201 ind = sn.statefulToNode(isf);
202 switch sn.nodetype(sn.statefulToNode(isf))
203 case NodeType.Cache
204 self.model.nodes{sn.statefulToNode(isf)}.setResultHitProb(sn.nodeparam{ind}.actualhitprob);
205 self.model.nodes{sn.statefulToNode(isf)}.setResultMissProb(sn.nodeparam{ind}.actualmissprob);
206 if isfield(sn.nodeparam{ind}, 'actualresidt')
207 self.model.nodes{sn.statefulToNode(isf)}.setResultResidT(sn.nodeparam{ind}.actualresidt);
208 end
209 self.model.refreshChains();
210 end
211 end
212 line_debug(options, 'SSA analysis complete: extracting results (nstations=%d, nclasses=%d)', sn.nstations, sn.nclasses);
213 runtime = toc(T0);
214 T = getAvgTputHandles(self);
215 if isFJ
216 [QN,UN,RN,TN,CN,XN] = sn_fj_foldback(QN,UN,RN,TN,CN,XN,fjclassmap,Korig);
217 self.result.fjclassmap = fjclassmap;
218 AN = sn_get_arvr_from_tput(sn_orig, TN, T);
219 % Join stations report the per-sibling waiting time (JMT
220 % convention): QLen over the sibling arrival rate
221 for ist=1:sn_orig.nstations
222 if sn_orig.nodetype(sn_orig.stationToNode(ist)) == NodeType.Join
223 for r=1:Korig
224 if AN(ist,r) > 0
225 RN(ist,r) = QN(ist,r)/AN(ist,r);
226 end
227 end
228 end
229 end
230 else
231 AN = sn_get_arvr_from_tput(sn, TN, T);
232 end
233 if strcmp(options.method,'default') && exist('actualmethod','var')
234 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,['default/' actualmethod]);
235 else
236 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method);
237 end
238 self.result.space = sn.space;
239
240 % Store CI data if computed
241 if confintEnabled && ~isempty(QNCI)
242 self.setAvgResultsCI(QNCI, UNCI, RNCI, TNCI, ANCI, WNCI, [], []);
243 end
244 if lineTimeoutExceeded(options)
245 self.result.Avg.timedOut = true;
246 line_warning(mfilename,'Solver stopped after the wall-clock time budget (options.timeout=%gs) was exceeded; returning the interim solution.\n', options.timeout);
247 end
248end
249end
Definition Station.m:287
Definition fjtag.m:157
Definition Station.m:245