mem: Change warmupCycle stat to warmupTick
[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
41 /**
42 * @file
43 * Definitions of BaseTags.
44 */
45
46 #include "mem/cache/tags/base.hh"
47
48 #include <cassert>
49
50 #include "base/types.hh"
51 #include "mem/cache/replacement_policies/replaceable_entry.hh"
52 #include "mem/cache/tags/indexing_policies/base.hh"
53 #include "mem/request.hh"
54 #include "sim/core.hh"
55 #include "sim/sim_exit.hh"
56 #include "sim/system.hh"
57
58 BaseTags::BaseTags(const Params &p)
59 : ClockedObject(p), blkSize(p.block_size), blkMask(blkSize - 1),
60 size(p.size), lookupLatency(p.tag_latency),
61 system(p.system), indexingPolicy(p.indexing_policy),
62 warmupBound((p.warmup_percentage/100.0) * (p.size / p.block_size)),
63 warmedUp(false), numBlocks(p.size / p.block_size),
64 dataBlks(new uint8_t[p.size]), // Allocate data storage in one big chunk
65 stats(*this)
66 {
67 registerExitCallback([this]() { cleanupRefs(); });
68 }
69
70 ReplaceableEntry*
71 BaseTags::findBlockBySetAndWay(int set, int way) const
72 {
73 return indexingPolicy->getEntry(set, way);
74 }
75
76 CacheBlk*
77 BaseTags::findBlock(Addr addr, bool is_secure) const
78 {
79 // Extract block tag
80 Addr tag = extractTag(addr);
81
82 // Find possible entries that may contain the given address
83 const std::vector<ReplaceableEntry*> entries =
84 indexingPolicy->getPossibleEntries(addr);
85
86 // Search for block
87 for (const auto& location : entries) {
88 CacheBlk* blk = static_cast<CacheBlk*>(location);
89 if (blk->matchTag(tag, is_secure)) {
90 return blk;
91 }
92 }
93
94 // Did not find block
95 return nullptr;
96 }
97
98 void
99 BaseTags::insertBlock(const PacketPtr pkt, CacheBlk *blk)
100 {
101 assert(!blk->isValid());
102
103 // Previous block, if existed, has been removed, and now we have
104 // to insert the new one
105
106 // Deal with what we are bringing in
107 RequestorID requestor_id = pkt->req->requestorId();
108 assert(requestor_id < system->maxRequestors());
109 stats.occupancies[requestor_id]++;
110
111 // Insert block with tag, src requestor id and task id
112 blk->insert(extractTag(pkt->getAddr()), pkt->isSecure(), requestor_id,
113 pkt->req->taskId());
114
115 // Check if cache warm up is done
116 if (!warmedUp && stats.tagsInUse.value() >= warmupBound) {
117 warmedUp = true;
118 stats.warmupTick = curTick();
119 }
120
121 // We only need to write into one tag and one data block.
122 stats.tagAccesses += 1;
123 stats.dataAccesses += 1;
124 }
125
126 void
127 BaseTags::moveBlock(CacheBlk *src_blk, CacheBlk *dest_blk)
128 {
129 assert(!dest_blk->isValid());
130 assert(src_blk->isValid());
131
132 // Move src's contents to dest's
133 *dest_blk = std::move(*src_blk);
134
135 assert(dest_blk->isValid());
136 assert(!src_blk->isValid());
137 }
138
139 Addr
140 BaseTags::extractTag(const Addr addr) const
141 {
142 return indexingPolicy->extractTag(addr);
143 }
144
145 void
146 BaseTags::cleanupRefsVisitor(CacheBlk &blk)
147 {
148 if (blk.isValid()) {
149 stats.totalRefs += blk.getRefCount();
150 ++stats.sampledRefs;
151 }
152 }
153
154 void
155 BaseTags::cleanupRefs()
156 {
157 forEachBlk([this](CacheBlk &blk) { cleanupRefsVisitor(blk); });
158 }
159
160 void
161 BaseTags::computeStatsVisitor(CacheBlk &blk)
162 {
163 if (blk.isValid()) {
164 const uint32_t task_id = blk.getTaskId();
165 assert(task_id < ContextSwitchTaskId::NumTaskId);
166 stats.occupanciesTaskId[task_id]++;
167 Tick age = blk.getAge();
168
169 int age_index;
170 if (age / SimClock::Int::us < 10) { // <10us
171 age_index = 0;
172 } else if (age / SimClock::Int::us < 100) { // <100us
173 age_index = 1;
174 } else if (age / SimClock::Int::ms < 1) { // <1ms
175 age_index = 2;
176 } else if (age / SimClock::Int::ms < 10) { // <10ms
177 age_index = 3;
178 } else
179 age_index = 4; // >10ms
180
181 stats.ageTaskId[task_id][age_index]++;
182 }
183 }
184
185 void
186 BaseTags::computeStats()
187 {
188 for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
189 stats.occupanciesTaskId[i] = 0;
190 for (unsigned j = 0; j < 5; ++j) {
191 stats.ageTaskId[i][j] = 0;
192 }
193 }
194
195 forEachBlk([this](CacheBlk &blk) { computeStatsVisitor(blk); });
196 }
197
198 std::string
199 BaseTags::print()
200 {
201 std::string str;
202
203 auto print_blk = [&str](CacheBlk &blk) {
204 if (blk.isValid())
205 str += csprintf("\tBlock: %s\n", blk.print());
206 };
207 forEachBlk(print_blk);
208
209 if (str.empty())
210 str = "no valid tags\n";
211
212 return str;
213 }
214
215 BaseTags::BaseTagStats::BaseTagStats(BaseTags &_tags)
216 : Stats::Group(&_tags),
217 tags(_tags),
218
219 ADD_STAT(tagsInUse, UNIT_RATE(Stats::Units::Tick, Stats::Units::Count),
220 "Average ticks per tags in use"),
221 ADD_STAT(totalRefs, UNIT_COUNT,
222 "Total number of references to valid blocks."),
223 ADD_STAT(sampledRefs, UNIT_COUNT,
224 "Sample count of references to valid blocks."),
225 ADD_STAT(avgRefs, UNIT_RATE(Stats::Units::Count, Stats::Units::Count),
226 "Average number of references to valid blocks."),
227 ADD_STAT(warmupTick, UNIT_TICK,
228 "The tick when the warmup percentage was hit."),
229 ADD_STAT(occupancies, UNIT_RATE(Stats::Units::Count, Stats::Units::Tick),
230 "Average occupied blocks per tick, per requestor"),
231 ADD_STAT(avgOccs, UNIT_RATE(Stats::Units::Ratio, Stats::Units::Tick),
232 "Average percentage of cache occupancy"),
233 ADD_STAT(occupanciesTaskId, UNIT_COUNT, "Occupied blocks per task id"),
234 ADD_STAT(ageTaskId, UNIT_COUNT,
235 "Occupied blocks per task id, per block age"),
236 ADD_STAT(ratioOccsTaskId, UNIT_RATIO,
237 "Ratio of occupied blocks and all blocks, per task id"),
238 ADD_STAT(tagAccesses, UNIT_COUNT, "Number of tag accesses"),
239 ADD_STAT(dataAccesses, UNIT_COUNT, "Number of data accesses")
240 {
241 }
242
243 void
244 BaseTags::BaseTagStats::regStats()
245 {
246 using namespace Stats;
247
248 Stats::Group::regStats();
249
250 System *system = tags.system;
251
252 avgRefs = totalRefs / sampledRefs;
253
254 occupancies
255 .init(system->maxRequestors())
256 .flags(nozero | nonan)
257 ;
258 for (int i = 0; i < system->maxRequestors(); i++) {
259 occupancies.subname(i, system->getRequestorName(i));
260 }
261
262 avgOccs.flags(nozero | total);
263 for (int i = 0; i < system->maxRequestors(); i++) {
264 avgOccs.subname(i, system->getRequestorName(i));
265 }
266
267 avgOccs = occupancies / Stats::constant(tags.numBlocks);
268
269 occupanciesTaskId
270 .init(ContextSwitchTaskId::NumTaskId)
271 .flags(nozero | nonan)
272 ;
273
274 ageTaskId
275 .init(ContextSwitchTaskId::NumTaskId, 5)
276 .flags(nozero | nonan)
277 ;
278
279 ratioOccsTaskId.flags(nozero);
280
281 ratioOccsTaskId = occupanciesTaskId / Stats::constant(tags.numBlocks);
282 }
283
284 void
285 BaseTags::BaseTagStats::preDumpStats()
286 {
287 Stats::Group::preDumpStats();
288
289 tags.computeStats();
290 }