clk_domain = system.cpu[i].clk_domain
# Ruby prefetcher
- prefetcher = RubyPrefetcher.Prefetcher(
+ prefetcher = RubyPrefetcher(
num_streams=16,
unit_filter = 256,
nonunit_filter = 256,
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
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')
Cycles response_latency := 2;
bool send_evictions;
- Prefetcher * prefetcher;
+ RubyPrefetcher * prefetcher;
bool enable_prefetch := "False";
// From this node's L0 cache to the network
: 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;
bool isSet(Addr);
}
-structure (Prefetcher, external = "yes") {
+structure (RubyPrefetcher, external = "yes") {
void observeMiss(Addr, RubyRequestType);
void observePfHit(Addr);
void observePfMiss(Addr);
+++ /dev/null
-/*
- * 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<Addr>& 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>(addr, 63, m_page_shift);
-}
+++ /dev/null
-/*
- * 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 <bitset>
-
-#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<MAX_PF_INFLIGHT> requestIssued;
- std::bitset<MAX_PF_INFLIGHT> 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<Addr>& 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<PrefetchEntry> 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<Addr> 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<Addr> 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<Addr> 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__
--- /dev/null
+/*
+ * 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<Addr>& 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>(addr, 63, m_page_shift);
+}
--- /dev/null
+/*
+ * 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 <bitset>
+
+#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<MAX_PF_INFLIGHT> requestIssued;
+ std::bitset<MAX_PF_INFLIGHT> 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<Addr>& 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<PrefetchEntry> 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<Addr> 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<Addr> 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<Addr> 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__
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")
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
Source('CacheMemory.cc')
Source('WireBuffer.cc')
Source('PersistentTable.cc')
-Source('Prefetcher.cc')
+Source('RubyPrefetcher.cc')
Source('TimerTable.cc')
Source('BankedArray.cc')
"MemoryControl": "MemoryControl",
"MessageBuffer": "MessageBuffer",
"DMASequencer": "DMASequencer",
- "Prefetcher":"Prefetcher",
+ "RubyPrefetcher":"RubyPrefetcher",
"Cycles":"Cycles",
}