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 hit probabilities are genuine only on the exact branch; see
56% _kb/09-ldes-and-cache.md on cache-analyzer per-list/per-item reporting
57pijlist = []; % genuine per-list occupancy (n x h), set in the exact branch
60 line_debug(
'Using exact cache method');
61 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
62 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
63 line_debug(
'Replacement strategy: RR/FIFO, calling cache_mva');
64 [~,~,pij] = cache_mva(gamma, m);
65 pij = [abs(1-sum(pij,2)),pij];
66 pijlist = pij(:, 2:end);
68 line_error(mfilename,
'MVA does not support exact solution of the specified cache replacement policy.')
71 line_debug('Default method: using approximate cache method\n');
72 line_debug('Using approximate cache method');
73 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
74 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
75 line_debug(
'Replacement strategy: RR/FIFO, calling cache_prob_fpi');
76 pij = cache_prob_fpi(gamma,m); % FPI method
77 case ReplacementStrategy.LRU
78 % Marked (
MMAP) source
is not IRM -> LRU(m)-MAP TTL approximation;
79 % see _kb/09-ldes-and-cache.md on cache-analyzer reporting
80 markedreaders = isfield(sn,
'markidx') && ~isempty(sn.markidx) ...
81 && any(sn.markidx(source_ist,:) > 0);
83 Dcell = sn.proc{source_ist}{find(sn.markidx(source_ist,:)>0,1)};
84 D0 = Dcell{1}; D1agg = Dcell{2};
85 D0c = cell(1,n); D1c = cell(1,n);
88 D1c{k} = zeros(size(D0));
90 if ~isnan(ch.pread{v})
91 if sn.markidx(source_ist,v) > 0
92 D1c{k} = D1c{k} + Dcell{2+sn.markidx(source_ist,v)} * ch.pread{v}(k);
93 elseif sourceRate(v) > 0 && any(ch.pread{v} > 0)
94 allmarked = false; % unmarked reader mixed in
98 D0c{k} = D0 + D1agg - D1c{k};
101 line_debug(
'Replacement strategy: LRU with marked MAP source, calling cache_ttl_lrum_map');
102 pij = cache_ttl_lrum_map(D0c, D1c, m);
104 line_debug(
'Replacement strategy: LRU, calling cache_ttl_lrua');
105 pij = cache_ttl_lrua(lambda, Rcost, m); % allows trees and access costs
108 line_debug(
'Replacement strategy: LRU, calling cache_ttl_lrua');
109 pij = cache_ttl_lrua(lambda, Rcost, m); % allows trees and access costs
111 case ReplacementStrategy.HLRU
112 % h-LRU / LRU(m) characteristic-time approximation (linear
113 % list topology; access-cost graphs are not supported)
114 line_debug(
'Replacement strategy: HLRU, calling cache_ttl_hlru');
115 pij = cache_ttl_hlru(lambda, m);
117 line_error(mfilename,
'MVA does not support approximate solution of the specified cache replacement policy.')
120missRate = zeros(1,u);
122 missRate(v) = lambda(v,:,1)*pij(:,1);
125% per-list (per-level) hit probabilities (access-weighted), only where the
126% exact algorithm produced a genuine per-list occupancy matrix.
127hitproblist = NaN(u, h);
130 if any(~isnan(ch.pread{v}))
131 pread = ch.pread{v}(:).
';
133 hitproblist(v,l) = pread * pijlist(:,l);
139% per-item occupancy [nitems x (lists+1)] (col 1 = miss); derived from the exact
140% cache_mva recursion (skipped, NaN, for >10 items); see
141% _kb/09-ldes-and-cache.md on cache-analyzer per-list/per-item reporting
144 itemprob = pij; % exact branch: already [n x (h+1)] with col 1 = miss
145elseif size(pij,2) == h+1
146 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
147 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
149 line_warning(mfilename, 'Per-item cache occupancy (getAvgItemTable)
requires the exact algorithm
for RR/FIFO and
is skipped
for caches with more than 10 items (%d items); reporting NaN.
', n);
150 itemprob = NaN(n, h+1);
152 [~,~,pij_ex] = cache_mva(gamma, m);
153 itemprob = [abs(1-sum(pij_ex,2)), pij_ex];
156 itemprob = pij; % LRU-TTL: genuine per-list distribution
161 if length(ch.hitclass)>=r && ch.missclass(r)>0 && ch.hitclass(r)>0
162 XN(ch.missclass(r)) = XN(ch.missclass(r)) + missRate(r);
163 XN(ch.hitclass(r)) = XN(ch.hitclass(r)) + (sourceRate(r) - missRate(r));
167% Set the actual method used
168if strcmp(options.method, 'exact
')
171 switch sn.nodeparam{sn.nodetype == NodeType.Cache}.replacestrat
172 case {ReplacementStrategy.RR, ReplacementStrategy.FIFO}
174 case ReplacementStrategy.LRU
177 method = options.method;