5#ifndef LINE_SOLVERS_NC_SOLVER_NC_CACHE_H
6#define LINE_SOLVERS_NC_SOLVER_NC_CACHE_H
128 const std::vector<int>& m, std::size_t n,
133 const std::size_t h = m.size();
134 const std::size_t u = lambda.size();
137 for (std::size_t v = 0; v < u; ++v)
138 for (std::size_t k = 0; k < n; ++k) lam1(v, k) = lambda[v](k, 0);
141 const std::vector<int>& sigma = ch.
itemsize;
142 const std::vector<int>& costcap = ch.
costcap;
143 if (!costcap.empty()) {
146 "solver_nc_cache_analyzer: storage cost caps require per-item sizes");
147 if (sigma.size() != n)
149 "solver_nc_cache_analyzer: the item size vector must have one entry per item");
150 if (costcap.size() != h)
152 "solver_nc_cache_analyzer: the cost cap vector must have one entry per cache "
159 std::ostringstream w;
160 w <<
"storage cost caps block the promotion path of item "
165 <<
" further pairs). The exact recursion normalizes over all size-feasible "
166 "states, which is then a strict superset of the states the cache can reach; "
167 "cross-check with SolverLDES.";
172 std::string cacheMethod =
opt.method;
176 if (cacheMethod ==
"rayint" || cacheMethod ==
"spm") cacheMethod =
"default";
182 for (std::size_t j = 0; j < h; ++j) msum += m[j];
183 const bool useSpmSize =
184 cacheMethod ==
"default" && !sigma.empty() && msum < static_cast<long>(n);
185 if (!costcap.empty() && !useSpmSize && cacheMethod !=
"exact" &&
186 cacheMethod !=
"sampling") {
190 double lattice =
static_cast<double>(n);
191 for (std::size_t j = 0; j < h; ++j)
192 lattice *=
static_cast<double>(m[j] + 1) *
static_cast<double>(costcap[j] + 1);
193 cacheMethod = (lattice <= 1e6) ?
"exact" :
"sampling";
195 std::ostringstream w;
196 w <<
"method '" <<
opt.method <<
"' does not support storage cost caps; using '"
197 << cacheMethod <<
"' instead.";
201 std::vector<T>& missRate = r.
missRate;
202 missRate.assign(u, zero);
203 if (cacheMethod ==
"exact") {
208 "solver_nc_cache_analyzer: NC does not support the exact solution of this "
209 "cache replacement policy -- only RR and FIFO are exchangeable, and a "
210 "recency-based policy (LRU, h-LRU, q-LRU, CLIMB) would silently receive the "
211 "exchangeable answer. Use the default (approximate) method or SolverCTMC");
213 for (std::size_t v = 0; v < u; ++v) {
215 for (std::size_t k = 0; k < n; ++k) acc += T(lambda[v](k, 0) * r.
pij(k, 0));
220 }
else if (useSpmSize) {
224 std::vector<int> raycap = costcap;
225 if (raycap.empty()) {
229 std::vector<int> srt = sigma;
230 std::sort(srt.begin(), srt.end(), std::greater<int>());
232 for (std::size_t j = 0; j < h; ++j) {
234 for (
int a = 0; a < m[j]; ++a) top += srt[static_cast<std::size_t>(a)];
241 for (std::size_t v = 0; v < u; ++v) {
243 for (std::size_t k = 0; k < n; ++k) acc += T(lambda[v](k, 0) * r.
pij(k, 0));
247 }
else if (cacheMethod ==
"sampling") {
277 "solver_nc_cache_analyzer: the cache occupancy is a normalizing constant formed in "
278 "logarithms and needs transcendental arithmetic");
282 const double dnan = std::numeric_limits<double>::quiet_NaN();
283 const std::size_t K =
sn.nclasses;
285 std::size_t cacheNode = 0, sourceStation = 0;
286 for (std::size_t i = 0; i <
sn.nodes.size(); ++i) {
287 if (
sn.nodes[i].nodetype == qn::NodeType::Cache) cacheNode = i + 1;
288 if (
sn.nodes[i].nodetype == qn::NodeType::Source)
289 sourceStation =
sn.nodes[i].station;
293 const auto itp =
sn.nodeparam.find(cacheNode);
294 if (itp ==
sn.nodeparam.end())
298 std::vector<T> sourceRate(K, zero);
299 for (std::size_t r = 0; r < K; ++r)
300 if (!
sn.disabled[sourceStation - 1][r]) sourceRate[r] =
sn.rates(sourceStation - 1, r);
302 const std::vector<int>& m = ch.itemcap;
303 const std::size_t n = ch.nitems;
310 bool shortForAll = !m.empty();
312 if (
static_cast<long>(n) >=
static_cast<long>(cap) + 2) shortForAll =
false;
315 "solver_nc_cache_analyzer: NC requires the number of items to exceed the "
316 "cache capacity at least by 2; this cache holds " + std::to_string(n) +
317 " items with capacity " + std::to_string(m[0]));
319 const std::size_t h = m.size();
320 const std::size_t u = K;
325 std::vector<Matrix<T>> lambda(u,
Matrix<T>(n, h + 1, zero));
326 for (std::size_t v = 0; v < u; ++v)
327 if (!ch.pread[v].empty())
328 for (std::size_t k = 0; k < n && k < ch.pread[v].size(); ++k)
329 for (std::size_t l = 0; l <= h; ++l)
330 lambda[v](k, l) = T(sourceRate[v] * ch.pread[v][k]);
335 std::vector<std::vector<Matrix<T>>> R = ch.accost;
338 for (std::size_t v = 0; v < u; ++v)
339 for (std::size_t k = 0; k < n; ++k) {
341 for (std::size_t l = 0; l < h; ++l) Rm(l, l + 1) = one;
350 const std::vector<int>& sigma = ch.itemsize;
351 const std::vector<int>& costcap = ch.costcap;
352 const std::vector<T>& missRate = cm.
missRate;
353 const bool exact = cm.
exact;
354 const std::string& method = cm.
method;
365 for (std::size_t v = 0; v < u; ++v) {
366 if (v >= sourceRate.size())
break;
368 if (!(lam > 0.0))
continue;
369 out.
missprob[v] = T(missRate[v] / sourceRate[v]);
375 const std::size_t M =
sn.nstations;
380 out.
sol.sol.C.assign(K, zero);
381 out.
sol.sol.X.assign(K, zero);
382 for (std::size_t r = 0; r < K; ++r) out.
sol.sol.Tp(sourceStation - 1, r) = sourceRate[r];
383 for (std::size_t r = 0; r < K; ++r) {
384 if (r >= ch.hitclass.size() || r >= ch.missclass.size())
continue;
385 const std::size_t hc = ch.hitclass[r],
mc = ch.missclass[r];
386 if (hc == 0 ||
mc == 0)
continue;
387 out.
sol.sol.X[
mc - 1] = T(out.
sol.sol.X[
mc - 1] + missRate[r]);
388 out.
sol.sol.X[hc - 1] = T(out.
sol.sol.X[hc - 1] + (sourceRate[r] - missRate[r]));
390 out.
sol.sol.lG = 0.0;
391 out.
sol.sol.iter = 1;
392 out.
sol.sol.method = method;
393 out.
sol.actualmethod = method;
400 for (std::size_t v = 0; v < u; ++v) {
401 if (ch.pread[v].empty())
continue;
402 for (std::size_t l = 0; l < h; ++l) {
404 for (std::size_t k = 0; k < n && k < ch.pread[v].size(); ++k)
405 acc += T(ch.pread[v][k] * out.
pij(k, l + 1));
423 if (!sigma.empty() && out.
pij.rows() == n && out.
pij.cols() == h + 1) {
434 if (
sn.nodes.size() != 3)
return false;
435 int src = 0, ca = 0, snk = 0;
437 if (nd.
nodetype == qn::NodeType::Source) ++src;
438 else if (nd.
nodetype == qn::NodeType::Cache) ++ca;
439 else if (nd.
nodetype == qn::NodeType::Sink) ++snk;
441 if (!(src == 1 && ca == 1 && snk == 1))
return false;
Mean per-list storage cost of a cache with item sizes, and the screen for promotion paths that storag...
Access factors of a tree-structured multi-list cache.
Cache miss rates from the importance-sampling hit probabilities.
Saddle-point approximation of the cache miss rates.
Exact per-item hit and miss probabilities of a multi-list cache.
Importance-sampling estimate of the cache hit-probability distribution.
Saddle-point approximation of the per-item cache hit probabilities.
Ray (WKB) asymptotic expansion of the cost-capped cache normalizing constant.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< CacheBlockedPair > cache_cost_pathcheck(const Matrix< T > &gamma, const std::vector< int > &sigma, const std::vector< int > &k, const std::vector< int > &parent)
std::vector< T > cache_cost(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k, const Matrix< T > &pij)
Mean per-list storage cost of a cache with item sizes, and the screen for promotion paths that storag...
CacheGammaResult< T > cache_gamma_lp(const std::vector< Matrix< T > > &lambda, const std::vector< std::vector< Matrix< T > > > &R)
Access factors of a tree-structured multi-list cache.
CacheMissIsResult< T > cache_miss_is(const Matrix< T > &gamma, const std::vector< int > &m, const Matrix< T > &lambda, std::size_t samples, std::uint64_t seed, const std::vector< int > &sigma, const std::vector< int > &cap)
Cache miss rates from the importance-sampling hit probabilities.
Matrix< T > cache_prob_erec(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k)
Per-item hit and miss probabilities under per-list storage cost caps, pi_ij = m_j gamma(i,...
Matrix< T > cache_prob_is(const Matrix< T > &gamma, const std::vector< int > &m, std::size_t samples, std::uint64_t seed, const std::vector< int > &sigma, const std::vector< int > &k)
Importance-sampling estimate of the cache hit-probability distribution.
CacheSpmSizeResult< T > cache_spm_size(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k, CacheCostMode mode=CacheCostMode::AtMost)
Ray (WKB) asymptotic expansion of the cost-capped cache normalizing constant.
CacheMissSpmResult< T > cache_miss_spm(const Matrix< T > &gamma, const std::vector< int > &m, const Matrix< T > &lambda)
Saddle-point approximation of the cache miss rates.
Matrix< T > cache_prob_spm(const Matrix< T > &gamma, const std::vector< int > &m)
Saddle-point approximation of the per-item cache hit probabilities.
@ FIFO
first in, first out
NcCacheMiss< T > nc_cache_missrate(const Matrix< T > &gamma, const std::vector< int > &parent, const std::vector< int > &m, std::size_t n, const std::vector< Matrix< T > > &lambda, const qn::CacheParam< T > &ch, const NcSolverOptions &opt)
Miss rates of an isolated cache under opt.method, honouring the per-item storage costs and per-list c...
NcCacheSolution< T > solver_nc_cache_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_cache_analyzer.m.
bool nc_is_noreentrant_cache(const qn::NetworkStruct< T > &sn)
True when the model is exactly a Source, a Cache and a Sink.
Conservation laws of a layered queueing network, enumerated from its structure.
Controls and result shape shared by the normalizing-constant analyzers.
A queueing network and its refreshed NetworkStruct.
Port of solver_nc.m: the load-INDEPENDENT normalizing-constant analyzer.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Return value of cache_gamma_lp, mirroring [gamma,u,n,h].
std::vector< int > parent
Parent list of each list, 0-based, -1 for lists rooted in the miss list.
Matrix< T > gamma
(n x h) access factors
std::vector< T > MU
(u) per-user miss rate; empty when no lambda given
Return value of cache_miss_spm, mirroring [M,MU,MI,pi0,lE].
std::vector< T > MU
(u) per-user miss rate
Outcome of the expansion.
Matrix< T > pij
Occupancy pi, n x (h+1), column 0 the miss probability.
Miss rates of one isolated cache and what produced them; see nc_cache_missrate.
std::vector< cache::CacheBlockedPair > costcap_blocked
std::vector< T > missRate
(u) miss rate of each user class
bool costcap_method_switched
bool exact
pij came from the exact recursion
Matrix< T > pij
(n x h+1) item occupancy of the chosen method, column 0 the miss one
What the cache analyzer returns beyond the usual metric table.
Matrix< T > hitproblist
(u x h) access-weighted per-list hit probability, NaN if not exact
Matrix< T > pij
(n x h+1) per-item occupancy, column 0 = miss
std::vector< T > missrate
(u) per-class miss rate
std::vector< cache::CacheBlockedPair > costcap_blocked
Storage cost caps that block a promotion path, so that the exact recursion normalizes over MORE state...
std::vector< T > missprob
(u) per-class miss and hit PROBABILITIES, missrate divided by the read class's arrival rate and its c...
Matrix< T > itemprob
(n x h+1) the same from the EXACT recursion, NaN above 10 items
bool costcap_method_switched
True when the requested method had no cost-capped counterpart and was switched.
std::vector< T > listcost
(h) mean storage cost held by each list, EMPTY without item sizes
The [Q,U,R,T,C,X,lG] of the reference, plus the algorithm that ran.
Controls, defaulting to SolverOptions('NC') in the reference.
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
std::vector< int > itemsize
Per-item storage cost (size) and per-list cap on the total cost of the resident items (ton21cache Sec...
std::vector< int > costcap
lang::ReplacementStrategy replacestrat
One job class of the network.
double population
infinite for an open class