mem-cache: Fix invalidation of prefetchers
[gem5.git] / src / mem / cache / tags / base.cc
1 /*
2 * Copyright (c) 2013,2016,2018-2019 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Erik Hallnor
41 * Ron Dreslinski
42 */
43
44 /**
45 * @file
46 * Definitions of BaseTags.
47 */
48
49 #include "mem/cache/tags/base.hh"
50
51 #include <cassert>
52
53 #include "base/types.hh"
54 #include "mem/cache/replacement_policies/replaceable_entry.hh"
55 #include "mem/cache/tags/indexing_policies/base.hh"
56 #include "mem/request.hh"
57 #include "sim/core.hh"
58 #include "sim/sim_exit.hh"
59 #include "sim/system.hh"
60
61 BaseTags::BaseTags(const Params *p)
62 : ClockedObject(p), blkSize(p->block_size), blkMask(blkSize - 1),
63 size(p->size), lookupLatency(p->tag_latency),
64 system(p->system), indexingPolicy(p->indexing_policy),
65 warmupBound((p->warmup_percentage/100.0) * (p->size / p->block_size)),
66 warmedUp(false), numBlocks(p->size / p->block_size),
67 dataBlks(new uint8_t[p->size]), // Allocate data storage in one big chunk
68 stats(*this)
69 {
70 registerExitCallback(new BaseTagsCallback(this));
71 }
72
73 ReplaceableEntry*
74 BaseTags::findBlockBySetAndWay(int set, int way) const
75 {
76 return indexingPolicy->getEntry(set, way);
77 }
78
79 CacheBlk*
80 BaseTags::findBlock(Addr addr, bool is_secure) const
81 {
82 // Extract block tag
83 Addr tag = extractTag(addr);
84
85 // Find possible entries that may contain the given address
86 const std::vector<ReplaceableEntry*> entries =
87 indexingPolicy->getPossibleEntries(addr);
88
89 // Search for block
90 for (const auto& location : entries) {
91 CacheBlk* blk = static_cast<CacheBlk*>(location);
92 if ((blk->tag == tag) && blk->isValid() &&
93 (blk->isSecure() == is_secure)) {
94 return blk;
95 }
96 }
97
98 // Did not find block
99 return nullptr;
100 }
101
102 void
103 BaseTags::insertBlock(const PacketPtr pkt, CacheBlk *blk)
104 {
105 assert(!blk->isValid());
106
107 // Previous block, if existed, has been removed, and now we have
108 // to insert the new one
109
110 // Deal with what we are bringing in
111 MasterID master_id = pkt->req->masterId();
112 assert(master_id < system->maxMasters());
113 stats.occupancies[master_id]++;
114
115 // Insert block with tag, src master id and task id
116 blk->insert(extractTag(pkt->getAddr()), pkt->isSecure(), master_id,
117 pkt->req->taskId());
118
119 // Check if cache warm up is done
120 if (!warmedUp && stats.tagsInUse.value() >= warmupBound) {
121 warmedUp = true;
122 stats.warmupCycle = curTick();
123 }
124
125 // We only need to write into one tag and one data block.
126 stats.tagAccesses += 1;
127 stats.dataAccesses += 1;
128 }
129
130 Addr
131 BaseTags::extractTag(const Addr addr) const
132 {
133 return indexingPolicy->extractTag(addr);
134 }
135
136 void
137 BaseTags::cleanupRefsVisitor(CacheBlk &blk)
138 {
139 if (blk.isValid()) {
140 stats.totalRefs += blk.refCount;
141 ++stats.sampledRefs;
142 }
143 }
144
145 void
146 BaseTags::cleanupRefs()
147 {
148 forEachBlk([this](CacheBlk &blk) { cleanupRefsVisitor(blk); });
149 }
150
151 void
152 BaseTags::computeStatsVisitor(CacheBlk &blk)
153 {
154 if (blk.isValid()) {
155 assert(blk.task_id < ContextSwitchTaskId::NumTaskId);
156 stats.occupanciesTaskId[blk.task_id]++;
157 assert(blk.tickInserted <= curTick());
158 Tick age = curTick() - blk.tickInserted;
159
160 int age_index;
161 if (age / SimClock::Int::us < 10) { // <10us
162 age_index = 0;
163 } else if (age / SimClock::Int::us < 100) { // <100us
164 age_index = 1;
165 } else if (age / SimClock::Int::ms < 1) { // <1ms
166 age_index = 2;
167 } else if (age / SimClock::Int::ms < 10) { // <10ms
168 age_index = 3;
169 } else
170 age_index = 4; // >10ms
171
172 stats.ageTaskId[blk.task_id][age_index]++;
173 }
174 }
175
176 void
177 BaseTags::computeStats()
178 {
179 for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
180 stats.occupanciesTaskId[i] = 0;
181 for (unsigned j = 0; j < 5; ++j) {
182 stats.ageTaskId[i][j] = 0;
183 }
184 }
185
186 forEachBlk([this](CacheBlk &blk) { computeStatsVisitor(blk); });
187 }
188
189 std::string
190 BaseTags::print()
191 {
192 std::string str;
193
194 auto print_blk = [&str](CacheBlk &blk) {
195 if (blk.isValid())
196 str += csprintf("\tBlock: %s\n", blk.print());
197 };
198 forEachBlk(print_blk);
199
200 if (str.empty())
201 str = "no valid tags\n";
202
203 return str;
204 }
205
206 BaseTags::BaseTagStats::BaseTagStats(BaseTags &_tags)
207 : Stats::Group(&_tags),
208 tags(_tags),
209
210 tagsInUse(this, "tagsinuse",
211 "Cycle average of tags in use"),
212 totalRefs(this, "total_refs",
213 "Total number of references to valid blocks."),
214 sampledRefs(this, "sampled_refs",
215 "Sample count of references to valid blocks."),
216 avgRefs(this, "avg_refs",
217 "Average number of references to valid blocks."),
218 warmupCycle(this, "warmup_cycle",
219 "Cycle when the warmup percentage was hit."),
220 occupancies(this, "occ_blocks",
221 "Average occupied blocks per requestor"),
222 avgOccs(this, "occ_percent",
223 "Average percentage of cache occupancy"),
224 occupanciesTaskId(this, "occ_task_id_blocks",
225 "Occupied blocks per task id"),
226 ageTaskId(this, "age_task_id_blocks", "Occupied blocks per task id"),
227 percentOccsTaskId(this, "occ_task_id_percent",
228 "Percentage of cache occupancy per task id"),
229 tagAccesses(this, "tag_accesses", "Number of tag accesses"),
230 dataAccesses(this, "data_accesses", "Number of data accesses")
231 {
232 }
233
234 void
235 BaseTags::BaseTagStats::regStats()
236 {
237 using namespace Stats;
238
239 Stats::Group::regStats();
240
241 System *system = tags.system;
242
243 avgRefs = totalRefs / sampledRefs;
244
245 occupancies
246 .init(system->maxMasters())
247 .flags(nozero | nonan)
248 ;
249 for (int i = 0; i < system->maxMasters(); i++) {
250 occupancies.subname(i, system->getMasterName(i));
251 }
252
253 avgOccs.flags(nozero | total);
254 for (int i = 0; i < system->maxMasters(); i++) {
255 avgOccs.subname(i, system->getMasterName(i));
256 }
257
258 avgOccs = occupancies / Stats::constant(tags.numBlocks);
259
260 occupanciesTaskId
261 .init(ContextSwitchTaskId::NumTaskId)
262 .flags(nozero | nonan)
263 ;
264
265 ageTaskId
266 .init(ContextSwitchTaskId::NumTaskId, 5)
267 .flags(nozero | nonan)
268 ;
269
270 percentOccsTaskId.flags(nozero);
271
272 percentOccsTaskId = occupanciesTaskId / Stats::constant(tags.numBlocks);
273 }
274
275 void
276 BaseTags::BaseTagStats::preDumpStats()
277 {
278 Stats::Group::preDumpStats();
279
280 tags.computeStats();
281 }