1function [QNn,UNn,RNn,TNn,ANn,WNn] = getAvgNode(self, Q, U, R, T, A, W)
2% [QNN,UNN,RNN,TNN,ANn,WNn] = GETNODEAVG(Q, U, R, T, A, W)
4% Compute average utilizations at steady-state
for all
nodes
6if nargin == 1 % no parameter
7 if isempty(self.model.handles) || ~isfield(self.model.handles,
'Q') || ...
8 ~isfield(self.model.handles,
'U') || ~isfield(self.model.handles,
'R') || ...
9 ~isfield(self.model.handles,
'T') || ~isfield(self.model.handles,
'A') || ...
10 ~isfield(self.model.handles,
'W')
11 reset(self); % reset in case there are partial results saved
13 [Q,U,R,T,A,W] = self.getAvgHandles;
16 [Q,U,R,T,A,W] = deal(handlers{:}); % set Q=handlers{1}, U=handlers{2}, ...
19[QN,UN,RN,TN,AN,WN] = self.getAvg(Q,U,R,T,A,W);
21 [QNn, UNn, RNn, TNn, ANn, WNn] = deal([]); % set each to []
25sn = self.model.getStruct; % must be called after getAvg eg
for caches
27% Resync each Cache node
's hit/miss/delayed-hit split from the just-run solver's
28% node-server result into the local
struct before reconstructing node
29% throughputs. see _kb/09-ldes-and-cache.md
for rationale
31 if sn.nodetype(ind) == NodeType.Cache
32 node = self.model.nodes{ind};
33 if isprop(node.server,
'actualHitProb') && ~isempty(node.server.actualHitProb)
34 sn.nodeparam{ind}.actualhitprob = full(node.server.actualHitProb);
35 sn.nodeparam{ind}.actualmissprob = full(node.server.actualMissProb);
37 if isprop(node.server,
'actualDelayedHitProb') && ~isempty(node.server.actualDelayedHitProb)
38 sn.nodeparam{ind}.actualdelayedhitprob = full(node.server.actualDelayedHitProb);
43I = sn.nnodes; % Physical
nodes only
46F = sn.nregions; % Number of FCR
virtual nodes
51% get average metrics that are zero at non-station
nodes
52QNn = zeros(totalNodes, R);
53UNn = zeros(totalNodes, R);
54RNn = zeros(totalNodes, R);
55WNn = zeros(totalNodes, R);
57% Map station metrics to node metrics
59 ind = sn.stationToNode(ist);
60 QNn(ind,:) = QN(ist,:);
61 UNn(ind,:) = UN(ist,:);
62 RNn(ind,:) = RN(ist,:);
63 WNn(ind,:) = WN(ist,:);
66% get the remaining node average metrics
67ANn = sn_get_node_arvr_from_tput(sn, TN(1:M,:), T, AN);
68TNn = sn_get_node_tput_from_tput(sn, TN(1:M,:), T, ANn);
70% Fix arrival rates
for ClassSwitch and Sink
nodes for cache hit/miss classes
71% The arrival rate at these
nodes for hit/miss classes equals the Cache throughput
73 if sn.nodetype(cacheInd) == NodeType.Cache
74 hitclass = sn.nodeparam{cacheInd}.hitclass;
75 missclass = sn.nodeparam{cacheInd}.missclass;
76 % Update arrival rates at ClassSwitch and Sink
nodes for hit/miss classes
78 if sn.nodetype(ind) == NodeType.ClassSwitch || sn.nodetype(ind) == NodeType.Sink
80 % Check
if this class is a hit class from the cache
81 if any(classIdx == hitclass(hitclass > 0))
82 ANn(ind, classIdx) = TNn(cacheInd, classIdx);
84 % Check
if this class is a miss class from the cache
85 if any(classIdx == missclass(missclass > 0))
86 ANn(ind, classIdx) = TNn(cacheInd, classIdx);
94% Extend ANn and TNn to include FCR rows
96 ANn = [ANn; NaN(F, R)]; % FCR A
is NaN (JMT doesn
't provide)
97 TNn = [TNn; zeros(F, R)];
100% Map FCR pseudo-station metrics to FCR node indices
101% FCR metrics are stored at station indices M+1 to M+F in self.result.Avg
102% FCR node indices are I+1 to I+F in node-level matrices
103% Note: getAvg() only returns station-level metrics (1:M), so we access FCR
104% metrics directly from self.result.Avg
105if F > 0 && isfield(self.result, 'Avg
') && size(self.result.Avg.Q, 1) > M
107 fcrStationIdx = M + f; % FCR pseudo-station index in result matrices
108 fcrNodeIdx = I + f; % FCR node index in nodenames
109 QNn(fcrNodeIdx,:) = self.result.Avg.Q(fcrStationIdx,:);
110 UNn(fcrNodeIdx,:) = self.result.Avg.U(fcrStationIdx,:);
111 RNn(fcrNodeIdx,:) = self.result.Avg.R(fcrStationIdx,:);
112 WNn(fcrNodeIdx,:) = self.result.Avg.W(fcrStationIdx,:);
113 TNn(fcrNodeIdx,:) = self.result.Avg.T(fcrStationIdx,:);
114 % ANn for FCR is NaN (already set above)