1%
MMAP-fed small RR cache with two correlated classes.
3% A marked MMPP2 arrival stream feeds a small Round-Robin (RR) cache. Its two
4% marks are bound to two open read classes that share
the modulating chain, so
5%
the classes are cross-correlated and autocorrelated in time. Each
class reads
6%
the cache with a DIFFERENT item-popularity distribution.
8% Phase 1 (bursty) emits mostly
class-1 references at a high rate; phase 2
9% (calm) emits mostly
class-2 references at a low rate. The shared modulating
10% chain therefore couples
"which class arrives" with
"how fast requests arrive".
12% We solve
the same system three ways:
13% (1) LDES - discrete-event simulation of
the true
MMAP-fed cache;
14% (2) CTMC - exact continuous-time Markov chain of
the true system;
15% (3) ENV - three random-environment methods that view
the MMPP2 phase as
16% an environment modulating phase-conditional Poisson arrivals
18%
'avg' - fast-environment limit: replace
the modulation by its
19% time-average per-
class Poisson rates and solve ONE
21%
'dec' - slow-environment limit: quasi-stationary
22% decomposition, solve each phase independently and
23% average per-phase hit ratios weighted by phase prob;
24%
'blend' - state-vector coupling: carry
the cache-state
25% distribution across phase switches and average each
26% phase
's sojourn-weighted distribution. For a
27% Markovian environment this recovers the exact joint
28% (cache x phase) solution, i.e. it matches CTMC.
29% The 'avg
' and 'dec
' limits discard the within-phase temporal correlation of
30% references, so neither is guaranteed to bracket the exact value.
34n = 4; % number of items
35m = 2; % cache capacity
37% Per-class item-popularity distributions (deliberately different)
38pAccess1 = DiscreteSampler([8 4 2 1]/15); % class 1 favors low-index items
39pAccess2 = DiscreteSampler([1 2 4 8]/15); % class 2 favors high-index items
41% Marked MMPP2 (M3A layout D = {D0, D11, D12}); D1 = D11 + D12 diagonal.
42% Phase 1 bursty (rate 4, 90% class1); phase 2 calm (rate 1, 80% class2).
43% Off-diagonal of D0 are the phase-switch rates (both 0.5).
44D0 = [-4.5, 0.5; 0.5, -1.5];
45D11 = [3.6, 0; 0, 0.2]; % class-1 arrivals per phase
46D12 = [0.4, 0; 0, 0.8]; % class-2 arrivals per phase
47mmap = MarkedMAP({D0, D11, D12}, 2);
49%% (1) LDES - simulation of the true MMAP-fed cache
50trueModel = buildCacheModel(n, m, pAccess1, pAccess2);
51src = trueModel.getNodeByName('Source
');
52src.setMarkedArrival(mmap, {trueModel.classes{1}, trueModel.classes{2}});
53cacheTrue = trueModel.getNodeByName('Cache
');
55solver{1} = LDES(trueModel, 'samples
', 2e5, 'seed
', 23000, 'verbose
', true);
56AvgTable{1} = solver{1}.getAvgNodeTable; AvgTable{1}
57hitLDES = cacheTrue.getHitRatio;
59%% (2) CTMC - exact solution of the true system
61solver{2} = CTMC(trueModel, 'keep
', false, 'cutoff
', 1);
62AvgTable{2} = solver{2}.getAvgNodeTable; AvgTable{2}
63hitCTMC = cacheTrue.getHitRatio;
65%% Random environment: the MMPP2 phase modulates phase-conditional Poisson
66% arrivals (D1 diagonal); the environment switches at the MMPP2 phase-transition
67% rates (-D0 diagonal minus the total arrival rate).
68envBase = buildCacheModel(n, m, pAccess1, pAccess2);
69env = Environment('MMPPphase
');
70env.addStage('Phase1
', 'bursty
', local_setRates(envBase, D11(1,1), D12(1,1))); % 3.6/0.4
71env.addStage('Phase2
', 'calm
', local_setRates(envBase, D11(2,2), D12(2,2))); % 0.2/0.8
72env.addTransition('Phase1
', 'Phase2
', Exp(-D0(1,1) - (D11(1,1)+D12(1,1)))); % 0.5
73env.addTransition('Phase2
', 'Phase1
', Exp(-D0(2,2) - (D11(2,2)+D12(2,2)))); % 0.5
77solverFactory = @(mdl) CTMC(mdl, 'keep
', false, 'cutoff
', 1);
79% (3a) ENV method 'avg
' - fast-environment limit (rate-averaged single model)
80optAvg = Solver.defaultOptions; optAvg.method = 'avg
'; optAvg.verbose = false;
81solver{3} = ENV(env, solverFactory, optAvg);
83hitAVG = solver{3}.ensemble{1}.getNodeByName('Cache
').getHitRatio;
85% (3b) ENV method 'dec
' - slow-environment quasi-stationary decomposition
86optDec = Solver.defaultOptions; optDec.method = 'dec
'; optDec.verbose = false;
87solver{4} = ENV(env, solverFactory, optDec);
89hitDEC = solver{4}.ensemble{1}.getNodeByName('Cache
').getHitRatio;
91% (3c) ENV method 'blend
' - state-vector coupling: carries the cache-state
92% distribution across phase switches and averages each phase's sojourn-weighted
93% distribution. Needs a finite-timespan CTMC inner solver.
94blendFactory = @(mdl) CTMC(mdl,
'keep',
false,
'cutoff', 1,
'timespan', [0, 1e3]);
95optBlend = Solver.defaultOptions; optBlend.method =
'blend'; optBlend.verbose =
false;
96optBlend.iter_max = 100; optBlend.iter_tol = 1e-4;
97solver{5} = ENV(env, blendFactory, optBlend);
99hitBLEND = solver{5}.ensemble{1}.getNodeByName(
'Cache').getHitRatio;
101% (3d) ENV
default mean-field with an FLD (refined mean-field) inner solver.
102% The cache
is analyzed by
the RMF drift;
the mean occupancy
is carried across
103% phase switches (
the cache analog of
the queue-length handoff) and
the hit
104% ratio
is the probEnv-weighted, sojourn-averaged (arrival x hit-prob). Needs a
105% finite-timespan fluid inner solver. This
is the fully mean-field counterpart
106% of
'blend', trading
the exact joint distribution
for a fluid approximation.
107fldFactory = @(mdl) FLD(mdl,
'method',
'rmf',
'timespan', [0, 50]);
108optFLD = Solver.defaultOptions; optFLD.verbose =
false;
109optFLD.iter_max = 100; optFLD.iter_tol = 1e-4;
110solver{6} = ENV(env, fldFactory, optFLD);
112hitFLD = solver{6}.ensemble{1}.getNodeByName(
'Cache').getHitRatio;
114%% Summary: per-read-
class actual hit ratio (classes 1=Read1, 2=Read2)
115fprintf(
'\n--- Actual cache hit ratio per read class ---\n');
116fprintf(
' Read1 Read2\n');
117fprintf(
'LDES (sim) : %8.4f %8.4f\n', hitLDES(1), hitLDES(2));
118fprintf(
'CTMC (true) : %8.4f %8.4f\n', hitCTMC(1), hitCTMC(2));
119fprintf(
'ENV (avg) : %8.4f %8.4f\n', hitAVG(1), hitAVG(2));
120fprintf(
'ENV (dec) : %8.4f %8.4f\n', hitDEC(1), hitDEC(2));
121fprintf(
'ENV (blend) : %8.4f %8.4f\n', hitBLEND(1), hitBLEND(2));
122fprintf(
'ENV (mf/FLD) : %8.4f %8.4f\n', hitFLD(1), hitFLD(2));
125function model = buildCacheModel(n, m, pAccess1, pAccess2)
126 model = Network(
'MMAPCache');
127 source = Source(model,
'Source');
128 cacheNode = Cache(model,
'Cache', n, m, ReplacementStrategy.RR);
129 sink = Sink(model,
'Sink');
131 rd1 = OpenClass(model,
'Read1', 0);
132 rd2 = OpenClass(model,
'Read2', 0);
133 hit1 = OpenClass(model,
'Hit1', 0);
134 mis1 = OpenClass(model,
'Miss1', 0);
135 hit2 = OpenClass(model,
'Hit2', 0);
136 mis2 = OpenClass(model,
'Miss2', 0);
138 cacheNode.setRead(rd1, pAccess1);
139 cacheNode.setRead(rd2, pAccess2);
140 cacheNode.setHitClass(rd1, hit1); cacheNode.setMissClass(rd1, mis1);
141 cacheNode.setHitClass(rd2, hit2); cacheNode.setMissClass(rd2, mis2);
143 P = model.initRoutingMatrix;
144 P{rd1,rd1}(source, cacheNode) = 1.0;
145 P{rd2,rd2}(source, cacheNode) = 1.0;
146 P{hit1,hit1}(cacheNode, sink) = 1.0;
147 P{mis1,mis1}(cacheNode, sink) = 1.0;
148 P{hit2,hit2}(cacheNode, sink) = 1.0;
149 P{mis2,mis2}(cacheNode, sink) = 1.0;
153function model = local_setRates(baseModel, lambda1, lambda2)
154 model = baseModel.copy();
155 source = model.getNodeByName(
'Source');
156 source.setArrival(model.classes{1}, Exp(lambda1)); % Read1 Poisson
157 source.setArrival(model.classes{2}, Exp(lambda2)); % Read2 Poisson