mem-ruby: Deep renaming of Prefetcher to RubyPrefetcher
authorAyaz Akram <yazakram@ucdavis.edu>
Tue, 5 May 2020 04:11:38 +0000 (21:11 -0700)
committerAyaz Akram <yazakram@ucdavis.edu>
Wed, 6 May 2020 23:17:52 +0000 (23:17 +0000)
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 <timothy.hayes@arm.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
13 files changed:
configs/ruby/MESI_Three_Level.py
configs/ruby/MESI_Two_Level.py
src/mem/ruby/SConscript
src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm
src/mem/ruby/protocol/RubySlicc_Types.sm
src/mem/ruby/structures/Prefetcher.cc [deleted file]
src/mem/ruby/structures/Prefetcher.hh [deleted file]
src/mem/ruby/structures/RubyPrefetcher.cc [new file with mode: 0644]
src/mem/ruby/structures/RubyPrefetcher.hh [new file with mode: 0644]
src/mem/ruby/structures/RubyPrefetcher.py
src/mem/ruby/structures/SConscript
src/mem/slicc/symbols/StateMachine.py

index 61d6c523b6a19adf524ef2d479f752bf0e3b7773..0bd893e380c0343159db029322a85423a7302544 100644 (file)
@@ -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,
index 8d2e01fb67878dc1e7c26eaae39cb6eb6a2561b6..3ddf8eff7161f70b0e3c248837c82fbd10e56378 100644 (file)
@@ -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
index 8c22ae495f29a9f836ec4b0402b245be8769059d..fc90f8a624ec5381cd876335bc05e8ee0f671188 100644 (file)
@@ -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')
index 3639ef2c594b60adbe84571de2e53b2160bfe74e..4de4a293e07542afb9f6f77f84d20c84c3296bfb 100644 (file)
@@ -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
index 7c83478db58c2d2eab5b266ca8c976d48d543189..3e3580f704f7e4181f6f57da1870d1f487ab2e4d 100644 (file)
@@ -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;
index 66d84fca30cf95699e45619b1eeaf101d197117c..6ab0f3f76885420e666a320492ad8271c46ed47d 100644 (file)
@@ -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 (file)
index 0602115..0000000
+++ /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<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);
-}
diff --git a/src/mem/ruby/structures/Prefetcher.hh b/src/mem/ruby/structures/Prefetcher.hh
deleted file mode 100644 (file)
index 4d2513f..0000000
+++ /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 <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__
diff --git a/src/mem/ruby/structures/RubyPrefetcher.cc b/src/mem/ruby/structures/RubyPrefetcher.cc
new file mode 100644 (file)
index 0000000..8646b99
--- /dev/null
@@ -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<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);
+}
diff --git a/src/mem/ruby/structures/RubyPrefetcher.hh b/src/mem/ruby/structures/RubyPrefetcher.hh
new file mode 100644 (file)
index 0000000..b691d3d
--- /dev/null
@@ -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 <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__
index d762ba5308bbccff21900fd97a9f651e036f6661..38397c33426bb62eee26d806efd796cd321850d6 100644 (file)
@@ -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
index 9e2bde924ab901ca9af16e84cedda094ab2d5a95..0cf05598f8af3ea856ca3931ada39e2ff6bde7e8 100644 (file)
@@ -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')
index 0904ac63fc658f28b89d1000d9b96a3da195987b..1263344aa23113c5f439747cdb5cdf79fa4a6d28 100644 (file)
@@ -61,7 +61,7 @@ python_class_map = {
                     "MemoryControl": "MemoryControl",
                     "MessageBuffer": "MessageBuffer",
                     "DMASequencer": "DMASequencer",
-                    "Prefetcher":"Prefetcher",
+                    "RubyPrefetcher":"RubyPrefetcher",
                     "Cycles":"Cycles",
                    }