LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getPerctRespT.m
1function [PercRT, PercTable] = getPerctRespT(self, percentiles, jobclass, method)
2% [PERCRT, PERCTABLE] = GETPERCTRESPT(SELF, PERCENTILES, JOBCLASS)
3% Retrieve response time percentile results from FJ_codes analysis or CDF
4%
5% Parameters:
6% self - SolverMAM instance
7% percentiles - Array of percentile values to compute (e.g., [0.90, 0.95, 0.99] or [90, 95, 99])
8% jobclass - (optional) specific job class to retrieve percentiles for
9%
10% Returns:
11% PercRT - Struct array with fields for each class:
12% .class - class name
13% .percentiles - percentile levels (e.g., [90, 95, 99])
14% .values - percentile values (response times)
15% .K - number of parallel queues in Fork-Join
16% PercTable - Formatted table for display with columns:
17% JobClass, Percentile, ResponseTime
18%
19% Reference:
20% Z. Qiu, J.F. Pérez, and P. Harrison, "Beyond the Mean in Fork-Join Queues:
21% Efficient Approximation for Response-Time Tails", IFIP Performance 2015.
22% Copyright 2015 Imperial College London
23%
24% Copyright (c) 2012-2026, Imperial College London
25% All rights reserved.
26
27% The forktail method is topology-driven, not solver-specific: hand it back
28% to the base implementation rather than duplicating it here.
29if nargin >= 4 && ~isempty(method) && ~strcmpi(method, 'default')
30 if nargin < 3
31 jobclass = [];
32 end
33 [PercRT, PercTable] = getPerctRespT@NetworkSolver(self, percentiles, jobclass, method);
34 return
35end
36
37% Normalize percentiles to [0, 1] range
38if any(percentiles > 1)
39 percentiles = percentiles / 100;
40end
41
42sn = self.getStruct();
43
44% Percentiles are a solve by-product, require a prior solve; see _kb/06-solver-catalog.md for rationale
45if ~self.hasAvgResults()
46 self.getAvg();
47end
48
49% Check if FJ_codes percentile results are available
50if isfield(self.result, 'Percentile') && ~isempty(self.result.Percentile)
51 % Use FJ_codes results (pre-computed)
52 percResults = self.result.Percentile;
53 useFJCodes = true;
54else
55 % Fall back to CDF-based percentile extraction
56 useFJCodes = false;
57end
58
59% Determine which classes to return
60if nargin < 3 || isempty(jobclass)
61 % Return all classes
62 classes = 1:sn.nclasses;
63else
64 % Find class index
65 if ischar(jobclass) || isstring(jobclass)
66 % Class name provided
67 classIdx = find(strcmp(sn.classnames, jobclass));
68 if isempty(classIdx)
69 line_error(mfilename, 'Job class "%s" not found in model.', jobclass);
70 end
71 classes = classIdx;
72 else
73 % Class index provided
74 classes = jobclass;
75 end
76end
77
78% Build PercRT struct array
79PercRT = struct([]);
80
81if useFJCodes
82 % Use pre-computed FJ_codes results
83 for idx = 1:length(classes)
84 r = classes(idx);
85
86 if r > length(percResults.RT) || isempty(percResults.RT{r})
87 line_warning(mfilename, 'No percentile results for class %d.', r);
88 continue;
89 end
90
91 % Extract percentile data for this class
92 classPercResults = percResults.RT{r};
93
94 % Interpolate to get requested percentiles (if different from stored)
95 storedPercentiles = classPercResults.percentiles; % In percentage form from mainFJ
96 storedValues = classPercResults.RTp;
97
98 % Convert requested percentiles to percentage form for interpolation
99 % (percentiles are already normalized to [0,1] on line 28)
100 requestedPercentiles = percentiles * 100;
101
102 % Interpolate to requested percentiles
103 interpValues = interp1(storedPercentiles, storedValues, requestedPercentiles, 'linear', 'extrap');
104
105 PercRT(idx).class = sn.classnames{r};
106 PercRT(idx).percentiles = percentiles; % Keep in fractional form [0,1]
107 PercRT(idx).values = interpValues;
108 PercRT(idx).K = percResults.K;
109 PercRT(idx).method = percResults.method;
110 end
111else
112 % Extract percentiles from CDF
113 try
114 RD = self.getCdfRespT();
115 catch
116 line_error(mfilename, 'Unable to compute percentiles. getCdfRespT not available for this model.');
117 end
118
119 for idx = 1:length(classes)
120 r = classes(idx);
121
122 % Find CDF data for this class
123 % RD is a cell array with format RD{station, class} = [F, X]
124 % where F are CDF probabilities and X are time values
125 % Search through stations to find non-empty CDF data
126 cdfData = [];
127 for i = 1:size(RD, 1)
128 if r <= size(RD, 2) && ~isempty(RD{i, r})
129 cdfData = RD{i, r};
130 break;
131 end
132 end
133
134 if ~isempty(cdfData)
135 % CDF format is [F, X] where F = probabilities, X = times
136 probs = cdfData(:, 1);
137 times = cdfData(:, 2);
138
139 % Remove duplicate probability values for interpolation
140 [probs_unique, idx_unique] = unique(probs, 'last');
141 times_unique = times(idx_unique);
142
143 % Interpolate to find times at requested percentiles
144 percValues = interp1(probs_unique, times_unique, percentiles, 'linear', 'extrap');
145
146 PercRT(idx).class = sn.classnames{r};
147 PercRT(idx).percentiles = percentiles; % Keep in fractional form [0,1]
148 PercRT(idx).values = percValues;
149 PercRT(idx).method = 'cdf';
150 end
151 end
152end
153
154% Build PercTable for display
155if nargout > 1
156 JobClass = {};
157 Percentile = [];
158 ResponseTime = [];
159
160 for idx = 1:length(PercRT)
161 nPercentiles = length(PercRT(idx).percentiles);
162 for p = 1:nPercentiles
163 JobClass{end+1,1} = PercRT(idx).class;
164 Percentile(end+1,1) = PercRT(idx).percentiles(p);
165 ResponseTime(end+1,1) = PercRT(idx).values(p);
166 end
167 end
168
169 JobClass = label(JobClass);
170 PercTable = Table(JobClass, Percentile, ResponseTime);
171end
172
173end