LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
lqn_transient.m
1% LQN_TRANSIENT Transient (time-dependent) analysis of a layered network.
2%
3% Demonstrates LN.getTranAvg, which returns the transient mean queue
4% length, utilization and throughput of every ensemble layer over time. The
5% traces are assembled block-diagonally: layer e occupies a disjoint block of
6% rows (its stations) and columns (its classes). Transient output is only
7% produced by transient-capable per-layer solvers (Fluid, CTMC, SSA); here the
8% layers are solved with the fluid ODE solver. Do not set a 'timespan' on the
9% per-layer factory: the steady-state fixed point rejects it, and getTranAvg
10% auto-selects the timespan per layer.
11%
12% getTranAvg first converges the LN fixed point (getAvg), pinning the
13% inter-layer demands to equilibrium, then runs each layer's transient with
14% those demands frozen. The initial point is the layer's default state (all
15% closed jobs at the reference station, via State.initDefault), NOT the
16% converged occupancy, so each curve relaxes from all-at-reference to the
17% layer steady state. Use setState to seed a different start.
18%
19% The model is a simple 3-layer LQN: a reference task T1 on processor P1 whose
20% activity synchronously calls entry E2 of task T2 on processor P2. The three
21% ensemble layers are the two processor (host) layers and the T2 task layer.
22
23model = LayeredNetwork('lqn_transient');
24
25P1 = Processor(model, 'P1', 1, SchedStrategy.PS);
26P2 = Processor(model, 'P2', 1, SchedStrategy.PS);
27
28T1 = Task(model, 'T1', 5, SchedStrategy.REF).on(P1).setThinkTime(Exp(1.0));
29T2 = Task(model, 'T2', 5, SchedStrategy.FCFS).on(P2).setThinkTime(Exp(1.0));
30
31E1 = Entry(model, 'E1').on(T1);
32E2 = Entry(model, 'E2').on(T2);
33
34A1 = Activity(model, 'A1', Exp(2.0)).on(T1).boundTo(E1).synchCall(E2, 1);
35A2 = Activity(model, 'A2', Exp(3.0)).on(T2).boundTo(E2).repliesTo(E2);
36
37% Solve the ensemble with a fluid solver on each layer, then obtain the
38% per-layer transient averages in a single call.
39solver = LN(model, @(m) FLD(m, 'verbose', false), 'verbose', false);
40[QNt, UNt, TNt] = solver.getTranAvg();
41
42E = solver.nlayers;
43fprintf('LN.getTranAvg returned transient traces for %d layers.\n', E);
44
45% Plot the transient mean queue length E[N](t) of each station, one panel per
46% layer. The block-diagonal offsets (r0,c0) advance by each layer's station and
47% class counts, mirroring how getTranAvg stacks the per-layer blocks.
48figure('Name', 'LN.getTranAvg: per-layer transient E[N](t)');
49r0 = 0;
50c0 = 0;
51for e = 1:E
52 sn = solver.ensemble{e}.getStruct();
53 M = sn.nstations;
54 K = sn.nclasses;
55 subplot(E, 1, e);
56 hold on;
57 box on;
58 grid on;
59 tsettle = 0;
60 for i = 1:M
61 for r = 1:K
62 trace = QNt{r0 + i, c0 + r};
63 if isstruct(trace) && isfield(trace, 'metric') && any(trace.metric > 1e-6)
64 stname = trace.handle{1}.name;
65 clname = trace.handle{2}.name;
66 plot(trace.t, trace.metric, 'LineWidth', 1.5, ...
67 'DisplayName', sprintf('%s [%s]', stname, clname));
68 % Track when this trace stops changing so the axis can be
69 % zoomed onto the transient (getTranAvg auto-selects a wide
70 % timespan and the curves are flat once settled).
71 m = trace.metric;
72 if numel(m) > 1
73 tol = 0.01 * (max(m) - min(m)) + 1e-9;
74 klast = find(abs(m - m(end)) > tol, 1, 'last');
75 if ~isempty(klast)
76 tsettle = max(tsettle, trace.t(min(klast + 1, numel(m))));
77 end
78 end
79 end
80 end
81 end
82 r0 = r0 + M;
83 c0 = c0 + K;
84 if tsettle > 0
85 xlim([0, 1.3 * tsettle]);
86 end
87 title(sprintf('Layer %d', e));
88 xlabel('time t');
89 ylabel('E[N](t)');
90 legend('Location', 'best');
91end
Definition Station.m:245