1/**
2 * Copyright (c) 2018 Metempsy Technology Consulting
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Javier Bueno
29 */
30
31#include "mem/cache/prefetch/irregular_stream_buffer.hh"
32
33#include "debug/HWPrefetch.hh"
34#include "mem/cache/prefetch/associative_set_impl.hh"
35#include "params/IrregularStreamBufferPrefetcher.hh"
36
37IrregularStreamBufferPrefetcher::IrregularStreamBufferPrefetcher(
38    const IrregularStreamBufferPrefetcherParams *p)
39    : QueuedPrefetcher(p),
40        chunkSize(p->chunk_size),
41        prefetchCandidatesPerEntry(p->prefetch_candidates_per_entry),
42        degree(p->degree),
43        trainingUnit(p->training_unit_assoc, p->training_unit_entries,
44                     p->training_unit_indexing_policy,
45                     p->training_unit_replacement_policy),
46        psAddressMappingCache(p->address_map_cache_assoc,
47                              p->address_map_cache_entries,
48                              p->ps_address_map_cache_indexing_policy,
49                              p->ps_address_map_cache_replacement_policy,
50                              AddressMappingEntry(prefetchCandidatesPerEntry,
51                                                  p->num_counter_bits)),
52        spAddressMappingCache(p->address_map_cache_assoc,
53                              p->address_map_cache_entries,
54                              p->sp_address_map_cache_indexing_policy,
55                              p->sp_address_map_cache_replacement_policy,
56                              AddressMappingEntry(prefetchCandidatesPerEntry,
57                                                  p->num_counter_bits)),
58        structuralAddressCounter(0)
59{
60    assert(isPowerOf2(prefetchCandidatesPerEntry));
61}
62
63void
64IrregularStreamBufferPrefetcher::calculatePrefetch(const PrefetchInfo &pfi,
65    std::vector<AddrPriority> &addresses)
66{
67    // This prefetcher requires a PC
68    if (!pfi.hasPC()) {
69        return;
70    }
71    bool is_secure = pfi.isSecure();
72    Addr pc = pfi.getPC();
73    Addr addr = blockIndex(pfi.getAddr());
74
75    // Training, if the entry exists, then we found a correlation between
76    // the entry lastAddress (named as correlated_addr_A) and the address of
77    // the current access (named as correlated_addr_B)
78    TrainingUnitEntry *entry = trainingUnit.findEntry(pc, is_secure);
79    bool correlated_addr_found = false;
80    Addr correlated_addr_A = 0;
81    Addr correlated_addr_B = 0;
82    if (entry != nullptr && entry->lastAddressSecure == is_secure) {
83        trainingUnit.accessEntry(entry);
84        correlated_addr_found = true;
85        correlated_addr_A = entry->lastAddress;
86        correlated_addr_B = addr;
87    } else {
88        entry = trainingUnit.findVictim(pc);
89        assert(entry != nullptr);
90
91        trainingUnit.insertEntry(pc, is_secure, entry);
92    }
93    // Update the entry
94    entry->lastAddress = addr;
95    entry->lastAddressSecure = is_secure;
96
97    if (correlated_addr_found) {
98        // If a correlation was found, update the Physical-to-Structural
99        // table accordingly
100        AddressMapping &mapping_A = getPSMapping(correlated_addr_A, is_secure);
101        AddressMapping &mapping_B = getPSMapping(correlated_addr_B, is_secure);
102        if (mapping_A.counter > 0 && mapping_B.counter > 0) {
103            // Entry for A and B
104            if (mapping_B.address == (mapping_A.address + 1)) {
105                mapping_B.counter++;
106            } else {
107                if (mapping_B.counter == 1) {
108                    // Counter would hit 0, reassign address while keeping
109                    // counter at 1
110                    mapping_B.address = mapping_A.address + 1;
111                    addStructuralToPhysicalEntry(mapping_B.address, is_secure,
112                            correlated_addr_B);
113                } else {
114                    mapping_B.counter--;
115                }
116            }
117        } else {
118            if (mapping_A.counter == 0) {
119                // if A is not valid, generate a new structural address
120                mapping_A.counter++;
121                mapping_A.address = structuralAddressCounter;
122                structuralAddressCounter += chunkSize;
123                addStructuralToPhysicalEntry(mapping_A.address,
124                        is_secure, correlated_addr_A);
125            }
126            mapping_B.counter.reset();
127            mapping_B.counter++;
128            mapping_B.address = mapping_A.address + 1;
129            // update SP-AMC
130            addStructuralToPhysicalEntry(mapping_B.address, is_secure,
131                    correlated_addr_B);
132        }
133    }
134
135    // Use the PS mapping to predict future accesses using the current address
136    // - Look for the structured address
137    // - if it exists, use it to generate prefetches for the subsequent
138    //   addresses in ascending order, as many as indicated by the degree
139    //   (given the structured address S, prefetch S+1, S+2, .. up to S+degree)
140    Addr amc_address = addr / prefetchCandidatesPerEntry;
141    Addr map_index   = addr % prefetchCandidatesPerEntry;
142    AddressMappingEntry *ps_am = psAddressMappingCache.findEntry(amc_address,
143                                                                 is_secure);
144    if (ps_am != nullptr) {
145        AddressMapping &mapping = ps_am->mappings[map_index];
146        if (mapping.counter > 0) {
147            Addr sp_address = mapping.address / prefetchCandidatesPerEntry;
148            Addr sp_index   = mapping.address % prefetchCandidatesPerEntry;
149            AddressMappingEntry *sp_am =
150                spAddressMappingCache.findEntry(sp_address, is_secure);
151            if (sp_am == nullptr) {
152                // The entry has been evicted, can not generate prefetches
153                return;
154            }
155            for (unsigned d = 1;
156                    d <= degree && (sp_index + d) < prefetchCandidatesPerEntry;
157                    d += 1)
158            {
159                AddressMapping &spm = sp_am->mappings[sp_index + d];
160                //generate prefetch
161                if (spm.counter > 0) {
162                    Addr pf_addr = spm.address << lBlkSize;
163                    addresses.push_back(AddrPriority(pf_addr, 0));
164                }
165            }
166        }
167    }
168}
169
170IrregularStreamBufferPrefetcher::AddressMapping&
171IrregularStreamBufferPrefetcher::getPSMapping(Addr paddr, bool is_secure)
172{
173    Addr amc_address = paddr / prefetchCandidatesPerEntry;
174    Addr map_index   = paddr % prefetchCandidatesPerEntry;
175    AddressMappingEntry *ps_entry =
176        psAddressMappingCache.findEntry(amc_address, is_secure);
177    if (ps_entry != nullptr) {
178        // A PS-AMC line already exists
179        psAddressMappingCache.accessEntry(ps_entry);
180    } else {
181        ps_entry = psAddressMappingCache.findVictim(amc_address);
182        assert(ps_entry != nullptr);
183
184        psAddressMappingCache.insertEntry(amc_address, is_secure, ps_entry);
185    }
186    return ps_entry->mappings[map_index];
187}
188
189void
190IrregularStreamBufferPrefetcher::addStructuralToPhysicalEntry(
191    Addr structural_address, bool is_secure, Addr physical_address)
192{
193    Addr amc_address = structural_address / prefetchCandidatesPerEntry;
194    Addr map_index   = structural_address % prefetchCandidatesPerEntry;
195    AddressMappingEntry *sp_entry =
196        spAddressMappingCache.findEntry(amc_address, is_secure);
197    if (sp_entry != nullptr) {
198        spAddressMappingCache.accessEntry(sp_entry);
199    } else {
200        sp_entry = spAddressMappingCache.findVictim(amc_address);
201        assert(sp_entry != nullptr);
202
203        spAddressMappingCache.insertEntry(amc_address, is_secure, sp_entry);
204    }
205    AddressMapping &mapping = sp_entry->mappings[map_index];
206    mapping.address = physical_address;
207    mapping.counter.reset();
208    mapping.counter++;
209}
210
211IrregularStreamBufferPrefetcher*
212IrregularStreamBufferPrefetcherParams::create()
213{
214    return new IrregularStreamBufferPrefetcher(this);
215}
216