2 * Copyright (c) 2018 Metempsy Technology Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "mem/cache/prefetch/access_map_pattern_matching.hh"
31 #include "debug/HWPrefetch.hh"
32 #include "mem/cache/prefetch/associative_set_impl.hh"
33 #include "params/AMPMPrefetcher.hh"
34 #include "params/AccessMapPatternMatching.hh"
36 namespace Prefetcher
{
38 AccessMapPatternMatching::AccessMapPatternMatching(
39 const AccessMapPatternMatchingParams
&p
)
40 : ClockedObject(p
), blkSize(p
.block_size
), limitStride(p
.limit_stride
),
41 startDegree(p
.start_degree
), hotZoneSize(p
.hot_zone_size
),
42 highCoverageThreshold(p
.high_coverage_threshold
),
43 lowCoverageThreshold(p
.low_coverage_threshold
),
44 highAccuracyThreshold(p
.high_accuracy_threshold
),
45 lowAccuracyThreshold(p
.low_accuracy_threshold
),
46 highCacheHitThreshold(p
.high_cache_hit_threshold
),
47 lowCacheHitThreshold(p
.low_cache_hit_threshold
),
48 epochCycles(p
.epoch_cycles
),
49 offChipMemoryLatency(p
.offchip_memory_latency
),
50 accessMapTable(p
.access_map_table_assoc
, p
.access_map_table_entries
,
51 p
.access_map_table_indexing_policy
,
52 p
.access_map_table_replacement_policy
,
53 AccessMapEntry(hotZoneSize
/ blkSize
)),
54 numGoodPrefetches(0), numTotalPrefetches(0), numRawCacheMisses(0),
55 numRawCacheHits(0), degree(startDegree
), usefulDegree(startDegree
),
56 epochEvent([this]{ processEpochEvent(); }, name())
58 fatal_if(!isPowerOf2(hotZoneSize
),
59 "the hot zone size must be a power of 2");
63 AccessMapPatternMatching::startup()
65 schedule(epochEvent
, clockEdge(epochCycles
));
69 AccessMapPatternMatching::processEpochEvent()
71 schedule(epochEvent
, clockEdge(epochCycles
));
72 double prefetch_accuracy
=
73 ((double) numGoodPrefetches
) / ((double) numTotalPrefetches
);
74 double prefetch_coverage
=
75 ((double) numGoodPrefetches
) / ((double) numRawCacheMisses
);
76 double cache_hit_ratio
= ((double) numRawCacheHits
) /
77 ((double) (numRawCacheHits
+ numRawCacheMisses
));
78 double num_requests
= (double) (numRawCacheMisses
- numGoodPrefetches
+
80 double memory_bandwidth
= num_requests
* offChipMemoryLatency
/
81 clockEdge(epochCycles
);
83 if (prefetch_coverage
> highCoverageThreshold
&&
84 (prefetch_accuracy
> highAccuracyThreshold
||
85 cache_hit_ratio
< lowCacheHitThreshold
)) {
87 } else if ((prefetch_coverage
< lowCoverageThreshold
&&
88 (prefetch_accuracy
< lowAccuracyThreshold
||
89 cache_hit_ratio
> highCacheHitThreshold
)) ||
90 (prefetch_accuracy
< lowAccuracyThreshold
&&
91 cache_hit_ratio
> highCacheHitThreshold
)) {
94 degree
= std::min((unsigned) memory_bandwidth
, usefulDegree
);
96 numGoodPrefetches
= 0.0;
97 numTotalPrefetches
= 0.0;
98 numRawCacheMisses
= 0.0;
99 numRawCacheHits
= 0.0;
102 AccessMapPatternMatching::AccessMapEntry
*
103 AccessMapPatternMatching::getAccessMapEntry(Addr am_addr
,
106 AccessMapEntry
*am_entry
= accessMapTable
.findEntry(am_addr
, is_secure
);
107 if (am_entry
!= nullptr) {
108 accessMapTable
.accessEntry(am_entry
);
110 am_entry
= accessMapTable
.findVictim(am_addr
);
111 assert(am_entry
!= nullptr);
113 accessMapTable
.insertEntry(am_addr
, is_secure
, am_entry
);
119 AccessMapPatternMatching::setEntryState(AccessMapEntry
&entry
,
120 Addr block
, enum AccessMapState state
)
122 enum AccessMapState old
= entry
.states
[block
];
123 entry
.states
[block
] = state
;
125 //do not update stats when initializing
126 if (state
== AM_INIT
) return;
130 if (state
== AM_PREFETCH
) {
131 numTotalPrefetches
+= 1;
132 } else if (state
== AM_ACCESS
) {
133 numRawCacheMisses
+= 1;
137 if (state
== AM_ACCESS
) {
138 numGoodPrefetches
+= 1;
139 numRawCacheMisses
+= 1;
143 if (state
== AM_ACCESS
) {
144 numRawCacheHits
+= 1;
148 panic("Impossible path\n");
154 AccessMapPatternMatching::calculatePrefetch(const Base::PrefetchInfo
&pfi
,
155 std::vector
<Queued::AddrPriority
> &addresses
)
157 assert(addresses
.empty());
159 bool is_secure
= pfi
.isSecure();
160 Addr am_addr
= pfi
.getAddr() / hotZoneSize
;
161 Addr current_block
= (pfi
.getAddr() % hotZoneSize
) / blkSize
;
162 uint64_t lines_per_zone
= hotZoneSize
/ blkSize
;
164 // Get the entries of the curent block (am_addr), the previous, and the
166 AccessMapEntry
*am_entry_curr
= getAccessMapEntry(am_addr
, is_secure
);
167 AccessMapEntry
*am_entry_prev
= (am_addr
> 0) ?
168 getAccessMapEntry(am_addr
-1, is_secure
) : nullptr;
169 AccessMapEntry
*am_entry_next
= (am_addr
< (MaxAddr
/hotZoneSize
)) ?
170 getAccessMapEntry(am_addr
+1, is_secure
) : nullptr;
171 assert(am_entry_curr
!= am_entry_prev
);
172 assert(am_entry_curr
!= am_entry_next
);
173 assert(am_entry_prev
!= am_entry_next
);
174 assert(am_entry_curr
!= nullptr);
176 //Mark the current access as Accessed
177 setEntryState(*am_entry_curr
, current_block
, AM_ACCESS
);
180 * Create a contiguous copy of the 3 entries states.
181 * With this, we avoid doing boundaries checking in the loop that looks
182 * for prefetch candidates, mark out of range positions with AM_INVALID
184 std::vector
<AccessMapState
> states(3 * lines_per_zone
);
185 for (unsigned idx
= 0; idx
< lines_per_zone
; idx
+= 1) {
187 am_entry_prev
!= nullptr ? am_entry_prev
->states
[idx
] : AM_INVALID
;
188 states
[idx
+ lines_per_zone
] = am_entry_curr
->states
[idx
];
189 states
[idx
+ 2 * lines_per_zone
] =
190 am_entry_next
!= nullptr ? am_entry_next
->states
[idx
] : AM_INVALID
;
194 * am_entry_prev->states => states[ 0 .. lines_per_zone-1]
195 * am_entry_curr->states => states[ lines_per_zone .. 2*lines_per_zone-1]
196 * am_entry_next->states => states[2*lines_per_zone .. 3*lines_per_zone-1]
199 // index of the current_block in the new vector
200 Addr states_current_block
= current_block
+ lines_per_zone
;
201 // consider strides 1..lines_per_zone/2
202 int max_stride
= limitStride
== 0 ? lines_per_zone
/ 2 : limitStride
+ 1;
203 for (int stride
= 1; stride
< max_stride
; stride
+= 1) {
204 // Test accessed positive strides
205 if (checkCandidate(states
, states_current_block
, stride
)) {
206 // candidate found, current_block - stride
208 if (stride
> current_block
) {
209 // The index (current_block - stride) falls in the range of
210 // the previous zone (am_entry_prev), adjust the address
212 Addr blk
= states_current_block
- stride
;
213 pf_addr
= (am_addr
- 1) * hotZoneSize
+ blk
* blkSize
;
214 setEntryState(*am_entry_prev
, blk
, AM_PREFETCH
);
216 // The index (current_block - stride) falls within
218 Addr blk
= current_block
- stride
;
219 pf_addr
= am_addr
* hotZoneSize
+ blk
* blkSize
;
220 setEntryState(*am_entry_curr
, blk
, AM_PREFETCH
);
222 addresses
.push_back(Queued::AddrPriority(pf_addr
, 0));
223 if (addresses
.size() == degree
) {
228 // Test accessed negative strides
229 if (checkCandidate(states
, states_current_block
, -stride
)) {
230 // candidate found, current_block + stride
232 if (current_block
+ stride
>= lines_per_zone
) {
233 // The index (current_block + stride) falls in the range of
234 // the next zone (am_entry_next), adjust the address
236 Addr blk
= (states_current_block
+ stride
) % lines_per_zone
;
237 pf_addr
= (am_addr
+ 1) * hotZoneSize
+ blk
* blkSize
;
238 setEntryState(*am_entry_next
, blk
, AM_PREFETCH
);
240 // The index (current_block + stride) falls within
242 Addr blk
= current_block
+ stride
;
243 pf_addr
= am_addr
* hotZoneSize
+ blk
* blkSize
;
244 setEntryState(*am_entry_curr
, blk
, AM_PREFETCH
);
246 addresses
.push_back(Queued::AddrPriority(pf_addr
, 0));
247 if (addresses
.size() == degree
) {
254 AMPM::AMPM(const AMPMPrefetcherParams
&p
)
255 : Queued(p
), ampm(*p
.ampm
)
260 AMPM::calculatePrefetch(const PrefetchInfo
&pfi
,
261 std::vector
<AddrPriority
> &addresses
)
263 ampm
.calculatePrefetch(pfi
, addresses
);
266 } // namespace Prefetcher
268 Prefetcher::AccessMapPatternMatching
*
269 AccessMapPatternMatchingParams::create() const
271 return new Prefetcher::AccessMapPatternMatching(*this);
275 AMPMPrefetcherParams::create() const
277 return new Prefetcher::AMPM(*this);