1function prOt = overtake_prob_markov(self, eidx)
2% OVERTAKE_PROB_MARKOV Overtaking probability via
the LQNS phased-server Markov chain.
4% PROT = OVERTAKE_PROB_MARKOV(SELF, EIDX) computes
the probability that a
new
5% arrival to server entry EIDX finds
the server busy in phase 2 (post-reply
6% processing),
using the LQNS V6 slice/overtake Markov chain (Layer 1) rather
7% than
the reduced 3-state CTMC in OVERTAKE_PROB.
9% This
is the input-mapping layer (Layer 1c): it derives
the per-client-phase
10% slice parameters (nSlices, host residence, calls to
the server task, calls to
11% other tasks, delay at other tasks) from
the LayeredNetworkStruct and
the
12% current per-layer MVA residence times, then delegates
the chain solution to
13% LQN_OVERTAKE_MARKOV. Contributions of all synchronous caller entries are
14% summed and truncated to 1 (cf. LQNS Markov_Phased_Server::PrOT_e).
16% Reference: Franks & Woodside,
"Effectiveness of early replies in client-server
17% systems", Perf. Eval. 36 (1999). See [[overtaking-markov-port]].
22 % Server phase-2 residence (x_j
for the tested server phase j=2).
23 xj = self.servt_ph2(eidx);
24 if ~(xj > GlobalConstants.FineTol)
27 server_tidx = lqn.parent(eidx);
29 % Synchronous caller activities into
this server entry.
30 caller_acts = full(lqn.callpair(lqn.callpair(:,2) == eidx, 1));
31 if isempty(caller_acts)
35 % Group caller activities by their owning client entry.
37 for ci = 1:numel(caller_acts)
38 aidx = caller_acts(ci);
39 ceidx = local_entry_of_activity(lqn, aidx);
40 if ceidx > 0 && ~any(caller_entries == ceidx)
41 caller_entries(end+1) = ceidx; %#ok<AGROW>
45 for ceidx = caller_entries
46 ctidx = lqn.parent(ceidx);
47 acts = lqn.actsof{ceidx};
52 % Maximum client phase (LINE activities carry phase 1 or 2).
55 a = aidx - lqn.ashift;
56 if a >= 1 && a <= lqn.nacts
57 maxPhaseA = max(maxPhaseA, lqn.actphase(a));
61 % clientPhases rows p=0..maxPhaseA: [nSlices service y_ij y_ik t_k].
62 nStates = maxPhaseA + 1;
63 clientPhases = zeros(nStates, 5);
64 clientPhases(1,1) = 1.0; % think slice: nSlices=1
65 clientPhases(1,2) = local_think_time(lqn, ctidx); % service = client think time
67 y_aj = zeros(1, maxPhaseA + 1);
69 nSlices = 1.0; service = 0.0;
70 y_ij = 0.0; y_ik = 0.0; tk_num = 0.0;
72 a = aidx - lqn.ashift;
73 if a < 1 || a > lqn.nacts || lqn.actphase(a) ~= p
76 service = service + self.servt(aidx); % host residence of
the phase
77 for c = lqn.callsof{aidx}
78 if lqn.calltype(c) ~= CallType.SYNC
81 y = lqn.callproc_mean(c);
82 if y == 0,
continue; end
83 nSlices = nSlices + y;
84 dst_tidx = lqn.parent(lqn.callpair(c,2));
85 if dst_tidx == server_tidx
89 tk_num = tk_num + y * self.callresidt(c); % rendezvous delay
93 if y_ik > 0.0, t_k = tk_num / y_ik;
else, t_k = 0.0; end
94 clientPhases(p+1,:) = [nSlices, service, y_ij, y_ik, t_k];
96 y_aj(1) = y_aj(1) + y_ij;
100 continue; %
this client does not call
the server task
103 % Client entry visit probability (1
for reference/sole entry).
105 if self.tput(ctidx) > GlobalConstants.FineTol && self.tput(ceidx) > GlobalConstants.FineTol
106 prVisit = self.tput(ceidx) / self.tput(ctidx);
109 prOt = prOt + lqn_overtake_markov(clientPhases, prVisit, xj, y_aj);
112 prOt = max(0.0, min(1.0, prOt));
115% ---------------------------------------------------------------------------
116function ceidx = local_entry_of_activity(lqn, aidx)
117% Absolute entry index owning activity aidx (via actsof),
else -1.
119 for e = 1:lqn.nentries
120 eabs = lqn.eshift + e;
121 if any(lqn.actsof{eabs} == aidx)
128function z = local_think_time(lqn, tidx)
129% Client task think time (0 when unspecified).
131 if isfield(lqn,
'think_mean') && numel(lqn.think_mean) >= tidx
132 v = lqn.think_mean(tidx);
133 if isfinite(v) && v > 0, z = v; end