From: Ayaz Akram Date: Tue, 5 May 2020 04:11:38 +0000 (-0700) Subject: mem-ruby: Deep renaming of Prefetcher to RubyPrefetcher X-Git-Tag: v20.0.0.0~54 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4f1c4147decd8c8b08e2cef2342fa25224cf4225;p=gem5.git mem-ruby: Deep renaming of Prefetcher to RubyPrefetcher A recent change (https://gem5-review.googlesource.com/c/ public/gem5/+/27949) updated the ruby prefetcher name, which breaks the use of old name in some SLICC files. This change makes sure that the new name is used at all places. Issue-On: https://gem5.atlassian.net/browse/GEM5-498 Change-Id: Ic667b61eac13dc7c267cee7dce3aa970f7ae9a8b Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28667 Reviewed-by: Timothy Hayes Maintainer: Jason Lowe-Power Tested-by: kokoro --- diff --git a/configs/ruby/MESI_Three_Level.py b/configs/ruby/MESI_Three_Level.py index 61d6c523b..0bd893e38 100644 --- a/configs/ruby/MESI_Three_Level.py +++ b/configs/ruby/MESI_Three_Level.py @@ -121,7 +121,7 @@ def create_system(options, full_system, system, dma_ports, bootmem, clk_domain = system.cpu[i].clk_domain # Ruby prefetcher - prefetcher = RubyPrefetcher.Prefetcher( + prefetcher = RubyPrefetcher( num_streams=16, unit_filter = 256, nonunit_filter = 256, diff --git a/configs/ruby/MESI_Two_Level.py b/configs/ruby/MESI_Two_Level.py index 8d2e01fb6..3ddf8eff7 100644 --- a/configs/ruby/MESI_Two_Level.py +++ b/configs/ruby/MESI_Two_Level.py @@ -78,7 +78,7 @@ def create_system(options, full_system, system, dma_ports, bootmem, start_index_bit = block_size_bits, is_icache = False) - prefetcher = RubyPrefetcher.Prefetcher() + prefetcher = RubyPrefetcher() # the ruby random tester reuses num_cpus to specify the # number of cpu ports connected to the tester object, which diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript index 8c22ae495..fc90f8a62 100644 --- a/src/mem/ruby/SConscript +++ b/src/mem/ruby/SConscript @@ -126,7 +126,7 @@ MakeInclude('structures/CacheMemory.hh') MakeInclude('structures/DirectoryMemory.hh') MakeInclude('structures/PerfectCacheMemory.hh') MakeInclude('structures/PersistentTable.hh') -MakeInclude('structures/Prefetcher.hh') +MakeInclude('structures/RubyPrefetcher.hh') MakeInclude('structures/TBETable.hh') MakeInclude('structures/TimerTable.hh') MakeInclude('structures/WireBuffer.hh') diff --git a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm index 3639ef2c5..4de4a293e 100644 --- a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm +++ b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm @@ -46,7 +46,7 @@ machine(MachineType:L0Cache, "MESI Directory L0 Cache") Cycles response_latency := 2; bool send_evictions; - Prefetcher * prefetcher; + RubyPrefetcher * prefetcher; bool enable_prefetch := "False"; // From this node's L0 cache to the network diff --git a/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm b/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm index 7c83478db..3e3580f70 100644 --- a/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm +++ b/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm @@ -30,7 +30,7 @@ machine(MachineType:L1Cache, "MESI Directory L1 Cache CMP") : Sequencer * sequencer; CacheMemory * L1Icache; CacheMemory * L1Dcache; - Prefetcher * prefetcher; + RubyPrefetcher * prefetcher; int l2_select_num_bits; Cycles l1_request_latency := 2; Cycles l1_response_latency := 2; diff --git a/src/mem/ruby/protocol/RubySlicc_Types.sm b/src/mem/ruby/protocol/RubySlicc_Types.sm index 66d84fca3..6ab0f3f76 100644 --- a/src/mem/ruby/protocol/RubySlicc_Types.sm +++ b/src/mem/ruby/protocol/RubySlicc_Types.sm @@ -246,7 +246,7 @@ structure (TimerTable, inport="yes", external = "yes") { bool isSet(Addr); } -structure (Prefetcher, external = "yes") { +structure (RubyPrefetcher, external = "yes") { void observeMiss(Addr, RubyRequestType); void observePfHit(Addr); void observePfMiss(Addr); diff --git a/src/mem/ruby/structures/Prefetcher.cc b/src/mem/ruby/structures/Prefetcher.cc deleted file mode 100644 index 06021159c..000000000 --- a/src/mem/ruby/structures/Prefetcher.cc +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (c) 2020 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood - * 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. - */ - -#include "mem/ruby/structures/Prefetcher.hh" - -#include "base/bitfield.hh" -#include "debug/RubyPrefetcher.hh" -#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" -#include "mem/ruby/system/RubySystem.hh" - -RubyPrefetcher* -PrefetcherParams::create() -{ - return new RubyPrefetcher(this); -} - -RubyPrefetcher::RubyPrefetcher(const Params *p) - : SimObject(p), m_num_streams(p->num_streams), - m_array(p->num_streams), m_train_misses(p->train_misses), - m_num_startup_pfs(p->num_startup_pfs), m_num_unit_filters(p->unit_filter), - m_num_nonunit_filters(p->nonunit_filter), - m_unit_filter(p->unit_filter, 0), - m_negative_filter(p->unit_filter, 0), - m_nonunit_filter(p->nonunit_filter, 0), - m_prefetch_cross_pages(p->cross_page), - m_page_shift(p->sys->getPageShift()) -{ - assert(m_num_streams > 0); - assert(m_num_startup_pfs <= MAX_PF_INFLIGHT); - - // create +1 stride filter - m_unit_filter_index = 0; - m_unit_filter_hit = new uint32_t[m_num_unit_filters]; - for (uint32_t i =0; i < m_num_unit_filters; i++) { - m_unit_filter_hit[i] = 0; - } - - // create -1 stride filter - m_negative_filter_index = 0; - m_negative_filter_hit = new uint32_t[m_num_unit_filters]; - for (int i =0; i < m_num_unit_filters; i++) { - m_negative_filter_hit[i] = 0; - } - - // create nonunit stride filter - m_nonunit_index = 0; - m_nonunit_stride = new int[m_num_nonunit_filters]; - m_nonunit_hit = new uint32_t[m_num_nonunit_filters]; - for (int i =0; i < m_num_nonunit_filters; i++) { - m_nonunit_stride[i] = 0; - m_nonunit_hit[i] = 0; - } -} - -RubyPrefetcher::~RubyPrefetcher() -{ - delete m_unit_filter_hit; - delete m_negative_filter_hit; - delete m_nonunit_stride; - delete m_nonunit_hit; -} - -void -RubyPrefetcher::regStats() -{ - SimObject::regStats(); - - numMissObserved - .name(name() + ".miss_observed") - .desc("number of misses observed") - ; - - numAllocatedStreams - .name(name() + ".allocated_streams") - .desc("number of streams allocated for prefetching") - ; - - numPrefetchRequested - .name(name() + ".prefetches_requested") - .desc("number of prefetch requests made") - ; - - numHits - .name(name() + ".hits") - .desc("number of prefetched blocks accessed (for the first time)") - ; - - numPartialHits - .name(name() + ".partial_hits") - .desc("number of misses observed for a block being prefetched") - ; - - numPagesCrossed - .name(name() + ".pages_crossed") - .desc("number of prefetches across pages") - ; - - numMissedPrefetchedBlocks - .name(name() + ".misses_on_prefetched_blocks") - .desc("number of misses for blocks that were prefetched, yet missed") - ; -} - -void -RubyPrefetcher::observeMiss(Addr address, const RubyRequestType& type) -{ - DPRINTF(RubyPrefetcher, "Observed miss for %#x\n", address); - Addr line_addr = makeLineAddress(address); - numMissObserved++; - - // check to see if we have already issued a prefetch for this block - uint32_t index = 0; - PrefetchEntry *pfEntry = getPrefetchEntry(line_addr, index); - if (pfEntry != NULL) { - if (pfEntry->requestIssued[index]) { - if (pfEntry->requestCompleted[index]) { - // We prefetched too early and now the prefetch block no - // longer exists in the cache - numMissedPrefetchedBlocks++; - return; - } else { - // The controller has issued the prefetch request, - // but the request for the block arrived earlier. - numPartialHits++; - observePfMiss(line_addr); - return; - } - } else { - // The request is still in the prefetch queue of the controller. - // Or was evicted because of other requests. - return; - } - } - - // check to see if this address is in the unit stride filter - bool alloc = false; - bool hit = accessUnitFilter(m_unit_filter, m_unit_filter_hit, - m_unit_filter_index, line_addr, 1, alloc); - if (alloc) { - // allocate a new prefetch stream - initializeStream(line_addr, 1, getLRUindex(), type); - } - if (hit) { - DPRINTF(RubyPrefetcher, " *** hit in unit stride buffer\n"); - return; - } - - hit = accessUnitFilter(m_negative_filter, m_negative_filter_hit, - m_negative_filter_index, line_addr, -1, alloc); - if (alloc) { - // allocate a new prefetch stream - initializeStream(line_addr, -1, getLRUindex(), type); - } - if (hit) { - DPRINTF(RubyPrefetcher, " *** hit in unit negative unit buffer\n"); - return; - } - - // check to see if this address is in the non-unit stride filter - int stride = 0; // NULL value - hit = accessNonunitFilter(address, &stride, alloc); - if (alloc) { - assert(stride != 0); // ensure non-zero stride prefetches - initializeStream(line_addr, stride, getLRUindex(), type); - } - if (hit) { - DPRINTF(RubyPrefetcher, " *** hit in non-unit stride buffer\n"); - return; - } -} - -void -RubyPrefetcher::observePfMiss(Addr address) -{ - numPartialHits++; - DPRINTF(RubyPrefetcher, "Observed partial hit for %#x\n", address); - issueNextPrefetch(address, NULL); -} - -void -RubyPrefetcher::observePfHit(Addr address) -{ - numHits++; - DPRINTF(RubyPrefetcher, "Observed hit for %#x\n", address); - issueNextPrefetch(address, NULL); -} - -void -RubyPrefetcher::issueNextPrefetch(Addr address, PrefetchEntry *stream) -{ - // get our corresponding stream fetcher - if (stream == NULL) { - uint32_t index = 0; - stream = getPrefetchEntry(address, index); - } - - // if (for some reason), this stream is unallocated, return. - if (stream == NULL) { - DPRINTF(RubyPrefetcher, "Unallocated stream, returning\n"); - return; - } - - // extend this prefetching stream by 1 (or more) - Addr page_addr = pageAddress(stream->m_address); - Addr line_addr = makeNextStrideAddress(stream->m_address, - stream->m_stride); - - // possibly stop prefetching at page boundaries - if (page_addr != pageAddress(line_addr)) { - if (!m_prefetch_cross_pages) { - // Deallocate the stream since we are not prefetching - // across page boundries - stream->m_is_valid = false; - return; - } - numPagesCrossed++; - } - - // launch next prefetch - numPrefetchRequested++; - stream->m_address = line_addr; - stream->m_use_time = m_controller->curCycle(); - DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr); - m_controller->enqueuePrefetch(line_addr, stream->m_type); -} - -uint32_t -RubyPrefetcher::getLRUindex(void) -{ - uint32_t lru_index = 0; - Cycles lru_access = m_array[lru_index].m_use_time; - - for (uint32_t i = 0; i < m_num_streams; i++) { - if (!m_array[i].m_is_valid) { - return i; - } - if (m_array[i].m_use_time < lru_access) { - lru_access = m_array[i].m_use_time; - lru_index = i; - } - } - - return lru_index; -} - -void -RubyPrefetcher::clearNonunitEntry(uint32_t index) -{ - m_nonunit_filter[index] = 0; - m_nonunit_stride[index] = 0; - m_nonunit_hit[index] = 0; -} - -void -RubyPrefetcher::initializeStream(Addr address, int stride, - uint32_t index, const RubyRequestType& type) -{ - numAllocatedStreams++; - - // initialize the stream prefetcher - PrefetchEntry *mystream = &(m_array[index]); - mystream->m_address = makeLineAddress(address); - mystream->m_stride = stride; - mystream->m_use_time = m_controller->curCycle(); - mystream->m_is_valid = true; - mystream->m_type = type; - - // create a number of initial prefetches for this stream - Addr page_addr = pageAddress(mystream->m_address); - Addr line_addr = makeLineAddress(mystream->m_address); - - // insert a number of prefetches into the prefetch table - for (int k = 0; k < m_num_startup_pfs; k++) { - line_addr = makeNextStrideAddress(line_addr, stride); - // possibly stop prefetching at page boundaries - if (page_addr != pageAddress(line_addr)) { - if (!m_prefetch_cross_pages) { - // deallocate this stream prefetcher - mystream->m_is_valid = false; - return; - } - numPagesCrossed++; - } - - // launch prefetch - numPrefetchRequested++; - DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr); - m_controller->enqueuePrefetch(line_addr, m_array[index].m_type); - } - - // update the address to be the last address prefetched - mystream->m_address = line_addr; -} - -PrefetchEntry * -RubyPrefetcher::getPrefetchEntry(Addr address, uint32_t &index) -{ - // search all streams for a match - for (int i = 0; i < m_num_streams; i++) { - // search all the outstanding prefetches for this stream - if (m_array[i].m_is_valid) { - for (int j = 0; j < m_num_startup_pfs; j++) { - if (makeNextStrideAddress(m_array[i].m_address, - -(m_array[i].m_stride*j)) == address) { - return &(m_array[i]); - } - } - } - } - return NULL; -} - -bool -RubyPrefetcher::accessUnitFilter(std::vector& filter_table, - uint32_t *filter_hit, uint32_t &index, Addr address, - int stride, bool &alloc) -{ - //reset the alloc flag - alloc = false; - - Addr line_addr = makeLineAddress(address); - for (int i = 0; i < m_num_unit_filters; i++) { - if (filter_table[i] == line_addr) { - filter_table[i] = makeNextStrideAddress(filter_table[i], stride); - filter_hit[i]++; - if (filter_hit[i] >= m_train_misses) { - alloc = true; - } - return true; - } - } - - // enter this address in the table - int local_index = index; - filter_table[local_index] = makeNextStrideAddress(line_addr, stride); - filter_hit[local_index] = 0; - local_index = local_index + 1; - if (local_index >= m_num_unit_filters) { - local_index = 0; - } - - index = local_index; - return false; -} - -bool -RubyPrefetcher::accessNonunitFilter(Addr address, int *stride, - bool &alloc) -{ - //reset the alloc flag - alloc = false; - - /// look for non-unit strides based on a (user-defined) page size - Addr page_addr = pageAddress(address); - Addr line_addr = makeLineAddress(address); - - for (uint32_t i = 0; i < m_num_nonunit_filters; i++) { - if (pageAddress(m_nonunit_filter[i]) == page_addr) { - // hit in the non-unit filter - // compute the actual stride (for this reference) - int delta = line_addr - m_nonunit_filter[i]; - - if (delta != 0) { - // no zero stride prefetches - // check that the stride matches (for the last N times) - if (delta == m_nonunit_stride[i]) { - // -> stride hit - // increment count (if > 2) allocate stream - m_nonunit_hit[i]++; - if (m_nonunit_hit[i] > m_train_misses) { - // This stride HAS to be the multiplicative constant of - // dataBlockBytes (bc makeNextStrideAddress is - // calculated based on this multiplicative constant!) - *stride = m_nonunit_stride[i] / - RubySystem::getBlockSizeBytes(); - - // clear this filter entry - clearNonunitEntry(i); - alloc = true; - } - } else { - // delta didn't match ... reset m_nonunit_hit count for - // this entry - m_nonunit_hit[i] = 0; - } - - // update the last address seen & the stride - m_nonunit_stride[i] = delta; - m_nonunit_filter[i] = line_addr; - return true; - } else { - return false; - } - } - } - - // not found: enter this address in the table - m_nonunit_filter[m_nonunit_index] = line_addr; - m_nonunit_stride[m_nonunit_index] = 0; - m_nonunit_hit[m_nonunit_index] = 0; - - m_nonunit_index = m_nonunit_index + 1; - if (m_nonunit_index >= m_num_nonunit_filters) { - m_nonunit_index = 0; - } - return false; -} - -void -RubyPrefetcher::print(std::ostream& out) const -{ - out << name() << " Prefetcher State\n"; - // print out unit filter - out << "unit table:\n"; - for (int i = 0; i < m_num_unit_filters; i++) { - out << m_unit_filter[i] << std::endl; - } - - out << "negative table:\n"; - for (int i = 0; i < m_num_unit_filters; i++) { - out << m_negative_filter[i] << std::endl; - } - - // print out non-unit stride filter - out << "non-unit table:\n"; - for (int i = 0; i < m_num_nonunit_filters; i++) { - out << m_nonunit_filter[i] << " " - << m_nonunit_stride[i] << " " - << m_nonunit_hit[i] << std::endl; - } - - // print out allocated stream buffers - out << "streams:\n"; - for (int i = 0; i < m_num_streams; i++) { - out << m_array[i].m_address << " " - << m_array[i].m_stride << " " - << m_array[i].m_is_valid << " " - << m_array[i].m_use_time << std::endl; - } -} - -Addr -RubyPrefetcher::pageAddress(Addr addr) const -{ - return mbits(addr, 63, m_page_shift); -} diff --git a/src/mem/ruby/structures/Prefetcher.hh b/src/mem/ruby/structures/Prefetcher.hh deleted file mode 100644 index 4d2513f78..000000000 --- a/src/mem/ruby/structures/Prefetcher.hh +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2020 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood - * 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. - */ - -#ifndef __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ -#define __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ - -// Implements Power 4 like prefetching - -#include - -#include "base/statistics.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/network/MessageBuffer.hh" -#include "mem/ruby/slicc_interface/AbstractController.hh" -#include "mem/ruby/slicc_interface/RubyRequest.hh" -#include "mem/ruby/system/RubySystem.hh" -#include "params/Prefetcher.hh" -#include "sim/sim_object.hh" -#include "sim/system.hh" - -#define MAX_PF_INFLIGHT 8 - -class PrefetchEntry -{ - public: - /// constructor - PrefetchEntry() - { - // default: 1 cache-line stride - m_stride = (1 << RubySystem::getBlockSizeBits()); - m_use_time = Cycles(0); - m_is_valid = false; - } - - //! The base address for the stream prefetch - Addr m_address; - - //! stride distance to get next address from - int m_stride; - - //! the last time that any prefetched request was used - Cycles m_use_time; - - //! valid bit for each stream - bool m_is_valid; - - //! L1D prefetches loads and stores - RubyRequestType m_type; - - //! Bitset for tracking prefetches for which addresses have been - //! issued, which ones have completed. - std::bitset requestIssued; - std::bitset requestCompleted; -}; - -class RubyPrefetcher : public SimObject -{ - public: - typedef PrefetcherParams Params; - RubyPrefetcher(const Params *p); - ~RubyPrefetcher(); - - void issueNextPrefetch(Addr address, PrefetchEntry *stream); - /** - * Implement the prefetch hit(miss) callback interface. - * These functions are called by the cache when it hits(misses) - * on a line with the line's prefetch bit set. If this address - * hits in m_array we will continue prefetching the stream. - */ - void observePfHit(Addr address); - void observePfMiss(Addr address); - - /** - * Observe a memory miss from the cache. - * - * @param address The physical address that missed out of the cache. - */ - void observeMiss(Addr address, const RubyRequestType& type); - - /** - * Print out some statistics - */ - void print(std::ostream& out) const; - void setController(AbstractController *_ctrl) - { m_controller = _ctrl; } - - void regStats(); - - private: - /** - * Returns an unused stream buffer (or if all are used, returns the - * least recently used (accessed) stream buffer). - * @return The index of the least recently used stream buffer. - */ - uint32_t getLRUindex(void); - - //! clear a non-unit stride prefetcher entry - void clearNonunitEntry(uint32_t index); - - //! allocate a new stream buffer at a specific index - void initializeStream(Addr address, int stride, - uint32_t index, const RubyRequestType& type); - - //! get pointer to the matching stream entry, returns NULL if not found - //! index holds the multiple of the stride this address is. - PrefetchEntry* getPrefetchEntry(Addr address, - uint32_t &index); - - /// access a unit stride filter to determine if there is a hit - bool accessUnitFilter(std::vector& filter_table, - uint32_t *hit_table, uint32_t &index, Addr address, - int stride, bool &alloc); - - /// access a unit stride filter to determine if there is a hit - bool accessNonunitFilter(Addr address, int *stride, - bool &alloc); - - /// determine the page aligned address - Addr pageAddress(Addr addr) const; - - //! number of prefetch streams available - uint32_t m_num_streams; - //! an array of the active prefetch streams - std::vector m_array; - - //! number of misses I must see before allocating a stream - uint32_t m_train_misses; - //! number of initial prefetches to startup a stream - uint32_t m_num_startup_pfs; - //! number of stride filters - uint32_t m_num_unit_filters; - //! number of non-stride filters - uint32_t m_num_nonunit_filters; - - /// a unit stride filter array: helps reduce BW requirement of - /// prefetching - std::vector m_unit_filter; - /// a round robin pointer into the unit filter group - uint32_t m_unit_filter_index; - //! An array used to count the of times particular filter entries - //! have been hit - uint32_t *m_unit_filter_hit; - - //! a negative unit stride filter array: helps reduce BW requirement - //! of prefetching - std::vector m_negative_filter; - /// a round robin pointer into the negative filter group - uint32_t m_negative_filter_index; - /// An array used to count the of times particular filter entries - /// have been hit - uint32_t *m_negative_filter_hit; - - /// a non-unit stride filter array: helps reduce BW requirement of - /// prefetching - std::vector m_nonunit_filter; - /// An array of strides (in # of cache lines) for the filter entries - int *m_nonunit_stride; - /// An array used to count the of times particular filter entries - /// have been hit - uint32_t *m_nonunit_hit; - /// a round robin pointer into the unit filter group - uint32_t m_nonunit_index; - - /// Used for allowing prefetches across pages. - bool m_prefetch_cross_pages; - - AbstractController *m_controller; - - const Addr m_page_shift; - - //! Count of accesses to the prefetcher - Stats::Scalar numMissObserved; - //! Count of prefetch streams allocated - Stats::Scalar numAllocatedStreams; - //! Count of prefetch requests made - Stats::Scalar numPrefetchRequested; - //! Count of successful prefetches - Stats::Scalar numHits; - //! Count of partial successful prefetches - Stats::Scalar numPartialHits; - //! Count of pages crossed - Stats::Scalar numPagesCrossed; - //! Count of misses incurred for blocks that were prefetched - Stats::Scalar numMissedPrefetchedBlocks; -}; - -#endif // __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ diff --git a/src/mem/ruby/structures/RubyPrefetcher.cc b/src/mem/ruby/structures/RubyPrefetcher.cc new file mode 100644 index 000000000..8646b9932 --- /dev/null +++ b/src/mem/ruby/structures/RubyPrefetcher.cc @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood + * 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. + */ + +#include "mem/ruby/structures/RubyPrefetcher.hh" + +#include "base/bitfield.hh" +#include "debug/RubyPrefetcher.hh" +#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" +#include "mem/ruby/system/RubySystem.hh" + +RubyPrefetcher* +RubyPrefetcherParams::create() +{ + return new RubyPrefetcher(this); +} + +RubyPrefetcher::RubyPrefetcher(const Params *p) + : SimObject(p), m_num_streams(p->num_streams), + m_array(p->num_streams), m_train_misses(p->train_misses), + m_num_startup_pfs(p->num_startup_pfs), m_num_unit_filters(p->unit_filter), + m_num_nonunit_filters(p->nonunit_filter), + m_unit_filter(p->unit_filter, 0), + m_negative_filter(p->unit_filter, 0), + m_nonunit_filter(p->nonunit_filter, 0), + m_prefetch_cross_pages(p->cross_page), + m_page_shift(p->sys->getPageShift()) +{ + assert(m_num_streams > 0); + assert(m_num_startup_pfs <= MAX_PF_INFLIGHT); + + // create +1 stride filter + m_unit_filter_index = 0; + m_unit_filter_hit = new uint32_t[m_num_unit_filters]; + for (uint32_t i =0; i < m_num_unit_filters; i++) { + m_unit_filter_hit[i] = 0; + } + + // create -1 stride filter + m_negative_filter_index = 0; + m_negative_filter_hit = new uint32_t[m_num_unit_filters]; + for (int i =0; i < m_num_unit_filters; i++) { + m_negative_filter_hit[i] = 0; + } + + // create nonunit stride filter + m_nonunit_index = 0; + m_nonunit_stride = new int[m_num_nonunit_filters]; + m_nonunit_hit = new uint32_t[m_num_nonunit_filters]; + for (int i =0; i < m_num_nonunit_filters; i++) { + m_nonunit_stride[i] = 0; + m_nonunit_hit[i] = 0; + } +} + +RubyPrefetcher::~RubyPrefetcher() +{ + delete m_unit_filter_hit; + delete m_negative_filter_hit; + delete m_nonunit_stride; + delete m_nonunit_hit; +} + +void +RubyPrefetcher::regStats() +{ + SimObject::regStats(); + + numMissObserved + .name(name() + ".miss_observed") + .desc("number of misses observed") + ; + + numAllocatedStreams + .name(name() + ".allocated_streams") + .desc("number of streams allocated for prefetching") + ; + + numPrefetchRequested + .name(name() + ".prefetches_requested") + .desc("number of prefetch requests made") + ; + + numHits + .name(name() + ".hits") + .desc("number of prefetched blocks accessed (for the first time)") + ; + + numPartialHits + .name(name() + ".partial_hits") + .desc("number of misses observed for a block being prefetched") + ; + + numPagesCrossed + .name(name() + ".pages_crossed") + .desc("number of prefetches across pages") + ; + + numMissedPrefetchedBlocks + .name(name() + ".misses_on_prefetched_blocks") + .desc("number of misses for blocks that were prefetched, yet missed") + ; +} + +void +RubyPrefetcher::observeMiss(Addr address, const RubyRequestType& type) +{ + DPRINTF(RubyPrefetcher, "Observed miss for %#x\n", address); + Addr line_addr = makeLineAddress(address); + numMissObserved++; + + // check to see if we have already issued a prefetch for this block + uint32_t index = 0; + PrefetchEntry *pfEntry = getPrefetchEntry(line_addr, index); + if (pfEntry != NULL) { + if (pfEntry->requestIssued[index]) { + if (pfEntry->requestCompleted[index]) { + // We prefetched too early and now the prefetch block no + // longer exists in the cache + numMissedPrefetchedBlocks++; + return; + } else { + // The controller has issued the prefetch request, + // but the request for the block arrived earlier. + numPartialHits++; + observePfMiss(line_addr); + return; + } + } else { + // The request is still in the prefetch queue of the controller. + // Or was evicted because of other requests. + return; + } + } + + // check to see if this address is in the unit stride filter + bool alloc = false; + bool hit = accessUnitFilter(m_unit_filter, m_unit_filter_hit, + m_unit_filter_index, line_addr, 1, alloc); + if (alloc) { + // allocate a new prefetch stream + initializeStream(line_addr, 1, getLRUindex(), type); + } + if (hit) { + DPRINTF(RubyPrefetcher, " *** hit in unit stride buffer\n"); + return; + } + + hit = accessUnitFilter(m_negative_filter, m_negative_filter_hit, + m_negative_filter_index, line_addr, -1, alloc); + if (alloc) { + // allocate a new prefetch stream + initializeStream(line_addr, -1, getLRUindex(), type); + } + if (hit) { + DPRINTF(RubyPrefetcher, " *** hit in unit negative unit buffer\n"); + return; + } + + // check to see if this address is in the non-unit stride filter + int stride = 0; // NULL value + hit = accessNonunitFilter(address, &stride, alloc); + if (alloc) { + assert(stride != 0); // ensure non-zero stride prefetches + initializeStream(line_addr, stride, getLRUindex(), type); + } + if (hit) { + DPRINTF(RubyPrefetcher, " *** hit in non-unit stride buffer\n"); + return; + } +} + +void +RubyPrefetcher::observePfMiss(Addr address) +{ + numPartialHits++; + DPRINTF(RubyPrefetcher, "Observed partial hit for %#x\n", address); + issueNextPrefetch(address, NULL); +} + +void +RubyPrefetcher::observePfHit(Addr address) +{ + numHits++; + DPRINTF(RubyPrefetcher, "Observed hit for %#x\n", address); + issueNextPrefetch(address, NULL); +} + +void +RubyPrefetcher::issueNextPrefetch(Addr address, PrefetchEntry *stream) +{ + // get our corresponding stream fetcher + if (stream == NULL) { + uint32_t index = 0; + stream = getPrefetchEntry(address, index); + } + + // if (for some reason), this stream is unallocated, return. + if (stream == NULL) { + DPRINTF(RubyPrefetcher, "Unallocated stream, returning\n"); + return; + } + + // extend this prefetching stream by 1 (or more) + Addr page_addr = pageAddress(stream->m_address); + Addr line_addr = makeNextStrideAddress(stream->m_address, + stream->m_stride); + + // possibly stop prefetching at page boundaries + if (page_addr != pageAddress(line_addr)) { + if (!m_prefetch_cross_pages) { + // Deallocate the stream since we are not prefetching + // across page boundries + stream->m_is_valid = false; + return; + } + numPagesCrossed++; + } + + // launch next prefetch + numPrefetchRequested++; + stream->m_address = line_addr; + stream->m_use_time = m_controller->curCycle(); + DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr); + m_controller->enqueuePrefetch(line_addr, stream->m_type); +} + +uint32_t +RubyPrefetcher::getLRUindex(void) +{ + uint32_t lru_index = 0; + Cycles lru_access = m_array[lru_index].m_use_time; + + for (uint32_t i = 0; i < m_num_streams; i++) { + if (!m_array[i].m_is_valid) { + return i; + } + if (m_array[i].m_use_time < lru_access) { + lru_access = m_array[i].m_use_time; + lru_index = i; + } + } + + return lru_index; +} + +void +RubyPrefetcher::clearNonunitEntry(uint32_t index) +{ + m_nonunit_filter[index] = 0; + m_nonunit_stride[index] = 0; + m_nonunit_hit[index] = 0; +} + +void +RubyPrefetcher::initializeStream(Addr address, int stride, + uint32_t index, const RubyRequestType& type) +{ + numAllocatedStreams++; + + // initialize the stream prefetcher + PrefetchEntry *mystream = &(m_array[index]); + mystream->m_address = makeLineAddress(address); + mystream->m_stride = stride; + mystream->m_use_time = m_controller->curCycle(); + mystream->m_is_valid = true; + mystream->m_type = type; + + // create a number of initial prefetches for this stream + Addr page_addr = pageAddress(mystream->m_address); + Addr line_addr = makeLineAddress(mystream->m_address); + + // insert a number of prefetches into the prefetch table + for (int k = 0; k < m_num_startup_pfs; k++) { + line_addr = makeNextStrideAddress(line_addr, stride); + // possibly stop prefetching at page boundaries + if (page_addr != pageAddress(line_addr)) { + if (!m_prefetch_cross_pages) { + // deallocate this stream prefetcher + mystream->m_is_valid = false; + return; + } + numPagesCrossed++; + } + + // launch prefetch + numPrefetchRequested++; + DPRINTF(RubyPrefetcher, "Requesting prefetch for %#x\n", line_addr); + m_controller->enqueuePrefetch(line_addr, m_array[index].m_type); + } + + // update the address to be the last address prefetched + mystream->m_address = line_addr; +} + +PrefetchEntry * +RubyPrefetcher::getPrefetchEntry(Addr address, uint32_t &index) +{ + // search all streams for a match + for (int i = 0; i < m_num_streams; i++) { + // search all the outstanding prefetches for this stream + if (m_array[i].m_is_valid) { + for (int j = 0; j < m_num_startup_pfs; j++) { + if (makeNextStrideAddress(m_array[i].m_address, + -(m_array[i].m_stride*j)) == address) { + return &(m_array[i]); + } + } + } + } + return NULL; +} + +bool +RubyPrefetcher::accessUnitFilter(std::vector& filter_table, + uint32_t *filter_hit, uint32_t &index, Addr address, + int stride, bool &alloc) +{ + //reset the alloc flag + alloc = false; + + Addr line_addr = makeLineAddress(address); + for (int i = 0; i < m_num_unit_filters; i++) { + if (filter_table[i] == line_addr) { + filter_table[i] = makeNextStrideAddress(filter_table[i], stride); + filter_hit[i]++; + if (filter_hit[i] >= m_train_misses) { + alloc = true; + } + return true; + } + } + + // enter this address in the table + int local_index = index; + filter_table[local_index] = makeNextStrideAddress(line_addr, stride); + filter_hit[local_index] = 0; + local_index = local_index + 1; + if (local_index >= m_num_unit_filters) { + local_index = 0; + } + + index = local_index; + return false; +} + +bool +RubyPrefetcher::accessNonunitFilter(Addr address, int *stride, + bool &alloc) +{ + //reset the alloc flag + alloc = false; + + /// look for non-unit strides based on a (user-defined) page size + Addr page_addr = pageAddress(address); + Addr line_addr = makeLineAddress(address); + + for (uint32_t i = 0; i < m_num_nonunit_filters; i++) { + if (pageAddress(m_nonunit_filter[i]) == page_addr) { + // hit in the non-unit filter + // compute the actual stride (for this reference) + int delta = line_addr - m_nonunit_filter[i]; + + if (delta != 0) { + // no zero stride prefetches + // check that the stride matches (for the last N times) + if (delta == m_nonunit_stride[i]) { + // -> stride hit + // increment count (if > 2) allocate stream + m_nonunit_hit[i]++; + if (m_nonunit_hit[i] > m_train_misses) { + // This stride HAS to be the multiplicative constant of + // dataBlockBytes (bc makeNextStrideAddress is + // calculated based on this multiplicative constant!) + *stride = m_nonunit_stride[i] / + RubySystem::getBlockSizeBytes(); + + // clear this filter entry + clearNonunitEntry(i); + alloc = true; + } + } else { + // delta didn't match ... reset m_nonunit_hit count for + // this entry + m_nonunit_hit[i] = 0; + } + + // update the last address seen & the stride + m_nonunit_stride[i] = delta; + m_nonunit_filter[i] = line_addr; + return true; + } else { + return false; + } + } + } + + // not found: enter this address in the table + m_nonunit_filter[m_nonunit_index] = line_addr; + m_nonunit_stride[m_nonunit_index] = 0; + m_nonunit_hit[m_nonunit_index] = 0; + + m_nonunit_index = m_nonunit_index + 1; + if (m_nonunit_index >= m_num_nonunit_filters) { + m_nonunit_index = 0; + } + return false; +} + +void +RubyPrefetcher::print(std::ostream& out) const +{ + out << name() << " Prefetcher State\n"; + // print out unit filter + out << "unit table:\n"; + for (int i = 0; i < m_num_unit_filters; i++) { + out << m_unit_filter[i] << std::endl; + } + + out << "negative table:\n"; + for (int i = 0; i < m_num_unit_filters; i++) { + out << m_negative_filter[i] << std::endl; + } + + // print out non-unit stride filter + out << "non-unit table:\n"; + for (int i = 0; i < m_num_nonunit_filters; i++) { + out << m_nonunit_filter[i] << " " + << m_nonunit_stride[i] << " " + << m_nonunit_hit[i] << std::endl; + } + + // print out allocated stream buffers + out << "streams:\n"; + for (int i = 0; i < m_num_streams; i++) { + out << m_array[i].m_address << " " + << m_array[i].m_stride << " " + << m_array[i].m_is_valid << " " + << m_array[i].m_use_time << std::endl; + } +} + +Addr +RubyPrefetcher::pageAddress(Addr addr) const +{ + return mbits(addr, 63, m_page_shift); +} diff --git a/src/mem/ruby/structures/RubyPrefetcher.hh b/src/mem/ruby/structures/RubyPrefetcher.hh new file mode 100644 index 000000000..b691d3d86 --- /dev/null +++ b/src/mem/ruby/structures/RubyPrefetcher.hh @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood + * 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. + */ + +#ifndef __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ +#define __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ + +// Implements Power 4 like prefetching + +#include + +#include "base/statistics.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/network/MessageBuffer.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/ruby/slicc_interface/RubyRequest.hh" +#include "mem/ruby/system/RubySystem.hh" +#include "params/RubyPrefetcher.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +#define MAX_PF_INFLIGHT 8 + +class PrefetchEntry +{ + public: + /// constructor + PrefetchEntry() + { + // default: 1 cache-line stride + m_stride = (1 << RubySystem::getBlockSizeBits()); + m_use_time = Cycles(0); + m_is_valid = false; + } + + //! The base address for the stream prefetch + Addr m_address; + + //! stride distance to get next address from + int m_stride; + + //! the last time that any prefetched request was used + Cycles m_use_time; + + //! valid bit for each stream + bool m_is_valid; + + //! L1D prefetches loads and stores + RubyRequestType m_type; + + //! Bitset for tracking prefetches for which addresses have been + //! issued, which ones have completed. + std::bitset requestIssued; + std::bitset requestCompleted; +}; + +class RubyPrefetcher : public SimObject +{ + public: + typedef RubyPrefetcherParams Params; + RubyPrefetcher(const Params *p); + ~RubyPrefetcher(); + + void issueNextPrefetch(Addr address, PrefetchEntry *stream); + /** + * Implement the prefetch hit(miss) callback interface. + * These functions are called by the cache when it hits(misses) + * on a line with the line's prefetch bit set. If this address + * hits in m_array we will continue prefetching the stream. + */ + void observePfHit(Addr address); + void observePfMiss(Addr address); + + /** + * Observe a memory miss from the cache. + * + * @param address The physical address that missed out of the cache. + */ + void observeMiss(Addr address, const RubyRequestType& type); + + /** + * Print out some statistics + */ + void print(std::ostream& out) const; + void setController(AbstractController *_ctrl) + { m_controller = _ctrl; } + + void regStats(); + + private: + /** + * Returns an unused stream buffer (or if all are used, returns the + * least recently used (accessed) stream buffer). + * @return The index of the least recently used stream buffer. + */ + uint32_t getLRUindex(void); + + //! clear a non-unit stride prefetcher entry + void clearNonunitEntry(uint32_t index); + + //! allocate a new stream buffer at a specific index + void initializeStream(Addr address, int stride, + uint32_t index, const RubyRequestType& type); + + //! get pointer to the matching stream entry, returns NULL if not found + //! index holds the multiple of the stride this address is. + PrefetchEntry* getPrefetchEntry(Addr address, + uint32_t &index); + + /// access a unit stride filter to determine if there is a hit + bool accessUnitFilter(std::vector& filter_table, + uint32_t *hit_table, uint32_t &index, Addr address, + int stride, bool &alloc); + + /// access a unit stride filter to determine if there is a hit + bool accessNonunitFilter(Addr address, int *stride, + bool &alloc); + + /// determine the page aligned address + Addr pageAddress(Addr addr) const; + + //! number of prefetch streams available + uint32_t m_num_streams; + //! an array of the active prefetch streams + std::vector m_array; + + //! number of misses I must see before allocating a stream + uint32_t m_train_misses; + //! number of initial prefetches to startup a stream + uint32_t m_num_startup_pfs; + //! number of stride filters + uint32_t m_num_unit_filters; + //! number of non-stride filters + uint32_t m_num_nonunit_filters; + + /// a unit stride filter array: helps reduce BW requirement of + /// prefetching + std::vector m_unit_filter; + /// a round robin pointer into the unit filter group + uint32_t m_unit_filter_index; + //! An array used to count the of times particular filter entries + //! have been hit + uint32_t *m_unit_filter_hit; + + //! a negative unit stride filter array: helps reduce BW requirement + //! of prefetching + std::vector m_negative_filter; + /// a round robin pointer into the negative filter group + uint32_t m_negative_filter_index; + /// An array used to count the of times particular filter entries + /// have been hit + uint32_t *m_negative_filter_hit; + + /// a non-unit stride filter array: helps reduce BW requirement of + /// prefetching + std::vector m_nonunit_filter; + /// An array of strides (in # of cache lines) for the filter entries + int *m_nonunit_stride; + /// An array used to count the of times particular filter entries + /// have been hit + uint32_t *m_nonunit_hit; + /// a round robin pointer into the unit filter group + uint32_t m_nonunit_index; + + /// Used for allowing prefetches across pages. + bool m_prefetch_cross_pages; + + AbstractController *m_controller; + + const Addr m_page_shift; + + //! Count of accesses to the prefetcher + Stats::Scalar numMissObserved; + //! Count of prefetch streams allocated + Stats::Scalar numAllocatedStreams; + //! Count of prefetch requests made + Stats::Scalar numPrefetchRequested; + //! Count of successful prefetches + Stats::Scalar numHits; + //! Count of partial successful prefetches + Stats::Scalar numPartialHits; + //! Count of pages crossed + Stats::Scalar numPagesCrossed; + //! Count of misses incurred for blocks that were prefetched + Stats::Scalar numMissedPrefetchedBlocks; +}; + +#endif // __MEM_RUBY_STRUCTURES_PREFETCHER_HH__ diff --git a/src/mem/ruby/structures/RubyPrefetcher.py b/src/mem/ruby/structures/RubyPrefetcher.py index d762ba530..38397c334 100644 --- a/src/mem/ruby/structures/RubyPrefetcher.py +++ b/src/mem/ruby/structures/RubyPrefetcher.py @@ -42,10 +42,10 @@ from m5.proxy import * from m5.objects.System import System -class Prefetcher(SimObject): - type = 'Prefetcher' +class RubyPrefetcher(SimObject): + type = 'RubyPrefetcher' cxx_class = 'RubyPrefetcher' - cxx_header = "mem/ruby/structures/Prefetcher.hh" + cxx_header = "mem/ruby/structures/RubyPrefetcher.hh" num_streams = Param.UInt32(4, "Number of prefetch streams to be allocated") @@ -58,3 +58,7 @@ class Prefetcher(SimObject): cross_page = Param.Bool(False, """True if prefetched address can be on a page different from the observed address""") sys = Param.System(Parent.any, "System this prefetcher belongs to") + +class Prefetcher(RubyPrefetcher): + """DEPRECATED""" + pass diff --git a/src/mem/ruby/structures/SConscript b/src/mem/ruby/structures/SConscript index 9e2bde924..0cf05598f 100644 --- a/src/mem/ruby/structures/SConscript +++ b/src/mem/ruby/structures/SConscript @@ -40,6 +40,6 @@ Source('DirectoryMemory.cc') Source('CacheMemory.cc') Source('WireBuffer.cc') Source('PersistentTable.cc') -Source('Prefetcher.cc') +Source('RubyPrefetcher.cc') Source('TimerTable.cc') Source('BankedArray.cc') diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index 0904ac63f..1263344aa 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -61,7 +61,7 @@ python_class_map = { "MemoryControl": "MemoryControl", "MessageBuffer": "MessageBuffer", "DMASequencer": "DMASequencer", - "Prefetcher":"Prefetcher", + "RubyPrefetcher":"RubyPrefetcher", "Cycles":"Cycles", }