1function [QN,UN,RN,TN,CN,XN,lGN,runtime,iter,method,hitproblist,itemprob] = solver_mva_cache_analyzer(sn, options)
2% [Q,U,R,T,C,X,LG,RUNTIME,ITER,METHOD,HITPROBLIST] = SOLVER_MVA_CACHE_ANALYZER(QN, OPTIONS)
4% Copyright (c) 2012-2026, Imperial College London
11XN = zeros(1,sn.nclasses);
15line_debug(
'MVA cache analyzer starting: method=%s, nclasses=%d', options.method, sn.nclasses);
17source_ist = sn.nodeToStation(sn.nodetype == NodeType.Source);
18sourceRate = sn.rates(source_ist,:);
19sourceRate(isnan(sourceRate)) = 0;
20TN(source_ist,:) = sourceRate;
22ch = sn.nodeparam{sn.nodetype == NodeType.Cache};
33 if ~isnan(ch.pread{v})
34 lambda(v,k,l) = sourceRate(v) * ch.pread{v}(k);
42 % Default linear cache routing: items flow from list l to list l+1
46 Rmat = diag(ones(1, h), 1);
53gamma = cache_gamma_lp(lambda,Rcost);
55% per-list (per-level) hit probabilities are reported only from the exact
56% kernel, where the miss column and the per-list columns of pij share one
57% consistent solution (so the per-list rows sum to the aggregate hit). For
58% the approximate kernels the per-list breakdown
is left undefined (NaN).
59pijlist = []; % genuine per-list occupancy (n x h), set in the exact branch
62 line_debug(
'Using exact cache method');
63 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
64 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
65 line_debug(
'Replacement strategy: RR/FIFO, calling cache_mva');
66 [~,~,pij] = cache_mva(gamma, m);
67 pij = [abs(1-sum(pij,2)),pij];
68 pijlist = pij(:, 2:end);
70 line_error(mfilename,
'MVA does not support exact solution of the specified cache replacement policy.')
73 line_debug('Default method: using approximate cache method\n');
74 line_debug('Using approximate cache method');
75 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
76 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
77 line_debug(
'Replacement strategy: RR/FIFO, calling cache_prob_fpi');
78 pij = cache_prob_fpi(gamma,m); % FPI method
79 case ReplacementStrategy.LRU
80 line_debug(
'Replacement strategy: LRU, calling cache_ttl_lrua');
81 %pij = cache_ttl_lrum(lambda, m); % linear topology only
82 pij = cache_ttl_lrua(lambda, Rcost, m); % allows trees and access costs
83 %
case ReplacementStrategy.HLRU
84 %
this is integrated but the cache_ttl_hlru script
is not
85 % working correctly at present
86 %pij = cache_ttl_hlru(lambda, m); % without considering different graph of different items linear
88 line_error(mfilename,
'MVA does not support approximate solution of the specified cache replacement policy.')
93 missRate(v) = lambda(v,:,1)*pij(:,1);
96% per-list (per-level) hit probabilities (access-weighted), only where the
97% exact kernel produced a genuine per-list occupancy matrix.
98hitproblist = NaN(u, h);
101 if any(~isnan(ch.pread{v}))
102 pread = ch.pread{v}(:).
';
104 hitproblist(v,l) = pread * pijlist(:,l);
110% per-item occupancy [nitems x (lists+1)] (col 1 = miss, cols 2..end per-list).
111% This requires a genuine per-list distribution (rows summing to 1):
112% - exact kernel: pij is already genuine;
113% - approximate LRU (cache_ttl_lrua): pij is a genuine per-list distribution;
114% - approximate RR/FIFO: the FPI kernel (cache_prob_fpi) replicates the
115% aggregate hit across list columns, so it is NOT a genuine per-list
116% breakdown; derive it from the exact product-form kernel cache_mva instead
117% (the FPI pij is still used above for the aggregate miss rate).
118% The exact RR/FIFO recursion (cache_mva) is only tractable for small item
119% sets, so it is skipped (NaN, with a warning) for caches with more than 10
123 itemprob = pij; % exact branch: already [n x (h+1)] with col 1 = miss
124elseif size(pij,2) == h+1
125 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
126 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
128 line_warning(mfilename, 'Per-item cache occupancy (getAvgItemTable)
requires the exact kernel
for RR/FIFO and
is skipped
for caches with more than 10 items (%d items); reporting NaN.
', n);
129 itemprob = NaN(n, h+1);
131 [~,~,pij_ex] = cache_mva(gamma, m);
132 itemprob = [abs(1-sum(pij_ex,2)), pij_ex];
135 itemprob = pij; % LRU-TTL: genuine per-list distribution
140 if length(ch.hitclass)>=r && ch.missclass(r)>0 && ch.hitclass(r)>0
141 XN(ch.missclass(r)) = XN(ch.missclass(r)) + missRate(r);
142 XN(ch.hitclass(r)) = XN(ch.hitclass(r)) + (sourceRate(r) - missRate(r));
146% Set the actual method used
147if strcmp(options.method, 'exact
')
150 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
151 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
153 case ReplacementStrategy.LRU
156 method = options.method;