1function [W, rho_total] = qsys_mg1_srpt(lambda, mu, cs)
2% QSYS_MG1_SRPT Compute mean response time
for M/G/1/SRPT queue
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.
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:
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)
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
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.
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.
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)
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)
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).
49% Copyright (c) 2012-2026, Imperial College London
52% Ensure inputs are
column vectors
53lambda = reshape(lambda, [], 1);
54mu = reshape(mu, [], 1);
55cs = reshape(cs, [], 1);
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');
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');
70lambda_total = sum(lambda);
71p = lambda / lambda_total; % size-mixture probabilities
73% Overall utilization and stability check
74rho_util = sum(lambda ./ mu);
76 error('qsys_mg1_srpt:UnstableSystem', ...
77 sprintf('System
is unstable: utilization rho = %g >= 1', rho_util));
80% Build per-class job-size representations and collect phase-rate bounds
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);
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)
';
97% Mixture density f(x) and tail Fbar(x) = 1 - F(x)
98fmix = zeros(N + 1, 1);
99Fbar = zeros(N + 1, 1);
101 fmix = fmix + p(r) * srpt_pdf(fits{r}, x);
102 Fbar = Fbar + p(r) * srpt_tail(fits{r}, x);
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);
109% Guard the (1-rho(x)) factors: rho(x) -> rho_util < 1 as x -> inf
110denom = max(1.0 - rho_x, 1e-12);
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);
117% Per-class mean response time: integrate E[T(x)] against class density
120 W(r) = trapz(x, ET .* srpt_pdf(fits{r}, x));
123% Load measure returned as rhohat = Q/(1+Q) (qsys convention)
125rho_total = Q / (1 + Q);
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.
135if abs(c2 - 1.0) < 1e-9
142 % Two-phase balanced-means hyperexponential (matches mean and scv)
143 pr = 0.5 * (1.0 + sqrt((c2 - 1.0) / (c2 + 1.0)));
145 r2 = 2.0 * (1.0 - pr) * mu;
150 fit.rate_min = min(r1, r2);
151 fit.rate_max = max(r1, r2);
153 % Tijms mixture of Erlang-(k-1) and Erlang-k with common rate
155 pr = (1.0 / (1.0 + c2)) * (k * c2 - sqrt(k * (1.0 + c2) - k * k * c2));
156 rate = (k - pr) / mean_x;
167function y = srpt_pdf(fit, x)
168% Job-size probability density evaluated on the grid x.
171 y = fit.rate * exp(-fit.rate * x);
173 y = fit.p * fit.r1 * exp(-fit.r1 * x) ...
174 + (1.0 - fit.p) * fit.r2 * exp(-fit.r2 * x);
176 y = fit.p * erlang_pdf(fit.k - 1, fit.rate, x) ...
177 + (1.0 - fit.p) * erlang_pdf(fit.k, fit.rate, x);
182function y = srpt_tail(fit, x)
183% Complementary CDF P(X > x) evaluated on the grid x.
186 y = exp(-fit.rate * x);
188 y = fit.p * exp(-fit.r1 * x) + (1.0 - fit.p) * exp(-fit.r2 * x);
190 y = fit.p * erlang_tail(fit.k - 1, fit.rate, x) ...
191 + (1.0 - fit.p) * erlang_tail(fit.k, fit.rate, x);
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!.
205 logp = m * log(t) - t - gammaln(m + 1); % log Poisson(m; t)
206 logp(t <= 0) = -Inf; % t=0 => pois(m>0)=0
208 logp(t <= 0) = 0; % pois(0;0)=1
210 y = rate * exp(logp);
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.
224 logp = j * log(t) - t - gammaln(j + 1);