LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
lqn_fwd_rendezvous.m
1function lqn = lqn_fwd_rendezvous(lqn)
2% LQN = LQN_FWD_RENDEZVOUS(LQN)
3% Port of LQNS Phase::addForwardingRendezvous (phase.cc): replace each
4% forwarding chain reachable from a synchronous call by caller-side pseudo
5% rendezvous (SYNC) calls to the forwarding targets, with mean equal to the
6% original call mean times the product of the forwarding probabilities on
7% the path. After this transformation the forwarded workload is carried by
8% ordinary SYNC call classes, so layer construction, think times,
9% populations and the interlock analysis all see plain rendezvous arcs.
10% This matches LQNS, which drops FWD arcs from the interlock analysis
11% ("Drop forward -- keep rnv", interlock.cc) and accounts for forwarding
12% only through these pseudo arcs. FWD calls are kept in the struct but no
13% longer contribute blocking anywhere in SolverLN.
14%
15% Asynchronous calls into a forwarding chain are left untouched (LQNS
16% breaks the backward search at a send-no-reply, phase.cc).
17
18if ~any(lqn.calltype == CallType.FWD)
19 return
20end
21
22ncalls0 = lqn.ncalls;
23for cidx = 1:ncalls0
24 if lqn.calltype(cidx) ~= CallType.SYNC
25 continue
26 end
27 aidx = lqn.callpair(cidx,1);
28 tidx = lqn.parent(aidx);
29 base_mean = lqn.callproc_mean(cidx);
30 if base_mean <= 0
31 continue
32 end
33 % BFS through the forwarding chain of the sync target
34 frontier = lqn.callpair(cidx,2);
35 probs = 1;
36 visitedE = [];
37 while ~isempty(frontier)
38 eidx = frontier(1); frontier(1) = [];
39 p_path = probs(1); probs(1) = [];
40 if ismember(eidx, visitedE), continue; end
41 visitedE(end+1) = eidx; %#ok<AGROW>
42 for fcidx = 1:ncalls0
43 if lqn.calltype(fcidx) ~= CallType.FWD || lqn.callpair(fcidx,1) ~= eidx
44 continue
45 end
46 fprob = lqn.callproc_mean(fcidx);
47 tgt = lqn.callpair(fcidx,2);
48 pseudo_mean = base_mean * p_path * fprob;
49 if pseudo_mean > 0 && lqn.parent(tgt) ~= tidx
50 % Merge into an existing SYNC call with the same
51 % (activity, target) pair, if any (recurActGraph matches
52 % call classes by callpair row, so duplicates are not
53 % allowed); otherwise append a new pseudo SYNC call.
54 mrow = 0;
55 for scan = 1:lqn.ncalls
56 if lqn.calltype(scan) == CallType.SYNC && ...
57 lqn.callpair(scan,1) == aidx && lqn.callpair(scan,2) == tgt
58 mrow = scan;
59 break
60 end
61 end
62 if mrow > 0
63 newmean = lqn.callproc_mean(mrow) + pseudo_mean;
64 d = Geometric(1/newmean);
65 lqn.callproc{mrow,1} = d;
66 lqn.callproc_mean(mrow) = newmean;
67 lqn.callproc_scv(mrow) = d.getSCV();
68 else
69 ncall = lqn.ncalls + 1;
70 lqn.ncalls = ncall;
71 target_tidx = lqn.parent(tgt);
72 d = Geometric(1/pseudo_mean);
73 lqn.calltype(ncall,1) = CallType.SYNC;
74 lqn.callpair(ncall,1:2) = [aidx, tgt];
75 lqn.callnames{ncall,1} = [lqn.names{aidx},'=>',lqn.names{tgt}];
76 lqn.callhashnames{ncall,1} = [lqn.hashnames{aidx},'=>',lqn.hashnames{tgt}];
77 lqn.callproc{ncall,1} = d;
78 % Only the mean (and the process object) are consumed by
79 % SolverLN; mirror the base call for the remaining fields
80 lqn.callproc_type(ncall) = lqn.callproc_type(cidx);
81 lqn.callproc_params{ncall} = lqn.callproc_params{cidx};
82 lqn.callproc_mean(ncall) = pseudo_mean;
83 lqn.callproc_scv(ncall) = d.getSCV();
84 lqn.callproc_proc{ncall} = lqn.callproc_proc{cidx};
85 lqn.callsof{aidx}(end+1) = ncall;
86 lqn.iscaller(tidx, target_tidx) = true;
87 lqn.iscaller(aidx, target_tidx) = true;
88 lqn.iscaller(tidx, tgt) = true;
89 lqn.iscaller(aidx, tgt) = true;
90 lqn.issynccaller(tidx, target_tidx) = true;
91 lqn.issynccaller(aidx, target_tidx) = true;
92 lqn.issynccaller(tidx, tgt) = true;
93 lqn.issynccaller(aidx, tgt) = true;
94 lqn.graph(aidx, tgt) = 1;
95 lqn.taskgraph(tidx, target_tidx) = 1;
96 end
97 end
98 % Follow the chain
99 if ~ismember(tgt, visitedE) && ~ismember(tgt, frontier)
100 frontier(end+1) = tgt; %#ok<AGROW>
101 probs(end+1) = p_path * fprob; %#ok<AGROW>
102 end
103 end
104 end
105end
106end
Definition Station.m:245