ruby: add a prefetcher

This patch adds a prefetcher for the ruby memory system. The prefetcher
is based on a prefetcher implemented by others (well, I don't know
who wrote the original). The prefetcher does stride-based prefetching,
both unit and non-unit. It obseves the misses in the cache and trains on
these. After the training period is over, the prefetcher starts issuing
prefetch requests to the controller.
This commit is contained in:
Nilay Vaish
2012-12-11 10:05:54 -06:00
parent d502384795
commit 93e283abb3
7 changed files with 771 additions and 1 deletions

View File

@@ -86,6 +86,7 @@ DebugFlag('RubyGenerated')
DebugFlag('RubyMemory')
DebugFlag('RubyNetwork')
DebugFlag('RubyPort')
DebugFlag('RubyPrefetcher')
DebugFlag('RubyQueue')
DebugFlag('RubySequencer')
DebugFlag('RubySlicc')
@@ -96,4 +97,5 @@ DebugFlag('RubyResourceStalls')
CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
'RubyGenerated', 'RubySlicc', 'RubySystem', 'RubyCache',
'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer', 'RubyCacheTrace'])
'RubyMemory', 'RubyDma', 'RubyPort', 'RubySequencer', 'RubyCacheTrace',
'RubyPrefetcher'])

View File

@@ -103,6 +103,7 @@ MakeInclude('common/DataBlock.hh')
MakeInclude('common/NetDest.hh')
MakeInclude('common/Set.hh')
MakeInclude('filters/GenericBloomFilter.hh')
MakeInclude('structures/Prefetcher.hh')
MakeInclude('system/CacheMemory.hh')
MakeInclude('system/DMASequencer.hh')
MakeInclude('system/DirectoryMemory.hh')

View File

@@ -78,6 +78,10 @@ class AbstractController : public SimObject, public Consumer
//! The return value indicates the number of messages written with the
//! data from the packet.
virtual uint32_t functionalWriteBuffers(PacketPtr&) = 0;
//! Function for enqueuing a prefetch request
virtual void enqueuePrefetch(const Address&, const RubyRequestType&)
{ fatal("Prefetches not implemented!");}
};
#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

View File

