LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
qsys_mg1_srpt.m
1function [W, rho_total] = qsys_mg1_srpt(lambda, mu, cs)
2% QSYS_MG1_SRPT Compute mean response time for M/G/1/SRPT queue
3%
4% [W, RHO] = QSYS_MG1_SRPT(LAMBDA, MU, CS) computes the mean response time
5% for each job class in an M/G/1 queue with Shortest Remaining Processing
6% Time (SRPT) scheduling.
7%
8% SRPT is a size-based policy: it always serves the job with the smallest
9% remaining processing time, preempting whenever a shorter job arrives.
10% The class-conditional response time is obtained from the Schrage-Miller
11% formula (Eqs (1)-(3) of Bansal-Harchol-Balter, SIGMETRICS 2003, citing
12% Schrage-Miller 1966). For a job of size x:
13%
14% E[T(x)] = E[W(x)] + E[R(x)]
15% E[W(x)] = lambda*(m2(x) + x^2*(1-F(x))) / (2*(1-rho(x))^2) (waiting)
16% E[R(x)] = integral_0^x dt/(1-rho(t)) (residence)
17%
18% where f(t) is the overall (mixture) job-size density, F(t) its CDF,
19% rho(x) = lambda * integral_0^x t*f(t) dt (load from jobs of size <= x)
20% m2(x) = integral_0^x t^2 f(t) dt
21%
22% The per-class mean is E[T_r] = integral_0^inf E[T(x)] f_r(x) dx, with
23% f_r the class-r size density and f = sum_r (lambda_r/lambda) f_r the
24% mixture. Because E[T(x)] depends only on the job size (SRPT is size-based,
25% not class-based), this integral is exact. The integrals are evaluated by
26% cumulative trapezoidal quadrature on a common grid.
27%
28% Each class is represented by a job-size distribution matched to its
29% (mean=1/mu_r, scv=cs_r^2): exponential when cs_r=1, a two-phase balanced
30% hyperexponential when cs_r>1, and a Tijms mixture of Erlang-(k-1)/Erlang-k
31% when cs_r<1. For the fully exponential case this reproduces the exact
32% M/M/1/SRPT hyperexponential-mixture result.
33%
34% PARAMETERS:
35% lambda : Vector of arrival rates per class
36% mu : Vector of service rates per class
37% cs : Vector of coefficients of variation per class (cs=1 for exponential)
38%
39% RETURNS:
40% W : Vector of mean response times per class (original class order)
41% rho : System load measure Q/(1+Q) with Q = sum(lambda.*W)
42%
43% REFERENCES:
44% - L. E. Schrage and L. W. Miller, "The queue M/G/1 with the shortest
45% remaining processing time discipline", Operations Research, 14:670-684, 1966.
46% - N. Bansal and M. Harchol-Balter, "Analysis of SRPT scheduling:
47% investigating unfairness", SIGMETRICS 2001, Sec. 4, Eqs (1)-(3).
48%
49% Copyright (c) 2012-2026, Imperial College London
50% All rights reserved.
51
52% Ensure inputs are column vectors
53lambda = reshape(lambda, [], 1);
54mu = reshape(mu, [], 1);
55cs = reshape(cs, [], 1);
56
57% Validate input lengths
58if ~isequal(length(lambda), length(mu), length(cs))
59 error('qsys_mg1_srpt:InvalidInput', ...
60 'lambda, mu, and cs must have the same length');
61end
62
63% Validate positive values
64if any(lambda <= 0) || any(mu <= 0) || any(cs < 0)
65 error('qsys_mg1_srpt:InvalidInput', ...
66 'lambda and mu must be positive, cs must be non-negative');
67end
68
69K = length(lambda);
70lambda_total = sum(lambda);
71p = lambda / lambda_total; % size-mixture probabilities
72
73% Overall utilization and stability check
74rho_util = sum(lambda ./ mu);
75if rho_util >= 1
76 error('qsys_mg1_srpt:UnstableSystem', ...
77 sprintf('System is unstable: utilization rho = %g >= 1', rho_util));
78end
79
80% Build per-class job-size representations and collect phase-rate bounds
81fits = cell(K, 1);
82rate_min = Inf;
83rate_max = 0;
84for r = 1:K
85 fits{r} = srpt_fit(mu(r), cs(r));
86 rate_min = min(rate_min, fits{r}.rate_min);
87 rate_max = max(rate_max, fits{r}.rate_max);
88end
89
90% Integration grid: span 40 e-foldings of the slowest phase, resolve the
91% fastest phase with at least 200 points per rate ratio.
92xmax = 40.0 / rate_min;
93N = min(2000000, max(20000, ceil(200.0 * rate_max / rate_min)));
94x = linspace(0.0, xmax, N + 1)';
95dx = x(2) - x(1);
96
97% Mixture density f(x) and tail Fbar(x) = 1 - F(x)
98fmix = zeros(N + 1, 1);
99Fbar = zeros(N + 1, 1);
100for r = 1:K
101 fmix = fmix + p(r) * srpt_pdf(fits{r}, x);
102 Fbar = Fbar + p(r) * srpt_tail(fits{r}, x);
103end
104
105% Truncated moments rho(x) and m2(x) by cumulative trapezoidal integration
106rho_x = lambda_total * cumtrapz(x, x .* fmix);
107m2_x = cumtrapz(x, x.^2 .* fmix);
108
109% Guard the (1-rho(x)) factors: rho(x) -> rho_util < 1 as x -> inf
110denom = max(1.0 - rho_x, 1e-12);
111
112% Schrage-Miller waiting and residence terms, and E[T(x)]
113Wait = lambda_total * (m2_x + x.^2 .* Fbar) ./ (2.0 * denom.^2);
114Res = cumtrapz(x, 1.0 ./ denom);
115ET = Wait + Res;
116
117% Per-class mean response time: integrate E[T(x)] against class density
118W = zeros(K, 1);
119for r = 1:K
120 W(r) = trapz(x, ET .* srpt_pdf(fits{r}, x));
121end
122
123% Load measure returned as rhohat = Q/(1+Q) (qsys convention)
124Q = sum(lambda .* W);
125rho_total = Q / (1 + Q);
126
127end
128
129
130function fit = srpt_fit(mu, cs)
131% Match a job-size distribution to mean 1/mu and scv cs^2.
132% Returns a struct with a type tag, parameters, and phase-rate bounds.
133mean_x = 1.0 / mu;
134c2 = cs^2;
135if abs(c2 - 1.0) < 1e-9
136 % Exponential
137 fit.type = 'exp';
138 fit.rate = mu;
139 fit.rate_min = mu;
140 fit.rate_max = mu;
141elseif c2 > 1.0
142 % Two-phase balanced-means hyperexponential (matches mean and scv)
143 pr = 0.5 * (1.0 + sqrt((c2 - 1.0) / (c2 + 1.0)));
144 r1 = 2.0 * pr * mu;
145 r2 = 2.0 * (1.0 - pr) * mu;
146 fit.type = 'h2';
147 fit.p = pr;
148 fit.r1 = r1;
149 fit.r2 = r2;
150 fit.rate_min = min(r1, r2);
151 fit.rate_max = max(r1, r2);
152else
153 % Tijms mixture of Erlang-(k-1) and Erlang-k with common rate
154 k = ceil(1.0 / c2);
155 pr = (1.0 / (1.0 + c2)) * (k * c2 - sqrt(k * (1.0 + c2) - k * k * c2));
156 rate = (k - pr) / mean_x;
157 fit.type = 'erlmix';
158 fit.k = k;
159 fit.p = pr;
160 fit.rate = rate;
161 fit.rate_min = rate;
162 fit.rate_max = rate;
163end
164end
165
166
167function y = srpt_pdf(fit, x)
168% Job-size probability density evaluated on the grid x.
169switch fit.type
170 case 'exp'
171 y = fit.rate * exp(-fit.rate * x);
172 case 'h2'
173 y = fit.p * fit.r1 * exp(-fit.r1 * x) ...
174 + (1.0 - fit.p) * fit.r2 * exp(-fit.r2 * x);
175 otherwise % 'erlmix'
176 y = fit.p * erlang_pdf(fit.k - 1, fit.rate, x) ...
177 + (1.0 - fit.p) * erlang_pdf(fit.k, fit.rate, x);
178end
179end
180
181
182function y = srpt_tail(fit, x)
183% Complementary CDF P(X > x) evaluated on the grid x.
184switch fit.type
185 case 'exp'
186 y = exp(-fit.rate * x);
187 case 'h2'
188 y = fit.p * exp(-fit.r1 * x) + (1.0 - fit.p) * exp(-fit.r2 * x);
189 otherwise % 'erlmix'
190 y = fit.p * erlang_tail(fit.k - 1, fit.rate, x) ...
191 + (1.0 - fit.p) * erlang_tail(fit.k, fit.rate, x);
192end
193end
194
195
196function y = erlang_pdf(n, rate, x)
197% Erlang-n (shape n, given rate) density, computed in log space to avoid
198% overflow when rate*x is large. n=0 is a point mass at 0 (density 0 for x>0).
199% f(x) = rate * pois(n-1; rate*x), pois(m;t) = exp(-t) t^m / m!.
200if n <= 0
201 y = zeros(size(x));
202else
203 t = rate * x;
204 m = n - 1;
205 logp = m * log(t) - t - gammaln(m + 1); % log Poisson(m; t)
206 logp(t <= 0) = -Inf; % t=0 => pois(m>0)=0
207 if m == 0
208 logp(t <= 0) = 0; % pois(0;0)=1
209 end
210 y = rate * exp(logp);
211end
212end
213
214
215function y = erlang_tail(n, rate, x)
216% Erlang-n complementary CDF P(X>x) = sum_{j=0}^{n-1} exp(-rate x)(rate x)^j/j!
217% (upper Poisson tail), computed in log space. n=0 tail is 0 for x>0.
218if n <= 0
219 y = zeros(size(x));
220else
221 t = rate * x;
222 y = zeros(size(x));
223 for j = 0:(n - 1)
224 logp = j * log(t) - t - gammaln(j + 1);
225 logp(t <= 0) = -Inf;
226 if j == 0
227 logp(t <= 0) = 0;
228 end
229 y = y + exp(logp);
230 end
231end
232end
Definition Station.m:245