LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fj_tail_forktail.m
1%{ @file fj_tail_forktail.m
2 % @brief ForkTail black-box tail-latency approximation for fork-join requests
3 %
4 % @author LINE Development Team
5%}
6
7%{
8 % @brief ForkTail black-box tail-latency approximation for fork-join requests
9 %
10 % @details
11 % Approximates the p-th percentile of the response time of a request that
12 % forks into K parallel tasks and joins on the last of them, from the mean
13 % and variance of the per-branch task response times alone. Each branch is
14 % treated as a black box: its task response time is fitted by a generalized
15 % exponential law
16 %
17 % F_T(x) = (1 - exp(-x/beta))^alpha
18 %
19 % whose two parameters are matched on the branch mean and variance,
20 %
21 % E[T] = beta*(psi(alpha+1) - psi(1)), V[T] = beta^2*(psi'(1) - psi'(alpha+1)),
22 %
23 % and the request response time is the maximum over the branches, taken as
24 % the product of the branch CDFs (exact only for independent branches):
25 %
26 % F_X(x) = prod_i (1 - exp(-x/beta_i))^alpha_i, x_p = F_X^{-1}(p).
27 %
28 % In the homogeneous case this inverts in closed form,
29 % x_p = -beta*log(1 - p^(1/(K*alpha))).
30 %
31 % When the fanout itself is random, i.e. a request spawns K_i tasks with
32 % probability P_i (a service whose requests touch different numbers of
33 % shards), the request law is the mixture
34 %
35 % F_X(x) = sum_i P_i * (1 - exp(-x/beta))^(K_i*alpha),
36 %
37 % which is inverted numerically.
38 %
39 % The approximation rests on the central limit theorem for G/G/m queues in
40 % heavy traffic, so it is a HIGH-LOAD result: the reference reports errors
41 % within 20% and 15% at 80% and 90% utilization respectively, and makes no
42 % claim at low load, where the tail is dominated by the service law rather
43 % than by queueing and the branch dependence is strongest. Use
44 % fj_is_homogeneous plus the FJ_codes route when the model is in the
45 % homogeneous MAP/PH/1 class, which is more accurate there; ForkTail covers
46 % the heterogeneous branches and mixed service laws that route rejects.
47 %
48 % @par Syntax:
49 % @code
50 % [xp, alpha, beta] = fj_tail_forktail(ET, VT, K, p)
51 % @endcode
52 %
53 % @par Parameters:
54 % <table>
55 % <tr><th>Name<th>Description
56 % <tr><td>ET<td>Mean task response time: a scalar (homogeneous branches) or a vector with one entry per branch
57 % <tr><td>VT<td>Variance of the task response time, same shape as ET
58 % <tr><td>K<td>Number of branches, or a vector of distinct fanouts when the fanout is random; ignored when ET is a vector (default 1)
59 % <tr><td>p<td>Percentile, either a fraction in (0,1) or a percentage in (0,100) (default 99)
60 % <tr><td>P<td>Probabilities of the fanouts in K, required when K is a vector of more than one entry
61 % </table>
62 %
63 % @par Returns:
64 % <table>
65 % <tr><th>Name<th>Description
66 % <tr><td>xp<td>Predicted p-th percentile of the request response time
67 % <tr><td>alpha<td>Fitted shape parameter(s) of the generalized exponential
68 % <tr><td>beta<td>Fitted scale parameter(s)
69 % </table>
70 %
71 % @par References:
72 % M. Nguyen, S. Alesawi, N. Li, H. Che, H. Jiang, "ForkTail: A Black-Box
73 % Fork-Join Tail Latency Prediction Model for User-Facing Datacenter
74 % Workloads", ACM HPDC 2018, pp. 206-217.
75%}
76function [xp, alpha, beta] = fj_tail_forktail(ET, VT, K, p, P)
77
78if nargin < 3 || isempty(K)
79 K = 1;
80end
81if nargin < 4 || isempty(p)
82 p = 99;
83end
84if nargin < 5
85 P = [];
86end
87K = K(:)';
88P = P(:)';
89if p > 1
90 p = p / 100;
91end
92if p <= 0 || p >= 1
93 line_error(mfilename, 'The percentile must lie strictly between 0 and 1 (or 0 and 100).');
94end
95
96ET = ET(:)';
97VT = VT(:)';
98if numel(VT) ~= numel(ET)
99 line_error(mfilename, 'ET and VT must have the same number of entries.');
100end
101if any(ET <= 0) || any(VT <= 0)
102 line_error(mfilename, 'The task response time mean and variance must be positive.');
103end
104
105nbranch = numel(ET);
106alpha = zeros(1, nbranch);
107beta = zeros(1, nbranch);
108for i = 1:nbranch
109 [alpha(i), beta(i)] = ge_fit(ET(i), VT(i));
110end
111
112if nbranch == 1 && numel(K) > 1
113 % Random fanout: mix the homogeneous request laws over the fanout
114 % distribution and invert numerically
115 if numel(P) ~= numel(K)
116 line_error(mfilename, 'A vector of fanouts K needs a probability vector P of the same length.');
117 end
118 if abs(sum(P) - 1) > GlobalConstants.CoarseTol || any(P < 0)
119 line_error(mfilename, 'The fanout probabilities P must be non-negative and sum to one.');
120 end
121 mixcdf = @(x) sum(P .* (1 - exp(-x/beta)).^(K*alpha));
122 xlo = -beta * log(1 - p^(1/(min(K)*alpha)));
123 xhi = -beta * log(1 - p^(1/(max(K)*alpha)));
124 xp = fzero(@(x) mixcdf(x) - p, [xlo, xhi]);
125 return
126end
127
128if nbranch == 1
129 % Homogeneous: every branch shares (alpha,beta), so the product of K
130 % identical CDFs raises the shape to K*alpha and inverts in closed form
131 xp = -beta * log(1 - p^(1/(K*alpha)));
132 return
133end
134
135% Inhomogeneous: solve prod_i (1-exp(-x/beta_i))^alpha_i = p. F_X is bounded
136% above by the CDF of any single branch, so the request percentile is at
137% least the largest branch percentile; expand from there until the root is
138% bracketed.
139logp = log(p);
140residual = @(x) sum(alpha .* log1p(-exp(-x ./ beta))) - logp;
141xlo = max(-beta .* log(1 - p.^(1 ./ alpha)));
142xhi = xlo;
143while residual(xhi) < 0
144 xhi = 2 * xhi;
145 if ~isfinite(xhi)
146 line_error(mfilename, 'Could not bracket the ForkTail percentile.');
147 end
148end
149if residual(xlo) > 0
150 xlo = xlo / 2;
151 while residual(xlo) > 0 && xlo > eps
152 xlo = xlo / 2;
153 end
154end
155xp = fzero(residual, [xlo, xhi]);
156end
157
158function [alpha, beta] = ge_fit(ET, VT)
159% [ALPHA, BETA] = GE_FIT(ET, VT)
160% Match a generalized exponential law on a mean and a variance. The squared
161% coefficient of variation depends on the shape alone and decreases
162% monotonically in it, so the shape is recovered by a scalar root-find on a
163% logarithmic scale and the scale then follows in closed form. SCV = 1 is the
164% exponential case alpha = 1, kept exact.
165scv = VT / ET^2;
166if abs(scv - 1) < GlobalConstants.FineTol
167 alpha = 1;
168else
169 scvOf = @(a) (psi(1,1) - psi(1,a+1)) / (psi(0,a+1) - psi(0,1))^2;
170 residual = @(la) scvOf(exp(la)) - scv;
171 lo = -30; hi = 30;
172 while residual(lo) < 0 && lo > -700
173 lo = lo - 30; % smaller shape -> larger SCV
174 end
175 while residual(hi) > 0 && hi < 700
176 hi = hi + 30; % larger shape -> smaller SCV
177 end
178 alpha = exp(fzero(residual, [lo, hi]));
179end
180beta = ET / (psi(0,alpha+1) - psi(0,1));
181end