| /** | |
| * Copyright (c) 2018 Metempsy Technology Consulting | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Javier Bueno | |
| */ | |
| #include "mem/cache/prefetch/irregular_stream_buffer.hh" | |
| #include "debug/HWPrefetch.hh" | |
| #include "mem/cache/prefetch/associative_set_impl.hh" | |
| #include "params/IrregularStreamBufferPrefetcher.hh" | |
| IrregularStreamBufferPrefetcher::IrregularStreamBufferPrefetcher( | |
| const IrregularStreamBufferPrefetcherParams *p) | |
| : QueuedPrefetcher(p), | |
| chunkSize(p->chunk_size), | |
| prefetchCandidatesPerEntry(p->prefetch_candidates_per_entry), | |
| degree(p->degree), | |
| trainingUnit(p->training_unit_assoc, p->training_unit_entries, | |
| p->training_unit_indexing_policy, | |
| p->training_unit_replacement_policy), | |
| psAddressMappingCache(p->address_map_cache_assoc, | |
| p->address_map_cache_entries, | |
| p->ps_address_map_cache_indexing_policy, | |
| p->ps_address_map_cache_replacement_policy, | |
| AddressMappingEntry(prefetchCandidatesPerEntry, | |
| p->num_counter_bits)), | |
| spAddressMappingCache(p->address_map_cache_assoc, | |
| p->address_map_cache_entries, | |
| p->sp_address_map_cache_indexing_policy, | |
| p->sp_address_map_cache_replacement_policy, | |
| AddressMappingEntry(prefetchCandidatesPerEntry, | |
| p->num_counter_bits)), | |
| structuralAddressCounter(0) | |
| { | |
| assert(isPowerOf2(prefetchCandidatesPerEntry)); | |
| } | |
| void | |
| IrregularStreamBufferPrefetcher::calculatePrefetch(const PrefetchInfo &pfi, | |
| std::vector<AddrPriority> &addresses) | |
| { | |
| // This prefetcher requires a PC | |
| if (!pfi.hasPC()) { | |
| return; | |
| } | |
| bool is_secure = pfi.isSecure(); | |
| Addr pc = pfi.getPC(); | |
| Addr addr = blockIndex(pfi.getAddr()); | |
| // Training, if the entry exists, then we found a correlation between | |
| // the entry lastAddress (named as correlated_addr_A) and the address of | |
| // the current access (named as correlated_addr_B) | |
| TrainingUnitEntry *entry = trainingUnit.findEntry(pc, is_secure); | |
| bool correlated_addr_found = false; | |
| Addr correlated_addr_A = 0; | |
| Addr correlated_addr_B = 0; | |
| if (entry != nullptr && entry->lastAddressSecure == is_secure) { | |
| trainingUnit.accessEntry(entry); | |
| correlated_addr_found = true; | |
| correlated_addr_A = entry->lastAddress; | |
| correlated_addr_B = addr; | |
| } else { | |
| entry = trainingUnit.findVictim(pc); | |
| assert(entry != nullptr); | |
| trainingUnit.insertEntry(pc, is_secure, entry); | |
| } | |
| // Update the entry | |
| entry->lastAddress = addr; | |
| entry->lastAddressSecure = is_secure; | |
| if (correlated_addr_found) { | |
| // If a correlation was found, update the Physical-to-Structural | |
| // table accordingly | |
| AddressMapping &mapping_A = getPSMapping(correlated_addr_A, is_secure); | |
| AddressMapping &mapping_B = getPSMapping(correlated_addr_B, is_secure); | |
| if (mapping_A.counter > 0 && mapping_B.counter > 0) { | |
| // Entry for A and B | |
| if (mapping_B.address == (mapping_A.address + 1)) { | |
| mapping_B.counter++; | |
| } else { | |
| if (mapping_B.counter == 1) { | |
| // Counter would hit 0, reassign address while keeping | |
| // counter at 1 | |
| mapping_B.address = mapping_A.address + 1; | |
| addStructuralToPhysicalEntry(mapping_B.address, is_secure, | |
| correlated_addr_B); | |
| } else { | |
| mapping_B.counter--; | |
| } | |
| } | |
| } else { | |
| if (mapping_A.counter == 0) { | |
| // if A is not valid, generate a new structural address | |
| mapping_A.counter++; | |
| mapping_A.address = structuralAddressCounter; | |
| structuralAddressCounter += chunkSize; | |
| addStructuralToPhysicalEntry(mapping_A.address, | |
| is_secure, correlated_addr_A); | |
| } | |
| mapping_B.counter.reset(); | |
| mapping_B.counter++; | |
| mapping_B.address = mapping_A.address + 1; | |
| // update SP-AMC | |
| addStructuralToPhysicalEntry(mapping_B.address, is_secure, | |
| correlated_addr_B); | |
| } | |
| } | |
| // Use the PS mapping to predict future accesses using the current address | |
| // - Look for the structured address | |
| // - if it exists, use it to generate prefetches for the subsequent | |
| // addresses in ascending order, as many as indicated by the degree | |
| // (given the structured address S, prefetch S+1, S+2, .. up to S+degree) | |
| Addr amc_address = addr / prefetchCandidatesPerEntry; | |
| Addr map_index = addr % prefetchCandidatesPerEntry; | |
| AddressMappingEntry *ps_am = psAddressMappingCache.findEntry(amc_address, | |
| is_secure); | |
| if (ps_am != nullptr) { | |
| AddressMapping &mapping = ps_am->mappings[map_index]; | |
| if (mapping.counter > 0) { | |
| Addr sp_address = mapping.address / prefetchCandidatesPerEntry; | |
| Addr sp_index = mapping.address % prefetchCandidatesPerEntry; | |
| AddressMappingEntry *sp_am = | |
| spAddressMappingCache.findEntry(sp_address, is_secure); | |
| if (sp_am == nullptr) { | |
| // The entry has been evicted, can not generate prefetches | |
| return; | |
| } | |
| for (unsigned d = 1; | |
| d <= degree && (sp_index + d) < prefetchCandidatesPerEntry; | |
| d += 1) | |
| { | |
| AddressMapping &spm = sp_am->mappings[sp_index + d]; | |
| //generate prefetch | |
| if (spm.counter > 0) { | |
| Addr pf_addr = spm.address << lBlkSize; | |
| addresses.push_back(AddrPriority(pf_addr, 0)); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| IrregularStreamBufferPrefetcher::AddressMapping& | |
| IrregularStreamBufferPrefetcher::getPSMapping(Addr paddr, bool is_secure) | |
| { | |
| Addr amc_address = paddr / prefetchCandidatesPerEntry; | |
| Addr map_index = paddr % prefetchCandidatesPerEntry; | |
| AddressMappingEntry *ps_entry = | |
| psAddressMappingCache.findEntry(amc_address, is_secure); | |
| if (ps_entry != nullptr) { | |
| // A PS-AMC line already exists | |
| psAddressMappingCache.accessEntry(ps_entry); | |
| } else { | |
| ps_entry = psAddressMappingCache.findVictim(amc_address); | |
| assert(ps_entry != nullptr); | |
| psAddressMappingCache.insertEntry(amc_address, is_secure, ps_entry); | |
| } | |
| return ps_entry->mappings[map_index]; | |
| } | |
| void | |
| IrregularStreamBufferPrefetcher::addStructuralToPhysicalEntry( | |
| Addr structural_address, bool is_secure, Addr physical_address) | |
| { | |
| Addr amc_address = structural_address / prefetchCandidatesPerEntry; | |
| Addr map_index = structural_address % prefetchCandidatesPerEntry; | |
| AddressMappingEntry *sp_entry = | |
| spAddressMappingCache.findEntry(amc_address, is_secure); | |
| if (sp_entry != nullptr) { | |
| spAddressMappingCache.accessEntry(sp_entry); | |
| } else { | |
| sp_entry = spAddressMappingCache.findVictim(amc_address); | |
| assert(sp_entry != nullptr); | |
| spAddressMappingCache.insertEntry(amc_address, is_secure, sp_entry); | |
| } | |
| AddressMapping &mapping = sp_entry->mappings[map_index]; | |
| mapping.address = physical_address; | |
| mapping.counter.reset(); | |
| mapping.counter++; | |
| } | |
| IrregularStreamBufferPrefetcher* | |
| IrregularStreamBufferPrefetcherParams::create() | |
| { | |
| return new IrregularStreamBufferPrefetcher(this); | |
| } |