@@ -0,0 +1,469 @@
/*
* 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 "debug/RubyPrefetcher.hh"
#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
#include "mem/ruby/structures/Prefetcher.hh"
#include "mem/ruby/system/System.hh"
Prefetcher*
PrefetcherParams::create()
{
return new Prefetcher(this);
}
Prefetcher::Prefetcher(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, Address(0)),
m_negative_filter(p->unit_filter, Address(0)),
m_nonunit_filter(p->nonunit_filter, Address(0)),
m_prefetch_cross_pages(p->cross_page)
{
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;
}
}
Prefetcher::~Prefetcher()
{
delete m_unit_filter_hit;
delete m_negative_filter_hit;
delete m_nonunit_stride;
delete m_nonunit_hit;
}
void
Prefetcher::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")
;
numPrefetchAccepted
.name(name() + ".prefetches_accepted")
.desc("number of prefetch requests accepted")
;
numDroppedPrefetches
.name(name() + ".dropped_prefetches")
.desc("number of prefetch requests dropped")
;
numHits
.name(name() + ".hits")
.desc("number of prefetched blocks accessed")
;
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
Prefetcher::observeMiss(const Address& address, const RubyRequestType& type)
{
DPRINTF(RubyPrefetcher, "Observed miss for %s\n", address);
Address line_addr = line_address(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++;
observePfHit(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
Prefetcher::observePfMiss(const Address& address)
{
numPartialHits++;
DPRINTF(RubyPrefetcher, "Observed partial hit for %s\n", address);
issueNextPrefetch(address, NULL);
}
void
Prefetcher::observePfHit(const Address& address)
{
numHits++;
DPRINTF(RubyPrefetcher, "Observed hit for %s\n", address);
issueNextPrefetch(address, NULL);
}
void
Prefetcher::issueNextPrefetch(const Address &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)
Address page_addr = page_address(stream->m_address);
Address line_addr = next_stride_address(stream->m_address,
stream->m_stride);
// possibly stop prefetching at page boundaries
if (page_addr != page_address(line_addr)) {
numPagesCrossed++;
if (!m_prefetch_cross_pages) {
// Deallocate the stream since we are not prefetching
// across page boundries
stream->m_is_valid = false;
return;
}
}
// launch next prefetch
stream->m_address = line_addr;
stream->m_use_time = g_system_ptr->getTime();
DPRINTF(RubyPrefetcher, "Requesting prefetch for %s\n", line_addr);
m_controller->enqueuePrefetch(line_addr, stream->m_type);
}
uint32_t
Prefetcher::getLRUindex(void)
{
uint32_t lru_index = 0;
Time 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
Prefetcher::clearNonunitEntry(uint32_t index)
{
m_nonunit_filter[index].setAddress(0);
m_nonunit_stride[index] = 0;
m_nonunit_hit[index] = 0;
}
void
Prefetcher::initializeStream(const Address& address, int stride,
uint32_t index, const RubyRequestType& type)
{
numAllocatedStreams++;
// initialize the stream prefetcher
PrefetchEntry *mystream = &(m_array[index]);
mystream->m_address = line_address(address);
mystream->m_stride = stride;
mystream->m_use_time = g_system_ptr->getTime();
mystream->m_is_valid = true;
mystream->m_type = type;
// create a number of initial prefetches for this stream
Address page_addr = page_address(mystream->m_address);
Address line_addr = line_address(mystream->m_address);
Address prev_addr = line_addr;
// insert a number of prefetches into the prefetch table
for (int k = 0; k < m_num_startup_pfs; k++) {
line_addr = next_stride_address(line_addr, stride);
// possibly stop prefetching at page boundaries
if (page_addr != page_address(line_addr)) {
numPagesCrossed++;
if (!m_prefetch_cross_pages) {
// deallocate this stream prefetcher
mystream->m_is_valid = false;
return;
}
}
// launch prefetch
numPrefetchRequested++;
DPRINTF(RubyPrefetcher, "Requesting prefetch for %s\n", line_addr);
m_controller->enqueuePrefetch(line_addr, m_array[index].m_type);
prev_addr = line_addr;
}
// update the address to be the last address prefetched
mystream->m_address = line_addr;
}
PrefetchEntry *
Prefetcher::getPrefetchEntry(const Address &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 (next_stride_address(m_array[i].m_address,
-(m_array[i].m_stride*j)) == address) {
return &(m_array[i]);
}
}
}
}
return NULL;
}
bool
Prefetcher::accessUnitFilter(std::vector<Address>& filter_table,
uint32_t *filter_hit, uint32_t &index, const Address &address,
int stride, bool &alloc)
{
//reset the alloc flag
alloc = false;
Address line_addr = line_address(address);
for (int i = 0; i < m_num_unit_filters; i++) {
if (filter_table[i] == line_addr) {
filter_table[i] = next_stride_address(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] = next_stride_address(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
Prefetcher::accessNonunitFilter(const Address& address, int *stride,
bool &alloc)
{
//reset the alloc flag
alloc = false;
/// look for non-unit strides based on a (user-defined) page size
Address page_addr = page_address(address);
Address line_addr = line_address(address);
for (uint32_t i = 0; i < m_num_nonunit_filters; i++) {
if (page_address(m_nonunit_filter[i]) == page_addr) {
// hit in the non-unit filter
// compute the actual stride (for this reference)
int delta = line_addr.getAddress() - m_nonunit_filter[i].getAddress();
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 next_stride_address 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
Prefetcher::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;
}
}

View File

@@ -0,0 +1,210 @@
/*
* 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 PREFETCHER_H
#define PREFETCHER_H
// Implements Power 4 like prefetching
#include <bitset>
#include "base/statistics.hh"
#include "mem/ruby/buffers/MessageBuffer.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/slicc_interface/RubyRequest.hh"
#include "params/Prefetcher.hh"
#include "sim/sim_object.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
Address 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 Prefetcher : public SimObject
{
public:
typedef PrefetcherParams Params;
Prefetcher(const Params *p);
~Prefetcher();
void issueNextPrefetch(const Address &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(const Address& address);
void observePfMiss(const Address& address);
/**
* Observe a memory miss from the cache.
*
* @param address The physical address that missed out of the cache.
*/
void observeMiss(const Address& 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(const Address& 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(const Address &address,
uint32_t &index);
/// access a unit stride filter to determine if there is a hit
bool accessUnitFilter(std::vector<Address>& filter_table,
uint32_t *hit_table, uint32_t &index, const Address &address,
int stride, bool &alloc);
/// access a unit stride filter to determine if there is a hit
bool accessNonunitFilter(const Address& address, int *stride,
bool &alloc);
//! 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<Address> 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 nit stride filter array: helps reduce BW requirement
//! of prefetching
std::vector<Address> 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<Address> 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;
//! 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 prefetch requests accepted
Stats::Scalar numPrefetchAccepted;
//! Count of prefetches dropped
Stats::Scalar numDroppedPrefetches;
//! 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 // PREFETCHER_H

View File

@@ -0,0 +1,47 @@
# Copyright (c) 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.
#
# Authors: Nilay Vaish
from m5.SimObject import SimObject
from m5.params import *
class Prefetcher(SimObject):
type = 'Prefetcher'
cxx_class = 'Prefetcher'
cxx_header = "mem/ruby/structures/Prefetcher.hh"
num_streams = Param.UInt32(4,
"Number of prefetch streams to be allocated")
pf_per_stream = Param.UInt32(1, "Number of prefetches per stream")
unit_filter = Param.UInt32(8,
"Number of entries in the unit filter array")
nonunit_filter = Param.UInt32(8,
"Number of entries in the non-unit filter array")
train_misses = Param.UInt32(4, "")
num_startup_pfs = Param.UInt32(1, "")
cross_page = Param.Bool(False, """True if prefetched address can be on a
page different from the observed address""")

View File

@@ -0,0 +1,37 @@
# -*- mode:python -*-
# Copyright (c) 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.
#
# Authors: Nilay Vaish
Import('*')
if env['PROTOCOL'] == 'None':
Return()
SimObject('RubyPrefetcher.py')
Source('Prefetcher.cc')