diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript index aab03554d6..bde71c0176 100644 --- a/src/mem/ruby/SConscript +++ b/src/mem/ruby/SConscript @@ -125,6 +125,7 @@ MakeInclude('structures/DirectoryMemory.hh') MakeInclude('structures/PerfectCacheMemory.hh') MakeInclude('structures/PersistentTable.hh') MakeInclude('structures/RubyPrefetcher.hh') +MakeInclude('structures/TBEStorage.hh') MakeInclude('structures/TBETable.hh') MakeInclude('structures/TimerTable.hh') MakeInclude('structures/WireBuffer.hh') diff --git a/src/mem/ruby/structures/SConscript b/src/mem/ruby/structures/SConscript index 0cf05598f8..546326b052 100644 --- a/src/mem/ruby/structures/SConscript +++ b/src/mem/ruby/structures/SConscript @@ -43,3 +43,4 @@ Source('PersistentTable.cc') Source('RubyPrefetcher.cc') Source('TimerTable.cc') Source('BankedArray.cc') +Source('TBEStorage.cc') diff --git a/src/mem/ruby/structures/TBEStorage.cc b/src/mem/ruby/structures/TBEStorage.cc new file mode 100644 index 0000000000..11a123083e --- /dev/null +++ b/src/mem/ruby/structures/TBEStorage.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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. + * + * 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 + +TBEStorage::TBEStorage(Stats::Group *parent, int number_of_TBEs) + : m_reserved(0), m_stats(parent) +{ + for (int i = 0; i < number_of_TBEs; ++i) + m_slots_avail.push(i); +} + +TBEStorage::TBEStorageStats::TBEStorageStats(Stats::Group *parent) + : Stats::Group(parent), + ADD_STAT(avg_size, "Avg. number of slots allocated"), + ADD_STAT(avg_util, "Avg. utilization"), + ADD_STAT(avg_reserved, "Avg. number of slots reserved") +{ +} diff --git a/src/mem/ruby/structures/TBEStorage.hh b/src/mem/ruby/structures/TBEStorage.hh new file mode 100644 index 0000000000..1a65907790 --- /dev/null +++ b/src/mem/ruby/structures/TBEStorage.hh @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2021 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. + * + * 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_TBESTORAGE_HH__ +#define __MEM_RUBY_STRUCTURES_TBESTORAGE_HH__ + +#include +#include +#include + +#include + +// The TBEStorage is used to track the resources consumed by the TBETable, +// i.e. the number of available TBE slots. +// +// TBEStorage resource tracking has two main differences from TBETable: +// +// 1) Allows slot reservation. This is useful to implement protocols that +// employ retry/credit messages instead of stall when the controller runs +// out of TBEs to accept new request. +// +// 2) Can also assign multiple entries to the same slot. This is useful to +// more easily model cases where multiple transactions share the same TBE +// resource (i.e. the slot). +// E.g: a request that triggers a replacement in a system without +// dedicated WB/Eviction buffer; both transactions can can have separate +// logical TBEs associated to the same slot. +// +// The motivation for having a separate structures for tracking TBEs +// availability are twofold: +// +// - Keeps TBETable simple and without the additional overhead for +// protocols that do not need these additional features. +// +// - Having two separate transactions sharing the same TBE resource using +// the current TBETable would be cumbersome since the TBETable is indexed +// by the transaction address. + +class TBEStorage { + public: + TBEStorage(Stats::Group *parent, int number_of_TBEs); + + // Returns the current number of slots allocated + int size() const { return m_slots_used.size(); } + + // Returns the total capacity of this TBEStorage table + int capacity() const { return m_slots_used.size() + m_slots_avail.size(); } + + // Returns number of slots currently reserved + int reserved() const { return m_reserved; } + + // Returns the number of slots available + int slotsAvailable() const { return m_slots_avail.size() - m_reserved; } + + // Returns the TBEStorage utilization + float utilization() const { return size() / (float)capacity(); } + + // Returns true if slotsAvailable() >= n; current_time is always ignored + // This allows this class to be used with check_allocate in SLICC to + // trigger resource stalls when there are no slots available + bool areNSlotsAvailable(int n, Tick current_time = 0) const; + + // Increase/decrease the number of reserved slots. Having reserved slots + // reduces the number of slots available for allocation + void incrementReserved(); + void decrementReserved(); + + // Assign a TBETable entry to a free slot and returns the slot number. + // Notice we don't need any info from TBETable and just track the number + // of entries assigned to each slot. + // This funcion requires slotsAvailable() > 0 + int addEntryToNewSlot(); + + // Assign an entry to an existing non-empty slot + void addEntryToSlot(int slot); + + // Remove an entry from an existing non-empty slot. The slot becomes + // available again when the number of assigned entries == 0 + void removeEntryFromSlot(int slot); + + private: + int m_reserved; + std::stack m_slots_avail; + std::unordered_map m_slots_used; + + struct TBEStorageStats : public Stats::Group + { + TBEStorageStats(Stats::Group *parent); + + // Statistical variables + Stats::Average avg_size; + Stats::Average avg_util; + Stats::Average avg_reserved; + } m_stats; +}; + +inline bool +TBEStorage::areNSlotsAvailable(int n, Tick current_time) const +{ + return slotsAvailable() >= n; +} + +inline void +TBEStorage::incrementReserved() +{ + ++m_reserved; + m_stats.avg_reserved = m_reserved; +} + +inline void +TBEStorage::decrementReserved() +{ + assert(m_reserved > 0); + --m_reserved; + m_stats.avg_reserved = m_reserved; +} + +inline int +TBEStorage::addEntryToNewSlot() +{ + assert(slotsAvailable() > 0); + assert(m_slots_avail.size() > 0); + int slot = m_slots_avail.top(); + m_slots_used[slot] = 1; + m_slots_avail.pop(); + m_stats.avg_size = size(); + m_stats.avg_util = utilization(); + return slot; +} + +inline void +TBEStorage::addEntryToSlot(int slot) +{ + auto iter = m_slots_used.find(slot); + assert(iter != m_slots_used.end()); + iter->second += 1; +} + +inline void +TBEStorage::removeEntryFromSlot(int slot) +{ + auto iter = m_slots_used.find(slot); + assert(iter != m_slots_used.end()); + assert(iter->second > 0); + iter->second -= 1; + if (iter->second == 0) { + m_slots_used.erase(iter); + m_slots_avail.push(slot); + } + m_stats.avg_size = size(); + m_stats.avg_util = utilization(); +} + +#endif