From: Daniel R. Carvalho Date: Sat, 21 Dec 2019 13:55:30 +0000 (+0100) Subject: mem-ruby: Use CircularQueue for prefetcher's non unit filter X-Git-Tag: develop-gem5-snapshot~659 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=453a334c8accbf0d7b0b9d01b42eec4a42a7ac17;p=gem5.git mem-ruby: Use CircularQueue for prefetcher's non unit filter Ruby prefetcher's non-unit filter is a circular queue, so use the class created for this functionality. This changes the behavior, since previously iterating through the filter was completely arbitrary, and now it iterates from the beginning of the queue to the end when accessing and updating the filter's contents. Change-Id: I3148efcbef00da0c8f6cf2dee7fb86f6c2ddb27d Signed-off-by: Daniel R. Carvalho Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/24533 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- diff --git a/src/mem/ruby/structures/RubyPrefetcher.cc b/src/mem/ruby/structures/RubyPrefetcher.cc index 02526aa57..b416269e3 100644 --- a/src/mem/ruby/structures/RubyPrefetcher.cc +++ b/src/mem/ruby/structures/RubyPrefetcher.cc @@ -58,30 +58,14 @@ 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_nonunit_filters(p->nonunit_filter), unitFilter(p->unit_filter), negativeFilter(p->unit_filter), - m_nonunit_filter(p->nonunit_filter, 0), + nonUnitFilter(p->nonunit_filter), 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 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_nonunit_stride; - delete m_nonunit_hit; } void @@ -180,7 +164,7 @@ RubyPrefetcher::observeMiss(Addr address, const RubyRequestType& type) // check to see if this address is in the non-unit stride filter int stride = 0; // NULL value - hit = accessNonunitFilter(address, &stride, alloc); + hit = accessNonunitFilter(line_addr, &stride, alloc); if (alloc) { assert(stride != 0); // ensure non-zero stride prefetches initializeStream(line_addr, stride, getLRUindex(), type); @@ -265,14 +249,6 @@ RubyPrefetcher::getLRUindex(void) 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) @@ -358,49 +334,46 @@ RubyPrefetcher::accessUnitFilter(CircularQueue* const filter, } bool -RubyPrefetcher::accessNonunitFilter(Addr address, int *stride, - bool &alloc) +RubyPrefetcher::accessNonunitFilter(Addr line_addr, 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); + Addr page_addr = pageAddress(line_addr); - for (uint32_t i = 0; i < m_num_nonunit_filters; i++) { - if (pageAddress(m_nonunit_filter[i]) == page_addr) { + for (auto& entry : nonUnitFilter) { + if (pageAddress(entry.addr) == page_addr) { // hit in the non-unit filter // compute the actual stride (for this reference) - int delta = line_addr - m_nonunit_filter[i]; + int delta = line_addr - entry.addr; if (delta != 0) { // no zero stride prefetches // check that the stride matches (for the last N times) - if (delta == m_nonunit_stride[i]) { + if (delta == entry.stride) { // -> stride hit // increment count (if > 2) allocate stream - m_nonunit_hit[i]++; - if (m_nonunit_hit[i] > m_train_misses) { + entry.hits++; + if (entry.hits > 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(); + *stride = entry.stride / + RubySystem::getBlockSizeBytes(); // clear this filter entry - clearNonunitEntry(i); + entry.clear(); alloc = true; } } else { - // delta didn't match ... reset m_nonunit_hit count for - // this entry - m_nonunit_hit[i] = 0; + // If delta didn't match reset entry's hit count + entry.hits = 0; } // update the last address seen & the stride - m_nonunit_stride[i] = delta; - m_nonunit_filter[i] = line_addr; + entry.addr = line_addr; + entry.stride = delta; return true; } else { return false; @@ -409,14 +382,8 @@ RubyPrefetcher::accessNonunitFilter(Addr address, int *stride, } // 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; + nonUnitFilter.push_back(NonUnitFilterEntry(line_addr)); - m_nonunit_index = m_nonunit_index + 1; - if (m_nonunit_index >= m_num_nonunit_filters) { - m_nonunit_index = 0; - } return false; } @@ -437,10 +404,10 @@ RubyPrefetcher::print(std::ostream& out) const // 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; + for (const auto& entry : nonUnitFilter) { + out << entry.addr << " " + << entry.stride << " " + << entry.hits << std::endl; } // print out allocated stream buffers diff --git a/src/mem/ruby/structures/RubyPrefetcher.hh b/src/mem/ruby/structures/RubyPrefetcher.hh index ebf59bd3b..8e08fdf62 100644 --- a/src/mem/ruby/structures/RubyPrefetcher.hh +++ b/src/mem/ruby/structures/RubyPrefetcher.hh @@ -97,7 +97,7 @@ class RubyPrefetcher : public SimObject public: typedef RubyPrefetcherParams Params; RubyPrefetcher(const Params *p); - ~RubyPrefetcher(); + ~RubyPrefetcher() = default; void issueNextPrefetch(Addr address, PrefetchEntry *stream); /** @@ -139,6 +139,25 @@ class RubyPrefetcher : public SimObject } }; + struct NonUnitFilterEntry : public UnitFilterEntry + { + /** Stride (in # of cache lines). */ + int stride; + + NonUnitFilterEntry(Addr _addr = 0) + : UnitFilterEntry(_addr), stride(0) + { + } + + void + clear() + { + addr = 0; + stride = 0; + hits = 0; + } + }; + /** * Returns an unused stream buffer (or if all are used, returns the * least recently used (accessed) stream buffer). @@ -146,9 +165,6 @@ class RubyPrefetcher : public SimObject */ 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); @@ -171,9 +187,17 @@ class RubyPrefetcher : public SimObject bool accessUnitFilter(CircularQueue* const filter, Addr line_addr, int stride, bool &alloc); - /// access a unit stride filter to determine if there is a hit - bool accessNonunitFilter(Addr address, int *stride, - bool &alloc); + /** + * Access a non-unit stride filter to determine if there is a hit, and + * update it otherwise. + * + * @param line_addr Address being accessed, block aligned. + * @param stride The stride value. + * @param alloc Whether a stream should be allocated on a hit. + * @return True if a corresponding entry was found and its stride is + * not zero. + */ + bool accessNonunitFilter(Addr line_addr, int *stride, bool &alloc); /// determine the page aligned address Addr pageAddress(Addr addr) const; @@ -187,8 +211,6 @@ class RubyPrefetcher : public SimObject uint32_t m_train_misses; //! number of initial prefetches to startup a stream uint32_t m_num_startup_pfs; - //! number of non-stride filters - uint32_t m_num_nonunit_filters; /** * A unit stride filter array: helps reduce BW requirement @@ -202,16 +224,11 @@ class RubyPrefetcher : public SimObject */ CircularQueue negativeFilter; - /// a non-unit stride filter array: helps reduce BW requirement of - /// prefetching - std::vector m_nonunit_filter; - /// An array of strides (in # of cache lines) for the filter entries - int *m_nonunit_stride; - /// An array used to count the of times particular filter entries - /// have been hit - uint32_t *m_nonunit_hit; - /// a round robin pointer into the unit filter group - uint32_t m_nonunit_index; + /** + * A non-unit stride filter array: helps reduce BW requirement of + * prefetching. + */ + CircularQueue nonUnitFilter; /// Used for allowing prefetches across pages. bool m_prefetch_cross_pages;