2function [runtime, tranSysState, tranSync] = runAnalyzer(self, options)
3% [RUNTIME, TRANSYSSTATE] = RUN()
6if nargin<2 %~exist('options','var')
7 options = self.getOptions;
9% Wall-clock time-budget launch marker (see options.timeout / lineTimeoutExceeded)
10options.timeout_tic = T0;
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);
18if strcmp(options.lang,'python')
19 line_debug(options, 'SSA: using lang=python, delegating to native line_solver');
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);
27self.runAnalyzerChecks(options);
28Solver.resetRandomGeneratorSeed(options.seed);
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);
35 line_printf('The solver will leverage %s.\n', strjoin(libs, ', '));
36 GlobalConstants.setLibraryAttributionShown(true);
40% Check if confidence intervals are requested
41[confintEnabled, confintLevel] = Solver.parseConfInt(options.confint);
43%options.lang = 'java';
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).
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);
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';
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');
61 options.method = 'serial';
64 [~, fjsn, fjclassmap] = ModelAdapter.fjtag(self.model);
66 line_debug(options, 'SSA: fork-join tag augmentation, %d classes (%d auxiliary), %d fork firings', sn.nclasses, sn.nclasses-Korig, length(sn.fjsync));
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.
77 options.method = 'serial';
80 case {
'default',
'serial',
'parallel'}
83 options.verbose = VerboseLevel.SILENT;
84 actualmethod =
'parallel';
86 jmodel = LINE2JLINE(self.model);
87 M = jmodel.getNumberOfStations;
88 R = jmodel.getNumberOfClasses;
90 jsolver = JLINE.SolverSSA(jmodel, options);
91 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(jsolver.getAvgTable);
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.
99 jres = jsolver.result;
100 if isempty(jres.tranSysState)
101 line_error(mfilename,'SSA transient trajectory unavailable from JLINE (serial analyzer required).');
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)));
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;
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);
135 if hitClass(k) > 0 && k <= length(hitRatioVec)
136 hitprob(k) = hitRatioVec(k);
137 missprob(k) = missRatioVec(k);
140 self.model.nodes{ind}.setResultHitProb(hitprob);
141 self.model.nodes{ind}.setResultMissProb(missprob);
144 if any(sn.nodetype == NodeType.Cache)
145 self.model.refreshStruct(true);
147 self.setAvgResults(QN,UN,RN,TN,AN,WN,CN,XN,runtime);
149 % Extract confidence intervals from Java solver results
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)
';
160 if isValidMatrix(result.UNCI)
161 UNCI = JLINE.from_jline_matrix(result.UNCI);
162 UNCI = reshape(UNCI', R, M)
';
166 if isValidMatrix(result.RNCI)
167 RNCI = JLINE.from_jline_matrix(result.RNCI);
168 RNCI = reshape(RNCI', R, M)
';
172 if isValidMatrix(result.TNCI)
173 TNCI = JLINE.from_jline_matrix(result.TNCI);
174 TNCI = reshape(TNCI', R, M)
';
178 if isValidMatrix(result.ANCI)
179 ANCI = JLINE.from_jline_matrix(result.ANCI);
180 ANCI = reshape(ANCI', R, M)
';
184 if isValidMatrix(result.WNCI)
185 WNCI = JLINE.from_jline_matrix(result.WNCI);
186 WNCI = reshape(WNCI', R, M)
';
191 self.setAvgResultsCI(QNCI, UNCI, RNCI, TNCI, ANCI, WNCI, [], []);
194 line_error(mfilename, ['the ',options.method',
' method is not available.']);
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);
200 for isf=1:sn.nstateful
201 ind = sn.statefulToNode(isf);
202 switch sn.nodetype(sn.statefulToNode(isf))
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);
209 self.model.refreshChains();
212 line_debug(options,
'SSA analysis complete: extracting results (nstations=%d, nclasses=%d)', sn.nstations, sn.nclasses);
214 T = getAvgTputHandles(self);
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
225 RN(ist,r) = QN(ist,r)/AN(ist,r);
231 AN = sn_get_arvr_from_tput(sn, TN, T);
233 if strcmp(options.method,
'default') && exist(
'actualmethod',
'var')
234 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,['default/' actualmethod]);
236 self.setAvgResults(QN,UN,RN,TN,AN,[],CN,XN,runtime,options.method);
238 self.result.space = sn.space;
240 % Store CI data if computed
241 if confintEnabled && ~isempty(QNCI)
242 self.setAvgResultsCI(QNCI, UNCI, RNCI, TNCI, ANCI, WNCI, [], []);
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);